Merge "Port "Better ObjectIdentifier validation" change from openJdk8u121-b13"
diff --git a/dalvik/src/main/java/dalvik/annotation/SourceDebugExtension.java b/dalvik/src/main/java/dalvik/annotation/SourceDebugExtension.java
new file mode 100644
index 0000000..fe30adf
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/SourceDebugExtension.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A "system annotation" used to provide the SourceDebugExtension attribute.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface SourceDebugExtension {}
+
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 2a95450..6dd1ba6 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -29,12 +29,16 @@
 import libcore.io.Libcore;
 
 /**
- * Manipulates DEX files. The class is similar in principle to
- * {@link java.util.zip.ZipFile}. It is used primarily by class loaders.
- * <p>
- * Note we don't directly open and read the DEX file here. They're memory-mapped
- * read-only by the VM.
+ * Loads DEX files. This class is meant for internal use and should not be used
+ * by applications.
+ *
+ * @deprecated This class should not be used directly by applications. It will hurt
+ *     performance in most cases and will lead to incorrect execution of bytecode in
+ *     the worst case. Applications should use one of the standard classloaders such
+ *     as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
+ *     in a future Android release</b>.
  */
+@Deprecated
 public final class DexFile {
   /**
    * If close is called, mCookie becomes null but the internal cookie is preserved if the close
@@ -45,22 +49,13 @@
     private final String mFileName;
 
     /**
-     * Opens a DEX file from a given File object. This will usually be a ZIP/JAR
-     * file with a "classes.dex" inside.
+     * Opens a DEX file from a given File object.
      *
-     * The VM will generate the name of the corresponding file in
-     * /data/dalvik-cache and open it, possibly creating or updating
-     * it first if system permissions allow.  Don't pass in the name of
-     * a file in /data/dalvik-cache, as the named file is expected to be
-     * in its original (pre-dexopt) state.
-     *
-     * @param file
-     *            the File object referencing the actual DEX file
-     *
-     * @throws IOException
-     *             if an I/O error occurs, such as the file not being found or
-     *             access rights missing for opening it
+     * @deprecated Applications should use one of the standard classloaders such
+     *     as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
+     *     in a future Android release</b>.
      */
+    @Deprecated
     public DexFile(File file) throws IOException {
         this(file.getPath());
     }
@@ -80,22 +75,13 @@
     }
 
     /**
-     * Opens a DEX file from a given filename. This will usually be a ZIP/JAR
-     * file with a "classes.dex" inside.
+     * Opens a DEX file from a given filename.
      *
-     * The VM will generate the name of the corresponding file in
-     * /data/dalvik-cache and open it, possibly creating or updating
-     * it first if system permissions allow.  Don't pass in the name of
-     * a file in /data/dalvik-cache, as the named file is expected to be
-     * in its original (pre-dexopt) state.
-     *
-     * @param fileName
-     *            the filename of the DEX file
-     *
-     * @throws IOException
-     *             if an I/O error occurs, such as the file not being found or
-     *             access rights missing for opening it
+     * @deprecated Applications should use one of the standard classloaders such
+     *     as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
+     *     in a future Android release</b>.
      */
+    @Deprecated
     public DexFile(String fileName) throws IOException {
         this(fileName, null, null);
     }
@@ -165,24 +151,11 @@
      * to be current, it will be used; if not, the VM will attempt to
      * regenerate it.
      *
-     * This is intended for use by applications that wish to download
-     * and execute DEX files outside the usual application installation
-     * mechanism.  This function should not be called directly by an
-     * application; instead, use a class loader such as
-     * dalvik.system.DexClassLoader.
-     *
-     * @param sourcePathName
-     *  Jar or APK file with "classes.dex".  (May expand this to include
-     *  "raw DEX" in the future.)
-     * @param outputPathName
-     *  File that will hold the optimized form of the DEX data.
-     * @param flags
-     *  Enable optional features.  (Currently none defined.)
-     * @return
-     *  A new or previously-opened DexFile.
-     * @throws IOException
-     *  If unable to open the source or output file.
+     * @deprecated Applications should use one of the standard classloaders such
+     *     as {@link dalvik.system.PathClassLoader} instead. <b>This API will be removed
+     *     in a future Android release</b>.
      */
