Merge "Remove hidden System.arraycopy(byte[]...."
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 2a81be1..486ee90 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -110,8 +110,9 @@
         //System.out.println("DEX FILE cookie is " + mCookie + " fileName=" + fileName);
     }
 
-    DexFile(ByteBuffer[] bufs) throws IOException {
-        mCookie = openInMemoryDexFiles(bufs);
+    DexFile(ByteBuffer[] bufs, ClassLoader loader, DexPathList.Element[] elements)
+            throws IOException {
+        mCookie = openInMemoryDexFiles(bufs, loader, elements);
         mInternalCookie = mCookie;
         mFileName = null;
     }
@@ -370,7 +371,8 @@
                                  elements);
     }
 
-    private static Object openInMemoryDexFiles(ByteBuffer[] bufs) throws IOException {
+    private static Object openInMemoryDexFiles(ByteBuffer[] bufs, ClassLoader loader,
+            DexPathList.Element[] elements) throws IOException {
         // Preprocess the ByteBuffers for openInMemoryDexFilesNative. We extract
         // the backing array (non-direct buffers only) and start/end positions
         // so that the native method does not have to call Java methods anymore.
@@ -382,11 +384,11 @@
             starts[i] = bufs[i].position();
             ends[i] = bufs[i].limit();
         }
-        return openInMemoryDexFilesNative(bufs, arrays, starts, ends);
+        return openInMemoryDexFilesNative(bufs, arrays, starts, ends, loader, elements);
     }
 
     private static native Object openInMemoryDexFilesNative(ByteBuffer[] bufs, byte[][] arrays,
-            int[] starts, int[] ends);
+            int[] starts, int[] ends, ClassLoader loader, DexPathList.Element[] elements);
 
     /*
      * Initiates background verification of this DexFile. This is a sepearate down-call
diff --git a/dalvik/src/main/java/dalvik/system/DexPathList.java b/dalvik/src/main/java/dalvik/system/DexPathList.java
index 227231a..c63bb13 100644
--- a/dalvik/src/main/java/dalvik/system/DexPathList.java
+++ b/dalvik/src/main/java/dalvik/system/DexPathList.java
@@ -266,10 +266,10 @@
 
         try {
             Element[] null_elements = null;
-            DexFile dex = new DexFile(dexFiles);
+            DexFile dex = new DexFile(dexFiles, definingContext, null_elements);
             // Capture class loader context from *before* `dexElements` is set (see comment below).
-            String classLoaderContext = DexFile.getClassLoaderContext(definingContext,
-                    null_elements);
+            String classLoaderContext = dex.isBackedByOatFile()
+                    ? null : DexFile.getClassLoaderContext(definingContext, null_elements);
             dexElements = new Element[] { new Element(dex) };
             // Spawn background thread to verify all classes and cache verification results.
             // Must be called *after* `dexElements` has been initialized for ART to find
@@ -277,7 +277,13 @@
             // the order of the array), but with class loader context from *before*
             // `dexElements` was set because that is what it will be compared against next
             // time the same bytecode is loaded.
-            dex.verifyInBackground(definingContext, classLoaderContext);
+            // We only spawn the background thread if the bytecode is not backed by an oat
+            // file, i.e. this is the first time this bytecode is being loaded and/or
+            // verification results have not been cached yet. Skip spawning the thread on
+            // all subsequent loads of the same bytecode in the same class loader context.
+            if (classLoaderContext != null) {
+                dex.verifyInBackground(definingContext, classLoaderContext);
+            }
         } catch (IOException suppressed) {
             System.logE("Unable to load dex files", suppressed);
             suppressedExceptions.add(suppressed);
@@ -340,7 +346,8 @@
         int elementPos = 0;
         for (ByteBuffer buf : dexFiles) {
             try {
-                DexFile dex = new DexFile(new ByteBuffer[] { buf });
+                DexFile dex = new DexFile(new ByteBuffer[] { buf }, /* classLoader */ null,
+                        /* dexElements */ null);
                 elements[elementPos++] = new Element(dex);
             } catch (IOException suppressed) {
                 System.logE("Unable to load dex file: " + buf, suppressed);
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 0260e68..7d70680 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -696,4 +696,10 @@
      */
     @libcore.api.CorePlatformApi
     public static native void setProcessPackageName(String packageName);
+
+    /**
+     * Sets the full path to data directory of the app running in this process.
+     */
+    @libcore.api.CorePlatformApi
+    public static native void setProcessDataDirectory(String dataDir);
 }
