Fix URLTest#testAtSignInUserInfo failure am: 7e6977749c am: 47ee0f9e11 am: d24900bf47
am: aba0708c7d

Change-Id: Ibd29c496b3b1faadf53ad8349f59b22b08c105c6
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 51c2a94..9082209 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -1537,8 +1537,13 @@
     sockaddr* from = (javaInetSocketAddress != NULL) ? reinterpret_cast<sockaddr*>(&ss) : NULL;
     socklen_t* fromLength = (javaInetSocketAddress != NULL) ? &sl : 0;
     jint recvCount = NET_FAILURE_RETRY(env, ssize_t, recvfrom, javaFd, bytes.get() + byteOffset, byteCount, flags, from, fromLength);
-    if (recvCount > 0) {
-        fillInetSocketAddress(env, javaInetSocketAddress, ss);
+    if (recvCount >= 0) {
+        // The socket may have performed orderly shutdown and recvCount would return 0 (see man 2
+        // recvfrom), in which case ss.ss_family == AF_UNIX and fillInetSocketAddress would fail.
+        // Don't fill in the address if recvfrom didn't succeed. http://b/33483694
+        if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
+            fillInetSocketAddress(env, javaInetSocketAddress, ss);
+        }
     }
     return recvCount;
 }
diff --git a/luni/src/test/java/libcore/java/net/InetAddressTest.java b/luni/src/test/java/libcore/java/net/InetAddressTest.java
index 600196b..4f922eb 100644
--- a/luni/src/test/java/libcore/java/net/InetAddressTest.java
+++ b/luni/src/test/java/libcore/java/net/InetAddressTest.java
@@ -186,10 +186,8 @@
     public void test_isReachable_neverThrows() throws Exception {
         InetAddress inetAddress = InetAddress.getByName("www.google.com");
 
-        final NetworkInterface netIf;
-        try {
-            netIf = NetworkInterface.getByName("dummy0");
-        } catch (SocketException e) {
+        final NetworkInterface netIf = NetworkInterface.getByName("dummy0");
+        if (netIf == null) {
             System.logI("Skipping test_isReachable_neverThrows because dummy0 isn't available");
             return;
         }
diff --git a/luni/src/test/java/libcore/java/net/OldSocketTest.java b/luni/src/test/java/libcore/java/net/OldSocketTest.java
index 4254516..0fae672 100644
--- a/luni/src/test/java/libcore/java/net/OldSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/OldSocketTest.java
@@ -1983,10 +1983,14 @@
                         + e.toString());
             }
         }
+    }
 
+    // Calling sendUrgentData on a closed socket should not allocate a new impl and leak resources.
+    // Bug: 31818400
+    public void test_sendUrgentDataI_leaky() throws IOException {
+        Socket theSocket = new Socket();
+        theSocket.close();
         try {
-            Socket theSocket = new Socket();
-            theSocket.close();
             theSocket.sendUrgentData(0);
             fail("IOException was not thrown.");
         } catch(IOException ioe) {
@@ -1994,6 +1998,19 @@
         }
     }
 
+    // Calling getTrafficClass on a closed socket should not allocate a new impl and leak resources.
+    // Bug: 31818400
+    public void test_getTrafficClass_leaky() throws IOException {
+        Socket theSocket = new Socket();
+        theSocket.close();
+        try {
+            theSocket.getTrafficClass();
+            fail();
+        } catch (IOException ioe) {
+            //expected
+        }
+    }
+
     public void test_setPerformancePreference_Int_Int_Int() throws Exception {
         Socket theSocket = new Socket();
         theSocket.setPerformancePreferences(1, 1, 1);
diff --git a/luni/src/test/java/libcore/java/nio/BufferTest.java b/luni/src/test/java/libcore/java/nio/BufferTest.java
index 3ef549b..9063e27 100644
--- a/luni/src/test/java/libcore/java/nio/BufferTest.java
+++ b/luni/src/test/java/libcore/java/nio/BufferTest.java
@@ -1365,4 +1365,105 @@
         d.put(1, (double)1);
         b.limit(0);  d.put(1, (double)1);
     }