+    @Deprecated
     static public DexFile loadDex(String sourcePathName, String outputPathName,
         int flags) throws IOException {
 
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
index 19a63af..601d522 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/PrintStreamTest.java
@@ -19,6 +19,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
 import java.io.InputStreamReader;
 import java.io.DataInputStream;
 import java.io.File;
@@ -27,9 +28,16 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Base64;
 import java.util.Locale;
+import libcore.io.IoUtils;
 
 public class PrintStreamTest extends junit.framework.TestCase {
+    private static final String UNICODE_STRING =
+            "K\u03B1\u03BB\u03B7\u00B5\u03B5\u00B4\u03C1\u03B1 \u03BA\u03BF\u00B4\u03C3\u00B5\u03B5";
 
     ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
@@ -70,19 +78,16 @@
      * {@link java.io.PrintStream#PrintStream(String)}
      */
     public void test_Constructor_Ljava_lang_String() throws IOException {
-        MockPrintStream os = new MockPrintStream(testFilePath);
-        assertNotNull(os);
+        PrintStream os = new PrintStream(testFilePath);
+        os.print(UNICODE_STRING);
         os.close();
+        assertFileContents(UNICODE_STRING.getBytes(Charset.defaultCharset()), testFile);
     }
 
     /**
      * {@link java.io.PrintStream#PrintStream(String, String)}
      */
     public void test_Constructor_Ljava_lang_String_Ljava_lang_String() throws Exception {
-        MockPrintStream os = new MockPrintStream(testFilePath, "utf-8");
-        assertNotNull(os);
-        os.close();
-
         // Test that a bogus charset is mentioned in the exception
         try {
             new PrintStream(testFilePath, "Bogus");
@@ -90,6 +95,20 @@
         } catch (UnsupportedEncodingException e) {
             assertNotNull(e.getMessage());
         }
+
+        {
+            PrintStream os = new PrintStream(testFilePath, "utf-8");
+            os.print(UNICODE_STRING);
+            os.close();
+            assertFileContents(UNICODE_STRING.getBytes(StandardCharsets.UTF_8), testFile);
+        }
+
+        {
+            PrintStream os = new PrintStream(testFilePath, "utf-16");
+            os.print(UNICODE_STRING);
+            os.close();
+            assertFileContents(UNICODE_STRING.getBytes(StandardCharsets.UTF_16), testFile);
+        }
     }
 
     /**
@@ -124,7 +143,7 @@
     /**
      * java.io.PrintStream#PrintStream(java.io.OutputStream, boolean, String)
      */
-    public void test_ConstructorLjava_io_OutputStreamZLjava_lang_String() {
+    public void test_ConstructorLjava_io_OutputStreamZLjava_lang_String() throws Exception {
         try {
             new PrintStream(new ByteArrayOutputStream(), false,
                     "%Illegal_name!");
@@ -132,6 +151,24 @@
         } catch (UnsupportedEncodingException e) {
             // expected
         }
+
+        {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            PrintStream printStream = new PrintStream(bos, true /* autoFlush */, "utf-8");
+            printStream.print(UNICODE_STRING);
+            printStream.close();
+            assertByteArraysEqual(UNICODE_STRING.getBytes(StandardCharsets.UTF_8),
+                    bos.toByteArray());
+        }
+
+        {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            PrintStream printStream = new PrintStream(bos, true /* autoFlush */, "utf-16");
+            printStream.print(UNICODE_STRING);
+            printStream.close();
+            assertByteArraysEqual(UNICODE_STRING.getBytes(StandardCharsets.UTF_16),
+                    bos.toByteArray());
+        }
     }
 
     /**
@@ -626,6 +663,59 @@
     }
 
     /**
+     * Tests that a PrintStream with {@code autoFlush == true} will call
+     * {@link OutputStream#flush()} at least once, after the last byte
+     * was written.
+     */
+    public void test_autoFlush_flushesEverything() {
+        CountFlushOutputStream counter = new CountFlushOutputStream(new ByteArrayOutputStream());
+        PrintStream printStream = new PrintStream(counter, true /* autoFlush */);
+        printStream.print("Hello, world!");
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print(Math.PI);
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print("\n");
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.println();
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.println("Lots\nof\nnewlines\n");
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print("Line 1\nLine 2\n".toCharArray());
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+
+        byte[] bytes = "Line without a newline".getBytes(StandardCharsets.UTF_8);
+        printStream.write(bytes, 0, bytes.length);
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+    }
+
+    /**
+     * Tests that a PrintStream with {@code autoFlush == false} will not
+     * call {@link OutputStream#flush()} in regular (non-error) operation.
+     */
+    public void test_noAutoFlush() {
+        CountFlushOutputStream counter = new CountFlushOutputStream(new ByteArrayOutputStream());
+        PrintStream printStream = new PrintStream(counter, false /* autoFlush */);
+        printStream.print("Hello, world!");
+        printStream.print(Math.PI);
+        printStream.print("\n");
+        printStream.println();
+        printStream.println("Lots\nof\nnewlines\n");
+        printStream.print("Line 1\nLine 2\n".toCharArray());
+        byte[] bytes = "Line without a newline".getBytes(StandardCharsets.UTF_8);
+        printStream.write(bytes, 0, bytes.length);
+        assertFalse(counter.hasEverBeenFlushed());
+        assertFalse(counter.hasBeenFlushedSinceLastWrite());
+
+        // checkError() still causes the PrintStream to flush(), even when autoFlush == false.
+        printStream.checkError();
+        assertTrue(counter.hasEverBeenFlushed());
+        assertTrue(counter.hasBeenFlushedSinceLastWrite());
+        printStream.print("This data\nwill not be flushed.");
+        assertTrue(counter.hasEverBeenFlushed());
+        assertFalse(counter.hasBeenFlushedSinceLastWrite());
+    }
+
+    /**
      * java.io.PrintStream#printf(java.lang.String, java.lang.Object...)
      */
     public void test_printfLjava_lang_String$Ljava_lang_Object() {
@@ -669,5 +759,47 @@
         super.tearDown();
     }
 
+    private static void assertByteArraysEqual(byte[] expected, byte[] actual) {
+        String message = "Expected " + Base64.getEncoder().encodeToString(expected) + ", got: "
+                + Base64.getEncoder().encodeToString(actual);
+        assertTrue(message, Arrays.equals(actual, expected));
+    }
+
+    private static void assertFileContents(byte[] expected, File file) throws IOException {
+        byte[] actual = IoUtils.readFileAsByteArray(file.getAbsolutePath());
+        assertByteArraysEqual(expected, actual);
+    }
+
+    static class CountFlushOutputStream extends FilterOutputStream {
+        private boolean hasBeenFlushedSinceLastWrite = false;
+        private boolean hasEverBeenFlushed = false;
+
+        public CountFlushOutputStream(OutputStream delegate) {
+            super(delegate);
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            super.write(b);
+            hasBeenFlushedSinceLastWrite = false;
+        }
+
+        @Override
+        public void flush() throws IOException {
+            super.flush();
+            hasBeenFlushedSinceLastWrite = true;
+            hasEverBeenFlushed = true;
+        }
+
+        /** Whether {@link #flush()} has been called since the last write. */
+        public boolean hasBeenFlushedSinceLastWrite() {
+            return hasBeenFlushedSinceLastWrite;
+        }
+
+        /** Whether {@link #flush()} has ever been called after this stream was constructed. */
+        public boolean hasEverBeenFlushed() {
+            return hasEverBeenFlushed;
+        }
+    }
 
 }
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index ffba98a..d1eb3d4 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -277,6 +277,84 @@
         }
     }
 
+    /**
+     * Helper function to fetch services for Service.Algorithm IDs
+     */
+    private static Provider.Service getService(Provider p, String id) {
+        String[] typeAndAlg = id.split("\\.", 2);
+        assertEquals(id + " is not formatted as expected.", 2, typeAndAlg.length);
+        return p.getService(typeAndAlg[0], typeAndAlg[1]);
+    }
+
+    /**
+     * Ensures that, for all algorithms provided by Conscrypt, there is no alias from
+     * the BC provider that's not provided by Conscrypt.  If there is, then a request
+     * for that alias with no provider specified will return the BC implementation of
+     * it even though we have a Conscrypt implementation available.
+     */
+    public void test_Provider_ConscryptOverridesBouncyCastle() throws Exception {
+        if (StandardNames.IS_RI) {
+            // These providers aren't installed on RI
+            return;
+        }
+        Provider conscrypt = Security.getProvider("AndroidOpenSSL");
+        Provider bc = Security.getProvider("BC");
+
+        // 1. Find all the algorithms provided by Conscrypt.
+        Set<String> conscryptAlgs = new HashSet<>();
+        for (Entry<Object, Object> entry : conscrypt.entrySet()) {
+            String key = (String) entry.getKey();
+            if (key.contains(" ")) {
+                // These are implementation properties like "Provider.id name"
+                continue;
+            }
+            if (key.startsWith("Alg.Alias.")) {
+                // Ignore aliases, we only want the concrete algorithms
+                continue;
+            }
+            conscryptAlgs.add(key);
+        }
+
+        // 2. Determine which classes in BC implement those algorithms
+        Set<String> bcClasses = new HashSet<>();
+        for (String conscryptAlg : conscryptAlgs) {
+            Provider.Service service = getService(bc, conscryptAlg);
+            if (service != null) {
+                bcClasses.add(service.getClassName());
+            }
+        }
+        assertTrue(bcClasses.size() > 0);  // Sanity check
+
+        // 3. Determine which IDs in BC point to that set of classes
+        Set<String> shouldBeOverriddenBcIds = new HashSet<>();
+        for (Object keyObject : bc.keySet()) {
+            String key = (String) keyObject;
+            if (key.contains(" ")) {
+                continue;
+            }
+            if (key.startsWith("Alg.Alias.")) {
+                key = key.substring("Alg.Alias.".length());
+            }
+            Provider.Service service = getService(bc, key);
+            if (bcClasses.contains(service.getClassName())) {
+                shouldBeOverriddenBcIds.add(key);
+            }
+        }
+        assertTrue(shouldBeOverriddenBcIds.size() > 0);  // Sanity check
+
+        // 4. Check each of those IDs to ensure that it's present in Conscrypt
+        Set<String> nonOverriddenIds = new TreeSet<>();
+        for (String shouldBeOverridenBcId : shouldBeOverriddenBcIds) {
+            if (getService(conscrypt, shouldBeOverridenBcId) == null) {
+                nonOverriddenIds.add(shouldBeOverridenBcId);
+            }
+        }
+        assertTrue("Conscrypt does not provide IDs " + nonOverriddenIds
+                + ", but it does provide other IDs that point to the same implementation(s)"
+                + " in BouncyCastle.",
+                nonOverriddenIds.isEmpty());
+    }
+
     private static final String[] TYPES_SERVICES_CHECKED = new String[] {
             "KeyFactory", "CertPathBuilder", "Cipher", "SecureRandom",
             "AlgorithmParameterGenerator", "Signature", "KeyPairGenerator", "CertificateFactory",
diff --git a/ojluni/src/main/java/java/io/PrintStream.java b/ojluni/src/main/java/java/io/PrintStream.java
index 08bb3a3..809d39b 100644
--- a/ojluni/src/main/java/java/io/PrintStream.java
+++ b/ojluni/src/main/java/java/io/PrintStream.java
@@ -70,6 +70,7 @@
     private BufferedWriter textOut;
     private OutputStreamWriter charOut;
 
+    // Android-added: Lazy initialization of charOut and textOut.
     private Charset charset;
 
     /**
@@ -104,11 +105,18 @@
     private PrintStream(boolean autoFlush, OutputStream out) {
         super(out);
         this.autoFlush = autoFlush;
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this);
+        // this.textOut = new BufferedWriter(charOut);
     }
 
     private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
         super(out);
         this.autoFlush = autoFlush;
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this, charset);
+        // this.textOut = new BufferedWriter(charOut);
+        this.charset = charset;
     }
 
     /* Variant of the private constructor so that the given charset name
@@ -344,7 +352,7 @@
 
     private boolean closing = false; /* To avoid recursive closing */
 
-    // Android-changed: Lazily initialize textOut.
+    // BEGIN Android-added: Lazy initialization of charOut and textOut.
     private BufferedWriter getTextOut() {
         if (textOut == null) {
             charOut = charset != null ? new OutputStreamWriter(this, charset) :
@@ -353,6 +361,7 @@
         }
         return textOut;
     }
+    // END Android-added: Lazy initialization of charOut and textOut.
 
     /**
      * Closes the stream.  This is done by flushing the stream and then closing
@@ -365,10 +374,12 @@
             if (! closing) {
                 closing = true;
                 try {
-                    // Android-changed: Lazily initialized.
+                    // BEGIN Android-changed: Lazy initialization of charOut and textOut.
+                    // textOut.close();
                     if (textOut != null) {
                         textOut.close();
                     }
+                    // END Android-changed: Lazy initialization of charOut and textOut.
                     out.close();
                 }
                 catch (IOException x) {
@@ -512,7 +523,7 @@
         try {
             synchronized (this) {
                 ensureOpen();
-                // Android-changed: Lazily initialized.
+                // Android-added: Lazy initialization of charOut and textOut.
                 BufferedWriter textOut = getTextOut();
                 textOut.write(buf);
                 textOut.flushBuffer();
@@ -536,7 +547,7 @@
         try {
             synchronized (this) {
                 ensureOpen();
-                // Android-changed: Lazily initialized.
+                // Android-added: Lazy initialization of charOut and textOut.
                 BufferedWriter textOut = getTextOut();
                 textOut.write(s);
                 textOut.flushBuffer();
@@ -557,7 +568,7 @@
         try {
             synchronized (this) {
                 ensureOpen();
-                // Android-changed: Lazily initialized.
+                // Android-added: Lazy initialization of charOut and textOut.
                 BufferedWriter textOut = getTextOut();
                 textOut.newLine();
                 textOut.flushBuffer();
diff --git a/ojluni/src/main/native/NativeThread.c b/ojluni/src/main/native/NativeThread.c
index f8a68e7..9147bc3 100644
--- a/ojluni/src/main/native/NativeThread.c
+++ b/ojluni/src/main/native/NativeThread.c
@@ -35,8 +35,10 @@
 #ifdef __linux__
   #include <pthread.h>
   #include <sys/signal.h>
+  // Android-changed: Bionic (and AsynchronousCloseMonitor) expects libcore to use
+  // __SIGRTMIN + 2, not __SIGRTMAX - 2
   /* Also defined in net/linux_close.c */
-  #define INTERRUPT_SIGNAL (__SIGRTMAX - 2)
+  #define INTERRUPT_SIGNAL (__SIGRTMIN + 2)
 #elif __solaris__
   #include <thread.h>
   #include <signal.h>
diff --git a/ojluni/src/main/native/linux_close.cpp b/ojluni/src/main/native/linux_close.cpp
index e9a2588..6f88c93 100644
--- a/ojluni/src/main/native/linux_close.cpp
+++ b/ojluni/src/main/native/linux_close.cpp
@@ -45,7 +45,9 @@
 /*
  * Signal to unblock thread
  */
-static int sigWakeup = (__SIGRTMAX - 2);
+// Android-changed: Bionic (and AsynchronousCloseMonitor) expects libcore to use
+// __SIGRTMIN + 2, not __SIGRTMAX - 2
+static int sigWakeup = (__SIGRTMIN + 2);
 
 /*
  * Close or dup2 a file descriptor ensuring that all threads blocked on