diff --git a/luni/src/main/java/libcore/net/android.mime.types b/luni/src/main/java/libcore/net/android.mime.types
index 8a090fc..dd3b21a 100644
--- a/luni/src/main/java/libcore/net/android.mime.types
+++ b/luni/src/main/java/libcore/net/android.mime.types
@@ -90,4 +90,5 @@
 video/3gpp 3gpp!
 video/mpeg mpeg!
 video/quicktime mov!
+video/vnd.youtube.yt yt
 video/x-matroska mkv!
diff --git a/luni/src/test/java/libcore/libcore/net/MimeUtilsTest.java b/luni/src/test/java/libcore/libcore/net/MimeUtilsTest.java
index cf1e233..26be32b 100644
--- a/luni/src/test/java/libcore/libcore/net/MimeUtilsTest.java
+++ b/luni/src/test/java/libcore/libcore/net/MimeUtilsTest.java
@@ -90,8 +90,13 @@
         assertEquals("video/ogg", MimeUtils.guessMimeTypeFromExtension("ogv"));
     }
 
-    public void test_70851634() {
-        assertEquals("application/vnd.youtube.yt", MimeUtils.guessMimeTypeFromExtension("yt"));
+    public void test_70851634_mimeTypeFromExtension() {
+        assertEquals("video/vnd.youtube.yt", MimeUtils.guessMimeTypeFromExtension("yt"));
+    }
+
+    public void test_70851634_extensionFromMimeType() {
+        assertEquals("yt", MimeUtils.guessExtensionFromMimeType("video/vnd.youtube.yt"));
+        assertEquals("yt", MimeUtils.guessExtensionFromMimeType("application/vnd.youtube.yt"));
     }
 
     public void test_112162449_audio() {
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index 9e3515a..a304cf8 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -748,6 +748,7 @@
     method public void setHiddenApiExemptions(String[]);
     method public static void setHiddenApiUsageLogger(dalvik.system.VMRuntime.HiddenApiUsageLogger);
     method public static void setNonSdkApiUsageConsumer(java.util.function.Consumer<java.lang.String>);
+    method public static void setProcessDataDirectory(String);
     method public static void setProcessPackageName(String);
     method @dalvik.annotation.compat.UnsupportedAppUsage public float setTargetHeapUtilization(float);
     method public void setTargetSdkVersion(int);
diff --git a/ojluni/src/main/java/java/net/Inet6AddressImpl.java b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
index 6b22f8c..bb722f3 100644
--- a/ojluni/src/main/java/java/net/Inet6AddressImpl.java
+++ b/ojluni/src/main/java/java/net/Inet6AddressImpl.java
@@ -44,6 +44,7 @@
 import static android.system.OsConstants.AI_ADDRCONFIG;
 import static android.system.OsConstants.EACCES;
 import static android.system.OsConstants.ECONNREFUSED;
+import static android.system.OsConstants.EPERM;
 import static android.system.OsConstants.NI_NAMEREQD;
 import static android.system.OsConstants.ICMP6_ECHO_REPLY;
 import static android.system.OsConstants.ICMP_ECHOREPLY;
@@ -144,7 +145,8 @@
             // SecurityException to aid in debugging this common mistake.
             // http://code.google.com/p/android/issues/detail?id=15722
             if (gaiException.getCause() instanceof ErrnoException) {
-                if (((ErrnoException) gaiException.getCause()).errno == EACCES) {
+                int errno = ((ErrnoException) gaiException.getCause()).errno;
+                if (errno == EACCES || errno == EPERM) {
                     throw new SecurityException("Permission denied (missing INTERNET permission?)", gaiException);
                 }
             }