+
+    // http://b/32655865
+    public void test_ByteBufferAsXBuffer_ByteOrder() {
+        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
+        // Fill a ByteBuffer with different bytes that make it easy to tell byte ordering issues.
+        for (int i = 0; i < 10; i++) {
+            byteBuffer.put((byte)i);
+        }
+        byteBuffer.rewind();
+        // Obtain a big-endian and little-endian copy of the source array.
+        ByteBuffer bigEndian = byteBuffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+        ByteBuffer littleEndian = byteBuffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+
+        // Check each type longer than a byte to confirm the ordering differs.
+        // asXBuffer.
+        assertFalse(bigEndian.asShortBuffer().get() == littleEndian.asShortBuffer().get());
+        assertFalse(bigEndian.asIntBuffer().get() == littleEndian.asIntBuffer().get());
+        assertFalse(bigEndian.asLongBuffer().get() == littleEndian.asLongBuffer().get());
+        assertFalse(bigEndian.asDoubleBuffer().get() == littleEndian.asDoubleBuffer().get());
+        assertFalse(bigEndian.asCharBuffer().get() == littleEndian.asCharBuffer().get());
+        assertFalse(bigEndian.asFloatBuffer().get() == littleEndian.asFloatBuffer().get());
+
+        // asXBuffer().asReadOnlyBuffer()
+        assertFalse(bigEndian.asShortBuffer().asReadOnlyBuffer().get() ==
+                littleEndian.asShortBuffer().asReadOnlyBuffer().get());
+        assertFalse(bigEndian.asIntBuffer().asReadOnlyBuffer().get() ==
+                littleEndian.asIntBuffer().asReadOnlyBuffer().get());
+        assertFalse(bigEndian.asLongBuffer().asReadOnlyBuffer().get() ==
+                littleEndian.asLongBuffer().asReadOnlyBuffer().get());
+        assertFalse(bigEndian.asDoubleBuffer().asReadOnlyBuffer().get() ==
+                littleEndian.asDoubleBuffer().asReadOnlyBuffer().get());
+        assertFalse(bigEndian.asCharBuffer().asReadOnlyBuffer().get() ==
+                littleEndian.asCharBuffer().asReadOnlyBuffer().get());
+        assertFalse(bigEndian.asFloatBuffer().asReadOnlyBuffer().get() ==
+                littleEndian.asFloatBuffer().asReadOnlyBuffer().get());
+
+        // asXBuffer().duplicate()
+        assertFalse(bigEndian.asShortBuffer().duplicate().get() ==
+                littleEndian.asShortBuffer().duplicate().get());
+        assertFalse(bigEndian.asIntBuffer().duplicate().get() ==
+                littleEndian.asIntBuffer().duplicate().get());
+        assertFalse(bigEndian.asLongBuffer().duplicate().get() ==
+                littleEndian.asLongBuffer().duplicate().get());
+        assertFalse(bigEndian.asDoubleBuffer().duplicate().get() ==
+                littleEndian.asDoubleBuffer().duplicate().get());
+        assertFalse(bigEndian.asCharBuffer().duplicate().get() ==
+                littleEndian.asCharBuffer().duplicate().get());
+        assertFalse(bigEndian.asFloatBuffer().duplicate().get() ==
+                littleEndian.asFloatBuffer().duplicate().get());
+
+        // asXBuffer().slice()
+        assertFalse(bigEndian.asShortBuffer().slice().get() ==
+                littleEndian.asShortBuffer().slice().get());
+        assertFalse(bigEndian.asIntBuffer().slice().get() ==
+                littleEndian.asIntBuffer().slice().get());
+        assertFalse(bigEndian.asLongBuffer().slice().get() ==
+                littleEndian.asLongBuffer().slice().get());
+        assertFalse(bigEndian.asDoubleBuffer().slice().get() ==
+                littleEndian.asDoubleBuffer().slice().get());
+        assertFalse(bigEndian.asCharBuffer().slice().get() ==
+                littleEndian.asCharBuffer().slice().get());
+        assertFalse(bigEndian.asFloatBuffer().slice().get() ==
+                littleEndian.asFloatBuffer().slice().get());
+    }
+
+    // http://b/32655865
+    public void test_ByteBufferAsXBuffer_ByteOrder_2() {
+        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10);
+        byteBuffer.order(ByteOrder.BIG_ENDIAN);
+        // Fill a ByteBuffer with different bytes that make it easy to tell byte ordering issues.
+        for (int i = 0; i < 10; i++) {
+            byteBuffer.put((byte)i);
+        }
+        byteBuffer.rewind();
+
+        // Create BIG_ENDIAN views of the buffer.
+        ShortBuffer sb_be = byteBuffer.asShortBuffer();
+        LongBuffer lb_be = byteBuffer.asLongBuffer();
+        IntBuffer ib_be = byteBuffer.asIntBuffer();
+        DoubleBuffer db_be = byteBuffer.asDoubleBuffer();
+        CharBuffer cb_be = byteBuffer.asCharBuffer();
+        FloatBuffer fb_be = byteBuffer.asFloatBuffer();
+
+        // Change the order of the underlying buffer.
+        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+
+        // Create LITTLE_ENDIAN views of the buffer.
+        ShortBuffer sb_le = byteBuffer.asShortBuffer();
+        LongBuffer lb_le = byteBuffer.asLongBuffer();
+        IntBuffer ib_le = byteBuffer.asIntBuffer();
+        DoubleBuffer db_le = byteBuffer.asDoubleBuffer();
+        CharBuffer cb_le = byteBuffer.asCharBuffer();
+        FloatBuffer fb_le = byteBuffer.asFloatBuffer();
+
+        assertFalse(sb_be.get() == sb_le.get());
+        assertFalse(lb_be.get() == lb_le.get());
+        assertFalse(ib_be.get() == ib_le.get());
+        assertFalse(db_be.get() == db_le.get());
+        assertFalse(cb_be.get() == cb_le.get());
+        assertFalse(fb_be.get() == fb_le.get());
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/FormatterTest.java b/luni/src/test/java/libcore/java/util/FormatterTest.java
index e87fee5..aed9ca0 100644
--- a/luni/src/test/java/libcore/java/util/FormatterTest.java
+++ b/luni/src/test/java/libcore/java/util/FormatterTest.java
@@ -17,7 +17,11 @@
 package libcore.java.util;
 
 import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
 import java.util.Calendar;
+import java.util.Formatter;
 import java.util.GregorianCalendar;
 import java.util.Locale;
 import java.util.TimeZone;
@@ -183,4 +187,24 @@
       assertEquals(expected, String.format(Locale.US, "%t" + pattern, c));
       assertEquals(expected, String.format(Locale.US, "%T" + pattern, c));
     }
+
+    // http://b/33245708: Some locales have a group separator != '\0' but a default decimal format
+    // pattern without grouping (e.g. a group size of zero). This would throw divide by zero when
+    // working out where to place the separator.
+    public void testGroupingSizeZero() {
+        Locale localeWithoutGrouping = new Locale("hy");
+        DecimalFormat decimalFormat =
+                (DecimalFormat) NumberFormat.getInstance(localeWithoutGrouping);
+
+        // Confirm the locale is still a good example: it has a group separator, but no grouping in
+        // the default decimal format.
+        assertEquals(0, decimalFormat.getGroupingSize());
+        assertFalse(decimalFormat.isGroupingUsed());
+        DecimalFormatSymbols symbols = decimalFormat.getDecimalFormatSymbols();
+        assertTrue(symbols.getGroupingSeparator() != '\0');
+
+        Formatter formatter = new Formatter(localeWithoutGrouping);
+        formatter.format("%,d", 123456789);
+        // No exception expected
+    }
 }
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index 03b6bd2..a300205 100755
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -976,7 +976,8 @@
         // is prioritized over the properties in ICUConfig.properties. The issue with using
         // that is that it doesn't play well with jarjar and it needs complicated build rules
         // to change its default value.
-        p.put("android.icu.impl.ICUBinary.dataPath", getenv("ANDROID_ROOT") + "/usr/icu");
+        String icuDataPath = generateIcuDataPath();
+        p.put("android.icu.impl.ICUBinary.dataPath", icuDataPath);
 
         parsePropertyAssignments(p, specialProperties());
 
@@ -1002,6 +1003,37 @@
         return p;
     }
 
+    private static String generateIcuDataPath() {
+        StringBuilder icuDataPathBuilder = new StringBuilder();
+        // ICU should first look in ANDROID_DATA. This is used for (optional) timezone data.
+        String dataIcuDataPath = getEnvironmentPath("ANDROID_DATA", "/misc/zoneinfo/current/icu");
+        if (dataIcuDataPath != null) {
+            icuDataPathBuilder.append(dataIcuDataPath);
+        }
+
+        // ICU should always look in ANDROID_ROOT.
+        String systemIcuDataPath = getEnvironmentPath("ANDROID_ROOT", "/usr/icu");
+        if (systemIcuDataPath != null) {
+            if (icuDataPathBuilder.length() > 0) {
+                icuDataPathBuilder.append(":");
+            }
+            icuDataPathBuilder.append(systemIcuDataPath);
+        }
+        return icuDataPathBuilder.toString();
+    }
+
+    /**
+     * Creates a path by combining the value of an environment variable with a relative path.
+     * Returns {@code null} if the environment variable is not set.
+     */
+    private static String getEnvironmentPath(String environmentVariable, String path) {
+        String variable = getenv(environmentVariable);
+        if (variable == null) {
+            return null;
+        }
+        return variable + path;
+    }
+
     private static Properties initProperties() {
         Properties p = new PropertiesWithNonOverrideableDefaults(unchangeableProps);
         setDefaultChangeableProperties(p);
diff --git a/ojluni/src/main/java/java/net/Socket.java b/ojluni/src/main/java/java/net/Socket.java
index 96a7355..48c87a1 100755
--- a/ojluni/src/main/java/java/net/Socket.java
+++ b/ojluni/src/main/java/java/net/Socket.java
@@ -1052,6 +1052,13 @@
      * @since 1.4
      */
     public void sendUrgentData (int data) throws IOException  {
+        // Android-changed: If the socket is closed, sendUrgentData should not create a new impl.
+        // Fail early to avoid leaking resources.
+        // http://b/31818400
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
         if (!getImpl().supportsUrgentData ()) {
             throw new SocketException ("Urgent data not supported");
         }
@@ -1375,6 +1382,11 @@
      * @see #setTrafficClass(int)
      */
     public int getTrafficClass() throws SocketException {
+        // Android-changed: throw SocketException if the socket is already closed. http://b/31818400
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
         return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();
     }
 
diff --git a/ojluni/src/main/java/java/nio/ByteBuffer.java b/ojluni/src/main/java/java/nio/ByteBuffer.java
index 523bbda..1e50922 100644
--- a/ojluni/src/main/java/java/nio/ByteBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBuffer.java
@@ -555,14 +555,14 @@
             // isDirect() doesn't imply !hasArray(), ByteBuffer.allocateDirect allocated buffer will
             // have a backing, non-gc-movable byte array. JNI allocated direct byte buffers WILL NOT
             // have a backing array.
-            final Object srcObject = src.isDirect() ? src : src.array();
+            final Object srcObject = src.isDirect() ? src : src.hb;
             int srcOffset = src.position();
             if (!src.isDirect()) {
                 srcOffset += src.offset;
             }
 
             final ByteBuffer dst = this;
-            final Object dstObject = dst.isDirect() ? dst : dst.array();
+            final Object dstObject = dst.isDirect() ? dst : dst.hb;
             int dstOffset = dst.position();
             if (!dst.isDirect()) {
                 dstOffset += dst.offset;
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
index 0b2c18b..9dbb8a6 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
@@ -37,7 +37,7 @@
                            int mark, int pos, int lim, int cap,
                            int off, ByteOrder order) {
         super(mark, pos, lim, cap);
-        this.bb = bb;
+        this.bb = bb.duplicate();
         this.isReadOnly = bb.isReadOnly;
         // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
         // HeapByteBuffer. We only have to initialize the field when bb is an instance of
@@ -49,6 +49,7 @@
         if (bb instanceof DirectByteBuffer) {
             this.address = bb.address + off;
         }
+        this.bb.order(order);
         this.order = order;
         offset = off;
     }
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java
index 8ffbac5..ff4a6bf 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java
@@ -38,7 +38,7 @@
                              int mark, int pos, int lim, int cap,
                              int off, ByteOrder order) {
         super(mark, pos, lim, cap);
-        this.bb = bb;
+        this.bb = bb.duplicate();
         this.isReadOnly = bb.isReadOnly;
         // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
         // HeapByteBuffer. We only have to initialize the field when bb is an instance of
@@ -50,6 +50,7 @@
         if (bb instanceof DirectByteBuffer) {
             this.address = bb.address + off;
         }
+        this.bb.order(order);
         this.order = order;
         offset = off;
     }
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java
index dd16388..8e4e2e8 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java
@@ -37,7 +37,7 @@
                             int mark, int pos, int lim, int cap,
                             int off, ByteOrder order) {
         super(mark, pos, lim, cap);
-        this.bb = bb;
+        this.bb = bb.duplicate();
         this.isReadOnly = bb.isReadOnly;
         // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
         // HeapByteBuffer. We only have to initialize the field when bb is an instance of
@@ -49,6 +49,7 @@
         if (bb instanceof DirectByteBuffer) {
             this.address = bb.address + off;
         }
+        this.bb.order(order);
         this.order = order;
         offset = off;
     }
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java
index 48eff4b..e340426 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java
@@ -37,7 +37,7 @@
                           int mark, int pos, int lim, int cap,
                           int off, ByteOrder order) {
         super(mark, pos, lim, cap);
-        this.bb = bb;
+        this.bb = bb.duplicate();
         this.isReadOnly = bb.isReadOnly;
         // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
         // HeapByteBuffer. We only have to initialize the field when bb is an instance of
@@ -49,6 +49,7 @@
         if (bb instanceof DirectByteBuffer) {
             this.address = bb.address + off;
         }
+        this.bb.order(order);
         this.order = order;
         offset = off;
     }
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java
index b2d377b..70f59c9 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java
@@ -37,7 +37,7 @@
                            int mark, int pos, int lim, int cap,
                            int off, ByteOrder order) {
         super(mark, pos, lim, cap);
-        this.bb = bb;
+        this.bb = bb.duplicate();
         this.isReadOnly = bb.isReadOnly;
         // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
         // HeapByteBuffer. We only have to initialize the field when bb is an instance of
@@ -49,6 +49,7 @@
         if (bb instanceof DirectByteBuffer) {
             this.address = bb.address + off;
         }
+        this.bb.order(order);
         this.order = order;
         offset = off;
     }
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java
index 6527308..5178a7e0 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java
@@ -37,7 +37,7 @@
                             int mark, int pos, int lim, int cap,
                             int off, ByteOrder order) {
         super(mark, pos, lim, cap);
-        this.bb = bb;
+        this.bb = bb.duplicate();
         this.isReadOnly = bb.isReadOnly;
         // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
         // HeapByteBuffer. We only have to initialize the field when bb is an instance of
@@ -49,6 +49,7 @@
         if (bb instanceof DirectByteBuffer) {
             this.address = bb.address + off;
         }
+        this.bb.order(order);
         this.order = order;
         offset = off;
     }
diff --git a/ojluni/src/main/java/java/util/Formatter.java b/ojluni/src/main/java/java/util/Formatter.java
index 9a4e234..c656e9c 100755
--- a/ojluni/src/main/java/java/util/Formatter.java
+++ b/ojluni/src/main/java/java/util/Formatter.java
@@ -4193,6 +4193,14 @@
                     grpSep = dfs.getGroupingSeparator();
                     DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
                     grpSize = df.getGroupingSize();
+                    // Android-changed: http://b/33245708 : Some locales have a group separator but
+                    // also patterns without groups. If we do not clear the group separator in these
+                    // cases a divide by zero is thrown when determining where to place the
+                    // separators.
+                    if (!df.isGroupingUsed() || df.getGroupingSize() == 0) {
+                        grpSep = '\0';
+                    }
+                    // Android-changed: end http://b/33245708.
                 }
             }
 
diff --git a/ojluni/src/main/java/java/util/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index 0396e8c..2a24a2e 100755
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -33,6 +33,7 @@
 import java.util.function.Consumer;
 import java.util.function.BiConsumer;
 
+// Android-added: Note about spliterator order b/33945212 in Android N
 /**
  * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
  * with predictable iteration order.  This implementation differs from
@@ -140,6 +141,23 @@
  * 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.keySet()} or {@code c = lhm.values()}, use
+ *         {@code java.util.Spliterators.spliterator(c, c.spliterator().characteristics())}
+ *         instead of {@code c.spliterator()}.
+ *     <li>Instead of {@code lhm.stream()} or {@code lhm.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}openjdk-redirect.html?v=8&path=/technotes/guides/collections/index.html">