Merge "java.security.PKCS12Attribute: port class from jdk8u60"
diff --git a/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java b/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java
new file mode 100644
index 0000000..316a08f
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 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.system;
+
+import java.nio.ByteBuffer;
+import sun.misc.Cleaner;
+
+/**
+ * {@link ClassLoader} implementation for loading Dex file from
+ * memory.
+ *
+ * @hide
+ */
+public class InMemoryDexClassLoader extends ClassLoader {
+    private final DexData dexData;
+
+    /**
+     * Creates a new in-memory DEX class loader.
+     *
+     * @param dexBuffer buffer containing DEX file contents between
+     *                       <tt>buffer.position()</tt> and <tt>buffer.limit()</tt>.
+     * @param parent the parent class loader for delegation.
+     */
+    public InMemoryDexClassLoader(ByteBuffer dexBuffer, ClassLoader parent) {
+        super(parent);
+        if (dexBuffer == null) {
+            throw new NullPointerException("dexData == null");
+        }
+        this.dexData = new DexData(dexBuffer);
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        try {
+            return dexData.findClass(name, this);
+        } catch (Exception e) {
+            throw new ClassNotFoundException("Didn't find class \"" + name + "\"", e);
+        }
+    }
+
+    @Override
+    protected synchronized Package getPackage(String name) {
+        // This is duplicated from BaseDexClassLoader.getPackage which
+        // has an extensive comment on why this needs to be defined.
+        if (name == null || name.isEmpty()) {
+            return null;
+        }
+
+        Package pkg = super.getPackage(name);
+        if (pkg == null) {
+            pkg = definePackage(name, "Unknown", "0.0", "Unknown",
+                                "Unknown", "0.0", "Unknown", null);
+        }
+        return pkg;
+    }
+
+    /**
+     * Representation of native resources associated with DEX files loaded by
+     * InMemoryDexClassLoader.
+     */
+    private static final class DexData {
+        private final long cookie;
+
+        DexData(ByteBuffer buffer) {
+            if (buffer.isDirect()) {
+                cookie = initializeWithDirectBuffer(buffer, buffer.position(), buffer.limit());
+            } else {
+                cookie = initializeWithArray(buffer.array(), buffer.position(), buffer.limit());
+            }
+
+            if (cookie != 0) {
+                // Register for clean-up when this instance is phantom
+                // reachable. Cleaner instances are inserted in a global
+                // queue to preserve liveness. DexDataDeallocator must not
+                // have a pointer to DexData otherwise it will prevent
+                // cleaning and the freeing of the native resources.
+                Cleaner.create(this, new DexDataDeallocator(cookie));
+            }
+        }
+
+        protected Class<?> findClass(String name, ClassLoader loader) {
+            return findClass(name, loader, cookie);
+        }
+
+        private static native long initializeWithDirectBuffer(ByteBuffer buffer,
+                                                              int start, int end);
+        private static native long initializeWithArray(byte[] array, int start, int end);
+        private static native void uninitialize(long cookie);
+        private native Class findClass(String name, ClassLoader loader, long cookie);
+    }
+
+    /**
+     * Helper class to release native resources associated with DexData instances.
+     */
+    private static final class DexDataDeallocator implements Runnable {
+        private final long cookie;
+
+        DexDataDeallocator(long cookie) {
+            this.cookie = cookie;
+        }
+
+        public void run() {
+            DexData.uninitialize(cookie);
+        }
+    }
+}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java
index 170c901..5d97393 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/ClassTest.java
@@ -21,6 +21,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
@@ -34,7 +36,9 @@
 import java.security.Security;
 import java.util.Arrays;
 import java.util.List;
+import java.util.TreeMap;
 import java.util.Vector;
+import java.util.function.Function;
 
 public class ClassTest extends junit.framework.TestCase {
 
@@ -545,47 +549,6 @@
         }
     }
 
-    /**
-     * java.lang.Class#toString()
-     */
-    public void test_toString() throws ClassNotFoundException {
-        assertEquals("Class toString printed wrong value",
-                "int", int.class.toString());
-        Class<?> clazz = null;
-        clazz = Class.forName("[I");
-        assertEquals("Class toString printed wrong value",
-                "class [I", clazz.toString());
-
-        clazz = Class.forName("java.lang.Object");
-        assertEquals("Class toString printed wrong value",
-                "class java.lang.Object", clazz.toString());
-
-        clazz = Class.forName("[Ljava.lang.Object;");
-        assertEquals("Class toString printed wrong value",
-                "class [Ljava.lang.Object;", clazz.toString());
-    }
-
-    /**
-     * java.lang.Class#getTypeName()
-     */
-    public void test_getTypeName() throws ClassNotFoundException {
-        assertEquals("Class toString printed wrong value",
-                "int", int.class.getTypeName());
-
-        Class<?> clazz = null;
-        clazz = Class.forName("[I");
-        assertEquals("Class toString printed wrong value",
-                "int[]", clazz.getTypeName());
-
-        clazz = Class.forName("java.lang.Object");
-        assertEquals("Class toString printed wrong value",
-                "java.lang.Object", clazz.getTypeName());
-
-        clazz = Class.forName("[Ljava.lang.Object;");
-        assertEquals("Class toString printed wrong value",
-                "java.lang.Object[]", clazz.getTypeName());
-    }
-
     // Regression Test for JIRA-2047
     public void test_getResourceAsStream_withSharpChar() throws Exception {
         // Class.getResourceAsStream() requires a leading "/" for absolute paths.
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
index cd2666f..6e3e181 100644
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
@@ -201,16 +201,6 @@
         return accessFlags;
     }
 
-    /**
-     * Returns the constructor's signature in non-printable form. This is called
-     * (only) from IO native code and needed for deriving the serialVersionUID
-     * of the class
-     *
-     * @return The constructor's signature.
-     */
-    @SuppressWarnings("unused")
-    abstract String getSignature();
-
     static final class GenericInfo {
         final ListOfTypes genericExceptionTypes;
         final ListOfTypes genericParameterTypes;
diff --git a/luni/src/main/java/java/math/BigInt.java b/luni/src/main/java/java/math/BigInt.java
index 2cffee6..5e28a73 100644
--- a/luni/src/main/java/java/math/BigInt.java
+++ b/luni/src/main/java/java/math/BigInt.java
@@ -334,11 +334,11 @@
 
     static BigInt generatePrimeDefault(int bitLength) {
         BigInt r = newBigInt();
-        NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0, 0);
+        NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0);
         return r;
     }
 
     boolean isPrime(int certainty) {
-        return NativeBN.BN_is_prime_ex(bignum, certainty, 0);
+        return NativeBN.BN_primality_test(bignum, certainty, false);
     }
 }
diff --git a/luni/src/main/java/java/math/NativeBN.java b/luni/src/main/java/java/math/NativeBN.java
index 64b4468..d269f2e 100644
--- a/luni/src/main/java/java/math/NativeBN.java
+++ b/luni/src/main/java/java/math/NativeBN.java
@@ -120,12 +120,15 @@
 
 
     public static native void BN_generate_prime_ex(long ret, int bits, boolean safe,
-                                                   long add, long rem, long cb);
+                                                   long add, long rem);
     // int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe,
     //         const BIGNUM *add, const BIGNUM *rem, BN_GENCB *cb);
 
-    public static native boolean BN_is_prime_ex(long p, int nchecks, long cb);
-    // int BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, BN_GENCB *cb);
+    public static native boolean BN_primality_test(long candidate, int checks,
+                                                   boolean do_trial_division);
+    // int BN_primality_test(int *is_probably_prime, const BIGNUM *candidate, int checks,
+    //                       BN_CTX *ctx, int do_trial_division, BN_GENCB *cb);
+    // Returns *is_probably_prime on success and throws an exception on error.
 
     public static native long getNativeFinalizer();
     // &BN_free
diff --git a/luni/src/main/java/java/security/security.properties b/luni/src/main/java/java/security/security.properties
index 6b9007b..b5f4d25 100644
--- a/luni/src/main/java/java/security/security.properties
+++ b/luni/src/main/java/java/security/security.properties
@@ -62,3 +62,5 @@
 
 # Disable weak algorithms in CertPathVerifier and CertPathBuilder.
 jdk.certpath.disabledAlgorithms=MD2, MD4, RSA keySize < 1024, DSA keySize < 1024, EC keySize < 160
+
+securerandom.strongAlgorithms=SHA1PRNG:AndroidOpenSSL
diff --git a/luni/src/main/java/libcore/net/MimeUtils.java b/luni/src/main/java/libcore/net/MimeUtils.java
index 58afdf9..b746273 100644
--- a/luni/src/main/java/libcore/net/MimeUtils.java
+++ b/luni/src/main/java/libcore/net/MimeUtils.java
@@ -211,6 +211,12 @@
         add("application/x-xcf", "xcf");
         add("application/x-xfig", "fig");
         add("application/xhtml+xml", "xhtml");
+        // Video mime types for 3GPP first so they'll be default for guessMimeTypeFromExtension
+        // See RFC 3839 for 3GPP and RFC 4393 for 3GPP2
+        add("video/3gpp", "3gpp");
+        add("video/3gpp", "3gp");
+        add("video/3gpp2", "3gpp2");
+        add("video/3gpp2", "3g2");
         add("audio/3gpp", "3gpp");
         add("audio/aac", "aac");
         add("audio/aac-adts", "aac");
@@ -354,10 +360,6 @@
         add("text/x-tex", "cls");
         add("text/x-vcalendar", "vcs");
         add("text/x-vcard", "vcf");
-        add("video/3gpp", "3gpp");
-        add("video/3gpp", "3gp");
-        add("video/3gpp2", "3gpp2");
-        add("video/3gpp2", "3g2");
         add("video/avi", "avi");
         add("video/dl", "dl");
         add("video/dv", "dif");
diff --git a/luni/src/main/native/canonicalize_path.cpp b/luni/src/main/native/canonicalize_path.cpp
deleted file mode 100644
index b2a2a01..0000000
--- a/luni/src/main/native/canonicalize_path.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the authors may not be used to endorse or promote
- *    products derived from this software without specific prior written
- *    permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "readlink.h"
-
-#include <string>
-
-#include <errno.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-/**
- * This differs from realpath(3) mainly in its behavior when a path element does not exist or can
- * not be searched. realpath(3) treats that as an error and gives up, but we have Java-compatible
- * behavior where we just assume the path element was not a symbolic link. This leads to a textual
- * treatment of ".." from that point in the path, which may actually lead us back to a path we
- * can resolve (as in "/tmp/does-not-exist/../blah.txt" which would be an error for realpath(3)
- * but "/tmp/blah.txt" under the traditional Java interpretation).
- *
- * This implementation also removes all the fixed-length buffers of the C original.
- */
-bool canonicalize_path(const char* path, std::string& resolved) {
-    // 'path' must be an absolute path.
-    if (path[0] != '/') {
-        errno = EINVAL;
-        return false;
-    }
-
-    resolved = "/";
-    if (path[1] == '\0') {
-        return true;
-    }
-
-    // Iterate over path components in 'left'.
-    int symlinkCount = 0;
-    std::string left(path + 1);
-    while (!left.empty()) {
-        // Extract the next path component.
-        size_t nextSlash = left.find('/');
-        std::string nextPathComponent = left.substr(0, nextSlash);
-        if (nextSlash != std::string::npos) {
-            left.erase(0, nextSlash + 1);
-        } else {
-            left.clear();
-        }
-        if (nextPathComponent.empty()) {
-            continue;
-        } else if (nextPathComponent == ".") {
-            continue;
-        } else if (nextPathComponent == "..") {
-            // Strip the last path component except when we have single "/".
-            if (resolved.size() > 1) {
-                resolved.erase(resolved.rfind('/'));
-            }
-            continue;
-        }
-
-        // Append the next path component.
-        if (resolved[resolved.size() - 1] != '/') {
-            resolved += '/';
-        }
-        resolved += nextPathComponent;
-
-        // See if we've got a symbolic link, and resolve it if so.
-        struct stat sb;
-        if (lstat(resolved.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode)) {
-            if (symlinkCount++ > MAXSYMLINKS) {
-                errno = ELOOP;
-                return false;
-            }
-
-            std::string symlink;
-            if (!readlink(resolved.c_str(), symlink)) {
-                return false;
-            }
-            if (symlink[0] == '/') {
-                // The symbolic link is absolute, so we need to start from scratch.
-                resolved = "/";
-            } else if (resolved.size() > 1) {
-                // The symbolic link is relative, so we just lose the last path component (which
-                // was the link).
-                resolved.erase(resolved.rfind('/'));
-            }
-
-            if (!left.empty()) {
-                const char* maybeSlash = (symlink[symlink.size() - 1] != '/') ? "/" : "";
-                left = symlink + maybeSlash + left;
-            } else {
-                left = symlink;
-            }
-        }
-    }
-
-    // Remove trailing slash except when the resolved pathname is a single "/".
-    if (resolved.size() > 1 && resolved[resolved.size() - 1] == '/') {
-        resolved.erase(resolved.size() - 1, 1);
-    }
-    return true;
-}
diff --git a/luni/src/main/native/java_math_NativeBN.cpp b/luni/src/main/native/java_math_NativeBN.cpp
index e540942..45df4c5 100644
--- a/luni/src/main/native/java_math_NativeBN.cpp
+++ b/luni/src/main/native/java_math_NativeBN.cpp
@@ -51,11 +51,18 @@
   return reinterpret_cast<BIGNUM*>(static_cast<uintptr_t>(address));
 }
 
-static bool throwExceptionIfNecessary(JNIEnv* env) {
+static void throwException(JNIEnv* env) {
   long error = ERR_get_error();
+  // OpenSSL's error queue may contain multiple errors. Clean up after them.
+  ERR_clear_error();
+
   if (error == 0) {
-    return false;
+    // An operation failed but did not push to the error queue. Throw a default
+    // exception.
+    jniThrowException(env, "java/lang/ArithmeticException", "Operation failed");
+    return;
   }
+
   char message[256];
   ERR_error_string_n(error, message, sizeof(message));
   int reason = ERR_GET_REASON(error);
@@ -68,9 +75,6 @@
   } else {
     jniThrowException(env, "java/lang/ArithmeticException", message);
   }
-  // OpenSSL's error queue may contain multiple errors. Clean up after them.
-  ERR_clear_error();
-  return true;
 }
 
 static int isValidHandle(JNIEnv* env, jlong handle, const char* message) {
@@ -102,7 +106,9 @@
 
 static jlong NativeBN_BN_new(JNIEnv* env, jclass) {
   jlong result = static_cast<jlong>(reinterpret_cast<uintptr_t>(BN_new()));
-  throwExceptionIfNecessary(env);
+  if (!result) {
+    throwException(env);
+  }
   return result;
 }
 
@@ -122,8 +128,9 @@
 
 static void NativeBN_BN_copy(JNIEnv* env, jclass, jlong to, jlong from) {
   if (!twoValidHandles(env, to, from)) return;
-  BN_copy(toBigNum(to), toBigNum(from));
-  throwExceptionIfNecessary(env);
+  if (!BN_copy(toBigNum(to), toBigNum(from))) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, jlong java_dw, jboolean neg) {
@@ -131,28 +138,27 @@
 
   uint64_t dw = java_dw;
   BIGNUM* a = toBigNum(a0);
-  int ok;
 
   static_assert(sizeof(dw) == sizeof(BN_ULONG) ||
                 sizeof(dw) == 2*sizeof(BN_ULONG), "Unknown BN configuration");
 
   if (sizeof(dw) == sizeof(BN_ULONG)) {
-    ok = BN_set_word(a, dw);
-  } else if (sizeof(dw) == 2 * sizeof(BN_ULONG)) {
-    ok = (bn_wexpand(a, 2) != NULL);
-    if (ok) {
-      a->d[0] = dw;
-      a->d[1] = dw >> 32;
-      a->top = 2;
-      bn_correct_top(a);
+    if (!BN_set_word(a, dw)) {
+      throwException(env);
+      return;
     }
+  } else if (sizeof(dw) == 2 * sizeof(BN_ULONG)) {
+    if (!bn_wexpand(a, 2)) {
+      throwException(env);
+      return;
+    }
+    a->d[0] = dw;
+    a->d[1] = dw >> 32;
+    a->top = 2;
+    bn_correct_top(a);
   }
 
   BN_set_negative(a, neg);
-
-  if (!ok) {
-    throwExceptionIfNecessary(env);
-  }
 }
 
 static void NativeBN_putLongInt(JNIEnv* env, jclass cls, jlong a, jlong dw) {
@@ -171,7 +177,9 @@
   }
   BIGNUM* a = toBigNum(a0);
   int result = BN_dec2bn(&a, chars.c_str());
-  throwExceptionIfNecessary(env);
+  if (result == 0) {
+    throwException(env);
+  }
   return result;
 }
 
@@ -183,7 +191,9 @@
   }
   BIGNUM* a = toBigNum(a0);
   int result = BN_hex2bn(&a, chars.c_str());
-  throwExceptionIfNecessary(env);
+  if (result == 0) {
+    throwException(env);
+  }
   return result;
 }
 
@@ -193,10 +203,12 @@
   if (bytes.get() == NULL) {
     return;
   }
-  BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, toBigNum(ret));
-  if (!throwExceptionIfNecessary(env) && neg) {
-    BN_set_negative(toBigNum(ret), true);
+  if (!BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, toBigNum(ret))) {
+    throwException(env);
+    return;
   }
+
+  BN_set_negative(toBigNum(ret), neg);
 }
 
 /**
@@ -221,28 +233,29 @@
     const int wlen = len;
 #endif
     const unsigned int* tmpInts = reinterpret_cast<const unsigned int*>(scopedArray.get());
-    if ((tmpInts != NULL) && (bn_wexpand(ret, wlen) != NULL)) {
-#ifdef __LP64__
-      if (len % 2) {
-        ret->d[wlen - 1] = tmpInts[--len];
-      }
-      if (len > 0) {
-        for (int i = len - 2; i >= 0; i -= 2) {
-          ret->d[i/2] = ((unsigned long long)tmpInts[i+1] << 32) | tmpInts[i];
-        }
-      }
-#else
-      int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0);
-#endif
-      ret->top = wlen;
-      ret->neg = neg;
-      // need to call this due to clear byte at top if avoiding
-      // having the top bit set (-ve number)
-      // Basically get rid of top zero ints:
-      bn_correct_top(ret);
-    } else {
-      throwExceptionIfNecessary(env);
+    if (!bn_wexpand(ret, wlen)) {
+      throwException(env);
+      return;
     }
+
+#ifdef __LP64__
+    if (len % 2) {
+      ret->d[wlen - 1] = tmpInts[--len];
+    }
+    if (len > 0) {
+      for (int i = len - 2; i >= 0; i -= 2) {
+        ret->d[i/2] = ((unsigned long long)tmpInts[i+1] << 32) | tmpInts[i];
+      }
+    }
+#else
+    int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0);
+#endif
+    ret->top = wlen;
+    ret->neg = neg;
+    // need to call this due to clear byte at top if avoiding
+    // having the top bit set (-ve number)
+    // Basically get rid of top zero ints:
+    bn_correct_top(ret);
   } else { // (len = 0) means value = 0 and sign will be 0, too.
     ret->top = 0;
   }
@@ -257,57 +270,63 @@
 #define BYTES2ULONG(bytes, k) \
     (((bytes)[(k) + 3] & 0xff) | ((bytes)[(k) + 2] & 0xff) << 8 | ((bytes)[(k) + 1] & 0xff) << 16 | ((bytes)[(k) + 0] & 0xff) << 24)
 #endif
-static void negBigEndianBytes2bn(JNIEnv*, jclass, const unsigned char* bytes, int bytesLen, jlong ret0) {
+
+// negBigEndianBytes2bn interprets |bytes| as a little-endian two's complement negative integer and
+// sets |ret0| to the result. It returns true on success and false on allocation failure.
+static bool negBigEndianBytes2bn(JNIEnv*, jclass, const unsigned char* bytes, int bytesLen, jlong ret0) {
   BIGNUM* ret = toBigNum(ret0);
 
   bn_check_top(ret);
   // FIXME: assert bytesLen > 0
   int wLen = (bytesLen + sizeof(BN_ULONG) - 1) / sizeof(BN_ULONG);
   int firstNonzeroDigit = -2;
-  if (bn_wexpand(ret, wLen) != NULL) {
-    BN_ULONG* d = ret->d;
-    BN_ULONG di;
-    ret->top = wLen;
-    int highBytes = bytesLen % sizeof(BN_ULONG);
-    int k = bytesLen;
-    // Put bytes to the int array starting from the end of the byte array
-    int i = 0;
-    while (k > highBytes) {
-      k -= sizeof(BN_ULONG);
-      di = BYTES2ULONG(bytes, k);
-      if (di != 0) {
-        d[i] = -di;
-        firstNonzeroDigit = i;
-        i++;
-        while (k > highBytes) {
-          k -= sizeof(BN_ULONG);
-          d[i] = ~BYTES2ULONG(bytes, k);
-          i++;
-        }
-        break;
-      } else {
-        d[i] = 0;
-        i++;
-      }
-    }
-    if (highBytes != 0) {
-      di = -1;
-      // Put the first bytes in the highest element of the int array
-      if (firstNonzeroDigit != -2) {
-        for (k = 0; k < highBytes; k++) {
-          di = (di << 8) | (bytes[k] & 0xFF);
-        }
-        d[i] = ~di;
-      } else {
-        for (k = 0; k < highBytes; k++) {
-          di = (di << 8) | (bytes[k] & 0xFF);
-        }
-        d[i] = -di;
-      }
-    }
-    // The top may have superfluous zeros, so fix it.
-    bn_correct_top(ret);
+  if (!bn_wexpand(ret, wLen)) {
+    return false;
   }
+
+  BN_ULONG* d = ret->d;
+  BN_ULONG di;
+  ret->top = wLen;
+  int highBytes = bytesLen % sizeof(BN_ULONG);
+  int k = bytesLen;
+  // Put bytes to the int array starting from the end of the byte array
+  int i = 0;
+  while (k > highBytes) {
+    k -= sizeof(BN_ULONG);
+    di = BYTES2ULONG(bytes, k);
+    if (di != 0) {
+      d[i] = -di;
+      firstNonzeroDigit = i;
+      i++;
+      while (k > highBytes) {
+        k -= sizeof(BN_ULONG);
+        d[i] = ~BYTES2ULONG(bytes, k);
+        i++;
+      }
+      break;
+    } else {
+      d[i] = 0;
+      i++;
+    }
+  }
+  if (highBytes != 0) {
+    di = -1;
+    // Put the first bytes in the highest element of the int array
+    if (firstNonzeroDigit != -2) {
+      for (k = 0; k < highBytes; k++) {
+        di = (di << 8) | (bytes[k] & 0xFF);
+      }
+      d[i] = ~di;
+    } else {
+      for (k = 0; k < highBytes; k++) {
+        di = (di << 8) | (bytes[k] & 0xFF);
+      }
+      d[i] = -di;
+    }
+  }
+  // The top may have superfluous zeros, so fix it.
+  bn_correct_top(ret);
+  return true;
 }
 
 static void NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, jlong ret0) {
@@ -323,16 +342,21 @@
     //
     // We can use the existing BN implementation for unsigned big endian bytes:
     //
-    BN_bin2bn(s, bytesLen, ret);
+    if (!BN_bin2bn(s, bytesLen, ret)) {
+      throwException(env);
+      return;
+    }
     BN_set_negative(ret, false);
   } else { // Negative value!
     //
     // We need to apply two's complement:
     //
-    negBigEndianBytes2bn(env, cls, s, bytesLen, ret0);
+    if (!negBigEndianBytes2bn(env, cls, s, bytesLen, ret0)) {
+      throwException(env);
+      return;
+    }
     BN_set_negative(ret, true);
   }
-  throwExceptionIfNecessary(env);
 }
 
 static jlong NativeBN_longInt(JNIEnv* env, jclass, jlong a0) {
@@ -373,6 +397,7 @@
   if (!oneValidHandle(env, a)) return NULL;
   char* tmpStr = BN_bn2dec(toBigNum(a));
   if (tmpStr == NULL) {
+    throwException(env);
     return NULL;
   }
   char* retStr = leadingZerosTrimmed(tmpStr);
@@ -385,6 +410,7 @@
   if (!oneValidHandle(env, a)) return NULL;
   char* tmpStr = BN_bn2hex(toBigNum(a));
   if (tmpStr == NULL) {
+    throwException(env);
     return NULL;
   }
   char* retStr = leadingZerosTrimmed(tmpStr);
@@ -472,111 +498,135 @@
 
 static jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass, jlong a, int n) {
   if (!oneValidHandle(env, a)) return JNI_FALSE;
-  return BN_is_bit_set(toBigNum(a), n);
+  return BN_is_bit_set(toBigNum(a), n) ? JNI_TRUE : JNI_FALSE;
 }
 
 static void NativeBN_BN_shift(JNIEnv* env, jclass, jlong r, jlong a, int n) {
   if (!twoValidHandles(env, r, a)) return;
+  int ok;
   if (n >= 0) {
-    BN_lshift(toBigNum(r), toBigNum(a), n);
+    ok = BN_lshift(toBigNum(r), toBigNum(a), n);
   } else {
-    BN_rshift(toBigNum(r), toBigNum(a), -n);
+    ok = BN_rshift(toBigNum(r), toBigNum(a), -n);
   }
-  throwExceptionIfNecessary(env);
+  if (!ok) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_add_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
   if (!oneValidHandle(env, a)) return;
-  BN_add_word(toBigNum(a), w);
-  throwExceptionIfNecessary(env);
+  if (!BN_add_word(toBigNum(a), w)) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_mul_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
   if (!oneValidHandle(env, a)) return;
-  BN_mul_word(toBigNum(a), w);
-  throwExceptionIfNecessary(env);
+  if (!BN_mul_word(toBigNum(a), w)) {
+    throwException(env);
+  }
 }
 
 static BN_ULONG NativeBN_BN_mod_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
   if (!oneValidHandle(env, a)) return 0;
-  int result = BN_mod_word(toBigNum(a), w);
-  throwExceptionIfNecessary(env);
+  BN_ULONG result = BN_mod_word(toBigNum(a), w);
+  if (result == (BN_ULONG)-1) {
+    throwException(env);
+  }
   return result;
 }
 
 static void NativeBN_BN_add(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
   if (!threeValidHandles(env, r, a, b)) return;
-  BN_add(toBigNum(r), toBigNum(a), toBigNum(b));
-  throwExceptionIfNecessary(env);
+  if (!BN_add(toBigNum(r), toBigNum(a), toBigNum(b))) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_sub(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
   if (!threeValidHandles(env, r, a, b)) return;
-  BN_sub(toBigNum(r), toBigNum(a), toBigNum(b));
-  throwExceptionIfNecessary(env);
+  if (!BN_sub(toBigNum(r), toBigNum(a), toBigNum(b))) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_gcd(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
   if (!threeValidHandles(env, r, a, b)) return;
   Unique_BN_CTX ctx(BN_CTX_new());
-  BN_gcd(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
-  throwExceptionIfNecessary(env);
+  if (!BN_gcd(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get())) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_mul(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
   if (!threeValidHandles(env, r, a, b)) return;
   Unique_BN_CTX ctx(BN_CTX_new());
-  BN_mul(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
-  throwExceptionIfNecessary(env);
+  if (!BN_mul(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get())) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p) {
   if (!threeValidHandles(env, r, a, p)) return;
   Unique_BN_CTX ctx(BN_CTX_new());
-  BN_exp(toBigNum(r), toBigNum(a), toBigNum(p), ctx.get());
-  throwExceptionIfNecessary(env);
+  if (!BN_exp(toBigNum(r), toBigNum(a), toBigNum(p), ctx.get())) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_div(JNIEnv* env, jclass, jlong dv, jlong rem, jlong m, jlong d) {
   if (!fourValidHandles(env, (rem ? rem : dv), (dv ? dv : rem), m, d)) return;
   Unique_BN_CTX ctx(BN_CTX_new());
-  BN_div(toBigNum(dv), toBigNum(rem), toBigNum(m), toBigNum(d), ctx.get());
-  throwExceptionIfNecessary(env);
+  if (!BN_div(toBigNum(dv), toBigNum(rem), toBigNum(m), toBigNum(d), ctx.get())) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_nnmod(JNIEnv* env, jclass, jlong r, jlong a, jlong m) {
   if (!threeValidHandles(env, r, a, m)) return;
   Unique_BN_CTX ctx(BN_CTX_new());
-  BN_nnmod(toBigNum(r), toBigNum(a), toBigNum(m), ctx.get());
-  throwExceptionIfNecessary(env);
+  if (!BN_nnmod(toBigNum(r), toBigNum(a), toBigNum(m), ctx.get())) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_mod_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p, jlong m) {
   if (!fourValidHandles(env, r, a, p, m)) return;
   Unique_BN_CTX ctx(BN_CTX_new());
-  BN_mod_exp(toBigNum(r), toBigNum(a), toBigNum(p), toBigNum(m), ctx.get());
-  throwExceptionIfNecessary(env);
+  if (!BN_mod_exp(toBigNum(r), toBigNum(a), toBigNum(p), toBigNum(m), ctx.get())) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_mod_inverse(JNIEnv* env, jclass, jlong ret, jlong a, jlong n) {
   if (!threeValidHandles(env, ret, a, n)) return;
   Unique_BN_CTX ctx(BN_CTX_new());
-  BN_mod_inverse(toBigNum(ret), toBigNum(a), toBigNum(n), ctx.get());
-  throwExceptionIfNecessary(env);
+  if (!BN_mod_inverse(toBigNum(ret), toBigNum(a), toBigNum(n), ctx.get())) {
+    throwException(env);
+  }
 }
 
 static void NativeBN_BN_generate_prime_ex(JNIEnv* env, jclass, jlong ret, int bits,
-                                          jboolean safe, jlong add, jlong rem, jlong cb) {
+                                          jboolean safe, jlong add, jlong rem) {
   if (!oneValidHandle(env, ret)) return;
-  BN_generate_prime_ex(toBigNum(ret), bits, safe, toBigNum(add), toBigNum(rem),
-                       reinterpret_cast<BN_GENCB*>(cb));
-  throwExceptionIfNecessary(env);
+  if (!BN_generate_prime_ex(toBigNum(ret), bits, safe, toBigNum(add), toBigNum(rem),
+                            NULL)) {
+    throwException(env);
+  }
 }
 
-static jboolean NativeBN_BN_is_prime_ex(JNIEnv* env, jclass, jlong p, int nchecks, jlong cb) {
-  if (!oneValidHandle(env, p)) return JNI_FALSE;
+static jboolean NativeBN_BN_primality_test(JNIEnv* env, jclass, jlong candidate, int checks,
+                                           jboolean do_trial_decryption) {
+  if (!oneValidHandle(env, candidate)) return JNI_FALSE;
   Unique_BN_CTX ctx(BN_CTX_new());
-  return BN_is_prime_ex(toBigNum(p), nchecks, ctx.get(), reinterpret_cast<BN_GENCB*>(cb));
+  int is_probably_prime;
+  if (!BN_primality_test(&is_probably_prime, toBigNum(candidate), checks, ctx.get(),
+                         do_trial_decryption, NULL)) {
+    throwException(env);
+    return JNI_FALSE;
+  }
+  return is_probably_prime ? JNI_TRUE : JNI_FALSE;
 }
 
 static JNINativeMethod gMethods[] = {
@@ -593,10 +643,10 @@
    NATIVE_METHOD(NativeBN, BN_exp, "(JJJ)V"),
    NATIVE_METHOD(NativeBN, BN_free, "(J)V"),
    NATIVE_METHOD(NativeBN, BN_gcd, "(JJJ)V"),
-   NATIVE_METHOD(NativeBN, BN_generate_prime_ex, "(JIZJJJ)V"),
+   NATIVE_METHOD(NativeBN, BN_generate_prime_ex, "(JIZJJ)V"),
    NATIVE_METHOD(NativeBN, BN_hex2bn, "(JLjava/lang/String;)I"),
    NATIVE_METHOD(NativeBN, BN_is_bit_set, "(JI)Z"),
-   NATIVE_METHOD(NativeBN, BN_is_prime_ex, "(JIJ)Z"),
+   NATIVE_METHOD(NativeBN, BN_primality_test, "(JIZ)Z"),
    NATIVE_METHOD(NativeBN, BN_mod_exp, "(JJJJ)V"),
    NATIVE_METHOD(NativeBN, BN_mod_inverse, "(JJJ)V"),
    NATIVE_METHOD(NativeBN, BN_mod_word, "(JI)I"),
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 504a199..cacf62e 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -24,7 +24,6 @@
 #include "JniException.h"
 #include "NetworkUtilities.h"
 #include "Portability.h"
-#include "readlink.h"
 #include "ScopedBytes.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
@@ -61,6 +60,8 @@
 #include <unistd.h>
 #include <memory>
 
+#include <android-base/file.h>
+
 #ifndef __unused
 #define __unused __attribute__((__unused__))
 #endif
@@ -1639,7 +1640,7 @@
     }
 
     std::string result;
-    if (!readlink(path.c_str(), result)) {
+    if (!android::base::Readlink(path.c_str(), &result)) {
         throwErrnoException(env, "readlink");
         return NULL;
     }
diff --git a/luni/src/main/native/readlink.cpp b/luni/src/main/native/readlink.cpp
deleted file mode 100644
index 555d515..0000000
--- a/luni/src/main/native/readlink.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#include "LocalArray.h"
-#include "readlink.h"
-
-#include <string>
-#include <unistd.h>
-
-bool readlink(const char* path, std::string& result) {
-    // We can't know how big a buffer readlink(2) will need, so we need to
-    // loop until it says "that fit".
-    size_t bufSize = 512;
-    while (true) {
-        LocalArray<512> buf(bufSize);
-        ssize_t len = readlink(path, &buf[0], buf.size());
-        if (len == -1) {
-            // An error occurred.
-            return false;
-        }
-        if (static_cast<size_t>(len) < buf.size()) {
-            // The buffer was big enough.
-            result.assign(&buf[0], len);
-            return true;
-        }
-        // Try again with a bigger buffer.
-        bufSize *= 2;
-    }
-}
diff --git a/luni/src/main/native/readlink.h b/luni/src/main/native/readlink.h
deleted file mode 100644
index 14031dc..0000000
--- a/luni/src/main/native/readlink.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#include <string>
-
-/**
- * Fills 'result' with the contents of the symbolic link 'path'. Sets errno and returns false on
- * failure, returns true on success. The contents of 'result' on failure are undefined. Possible
- * errors are those defined for readlink(2), except that this function takes care of sizing the
- * buffer appropriately.
- */
-bool readlink(const char* path, std::string& result);
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index fbba3b6..803d818 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -11,7 +11,6 @@
     Register.cpp \
     ZipUtilities.cpp \
     android_system_OsConstants.cpp \
-    canonicalize_path.cpp \
     cbigint.cpp \
     java_lang_StringToReal.cpp \
     java_lang_invoke_MethodHandle.cpp \
@@ -26,7 +25,6 @@
     libcore_io_Posix.cpp \
     libcore_util_NativeAllocationRegistry.cpp \
     org_apache_harmony_xml_ExpatParser.cpp \
-    readlink.cpp \
     sun_misc_Unsafe.cpp \
     valueOf.cpp \
 
diff --git a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
index 0e0ee8d..36fde22 100644
--- a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
+++ b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
@@ -76,6 +76,7 @@
                 assertTrue(file.delete());
             }
         }
+        assertTrue(dir.delete());
     }
 
     /**
diff --git a/luni/src/test/java/dalvik/system/InMemoryDexClassLoaderTest.java b/luni/src/test/java/dalvik/system/InMemoryDexClassLoaderTest.java
new file mode 100644
index 0000000..c164d3b
--- /dev/null
+++ b/luni/src/test/java/dalvik/system/InMemoryDexClassLoaderTest.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2016 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.system;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import libcore.io.Streams;
+import junit.framework.TestCase;
+
+/**
+ * Tests for the class {@link InMemoryDexClassLoader}.
+ */
+public class InMemoryDexClassLoaderTest extends TestCase {
+    private static final String PACKAGE_PATH = "dalvik/system/";
+
+    private File srcDir;
+    private File dex1;
+    private File dex2;
+
+    protected void setUp() throws Exception {
+        srcDir = File.createTempFile("src", "");
+        assertTrue(srcDir.delete());
+        assertTrue(srcDir.mkdirs());
+
+        dex1 = new File(srcDir, "loading-test.dex");
+        dex2 = new File(srcDir, "loading-test2.dex");
+
+        copyResource("loading-test.dex", dex1);
+        copyResource("loading-test2.dex", dex2);
+    }
+
+    protected void tearDown() {
+        cleanUpDir(srcDir);
+    }
+
+    private static void cleanUpDir(File dir) {
+        if (!dir.isDirectory()) {
+            return;
+        }
+        File[] files = dir.listFiles();
+        for (File file : files) {
+            if (file.isDirectory()) {
+                cleanUpDir(file);
+            } else {
+                assertTrue(file.delete());
+            }
+        }
+        assertTrue(dir.delete());
+    }
+
+    /**
+     * Copy a resource in the package directory to the indicated
+     * target file.
+     */
+    private static void copyResource(String resourceName,
+            File destination) throws IOException {
+        ClassLoader loader = InMemoryDexClassLoaderTest.class.getClassLoader();
+        InputStream in = loader.getResourceAsStream(PACKAGE_PATH + resourceName);
+        if (in == null) {
+            throw new IllegalStateException("Resource not found: " + PACKAGE_PATH + resourceName);
+        }
+        try (FileOutputStream out = new FileOutputStream(destination)) {
+            Streams.copy(in, out);
+        } finally {
+            in.close();
+        }
+    }
+
+    private static ByteBuffer ReadFileToByteBufferDirect(File file) throws IOException {
+        try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocateDirect((int)file.length());
+            int done = 0;
+            while (done != file.length()) {
+                done += raf.getChannel().read(buffer);
+            }
+            buffer.rewind();
+            return buffer;
+        }
+    }
+
+    private static ByteBuffer ReadFileToByteBufferIndirect(File file) throws IOException {
+        ByteBuffer direct = ReadFileToByteBufferDirect(file);
+        byte[] array = new byte[direct.limit()];
+        direct.get(array);
+        return ByteBuffer.wrap(array);
+    }
+
+    /**
+     * Helper to construct a InMemoryDexClassLoader instance to test.
+     *
+     * Creates InMemoryDexClassLoader from ByteBuffer instances that are
+     * direct allocated.
+     *
+     * @param files The .dex files to use for the class path.
+     */
+    private static ClassLoader createLoaderDirect(File... files) throws IOException {
+        assertNotNull(files);
+        assertTrue(files.length > 0);
+        ClassLoader result = ClassLoader.getSystemClassLoader();
+        for (int i = 0; i < files.length; ++i) {
+            ByteBuffer buffer = ReadFileToByteBufferDirect(files[i]);
+            result = new InMemoryDexClassLoader(buffer, result);
+        }
+        return result;
+    }
+
+    /**
+     * Helper to construct a InMemoryDexClassLoader instance to test.
+     *
+     * Creates InMemoryDexClassLoader from ByteBuffer instances that are
+     * heap allocated.
+     *
+     * @param files The .dex files to use for the class path.
+     */
+    private static ClassLoader createLoaderIndirect(File... files) throws IOException {
+        assertNotNull(files);
+        assertTrue(files.length > 0);
+        ClassLoader result = ClassLoader.getSystemClassLoader();
+        for (int i = 0; i < files.length; ++i) {
+            ByteBuffer buffer = ReadFileToByteBufferIndirect(files[i]);
+            result = new InMemoryDexClassLoader(buffer, result);
+        }
+        return result;
+    }
+
+    /**
+     * Helper to construct a new InMemoryDexClassLoader via direct
+     * ByteBuffer instances.
+     *
+     * @param className The name of the class of the method to call.
+     * @param methodName The name of the method to call.
+     * @param files The .dex or .jar files to use for the class path.
+     */
+    private Object createLoaderDirectAndCallMethod(
+            String className, String methodName, File... files)
+            throws IOException, ReflectiveOperationException {
+        ClassLoader cl = createLoaderDirect(files);
+        Class c = cl.loadClass(className);
+        Method m = c.getMethod(methodName, (Class[]) null);
+        assertNotNull(m);
+        return m.invoke(null, (Object[]) null);
+    }
+
+    /**
+     * Helper to construct a new InMemoryDexClassLoader via indirect
+     * ByteBuffer instances.
+     *
+     * @param className The name of the class of the method to call.
+     * @param methodName The name of the method to call.
+     * @param files The .dex or .jar files to use for the class path.
+     */
+    private Object createLoaderIndirectAndCallMethod(
+            String className, String methodName, File... files)
+            throws IOException, ReflectiveOperationException {
+        ClassLoader cl = createLoaderIndirect(files);
+        Class c = cl.loadClass(className);
+        Method m = c.getMethod(methodName, (Class[]) null);
+        assertNotNull(m);
+        return m.invoke(null, (Object[]) null);
+    }
+
+    // ONE_DEX with direct ByteBuffer.
+
+    public void test_oneDexDirect_simpleUse() throws Exception {
+        String result = (String) createLoaderDirectAndCallMethod("test.Test1", "test", dex1);
+        assertSame("blort", result);
+    }
+
+    public void test_oneDexDirect_constructor() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_constructor", dex1);
+    }
+
+    public void test_oneDexDirect_callStaticMethod() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1);
+    }
+
+    public void test_oneDexDirect_getStaticVariable() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1);
+    }
+
+    public void test_oneDexDirect_callInstanceMethod() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1);
+    }
+
+    public void test_oneDexDirect_getInstanceVariable() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1);
+    }
+
+    // ONE_DEX with non-direct ByteBuffer.
+
+    public void test_oneDexIndirect_simpleUse() throws Exception {
+        String result = (String) createLoaderIndirectAndCallMethod("test.Test1", "test", dex1);
+        assertSame("blort", result);
+    }
+
+    public void test_oneDexIndirect_constructor() throws Exception {
+        createLoaderIndirectAndCallMethod("test.TestMethods", "test_constructor", dex1);
+    }
+
+    public void test_oneDexIndirect_callStaticMethod() throws Exception {
+        createLoaderIndirectAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1);
+    }
+
+    public void test_oneDexIndirect_getStaticVariable() throws Exception {
+        createLoaderIndirectAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1);
+    }
+
+    public void test_oneDexIndirect_callInstanceMethod() throws Exception {
+        createLoaderIndirectAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1);
+    }
+
+    public void test_oneDexIndirect_getInstanceVariable() throws Exception {
+        createLoaderIndirectAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1);
+    }
+
+    // TWO_DEX with direct ByteBuffer
+
+    public void test_twoDexDirect_simpleUse() throws Exception {
+        String result = (String) createLoaderDirectAndCallMethod("test.Test1", "test", dex1, dex2);
+        assertSame("blort", result);
+    }
+
+    public void test_twoDexDirect_constructor() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_constructor", dex1, dex2);
+    }
+
+    public void test_twoDexDirect_callStaticMethod() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1, dex2);
+    }
+
+    public void test_twoDexDirect_getStaticVariable() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1, dex2);
+    }
+
+    public void test_twoDexDirect_callInstanceMethod() throws Exception {
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1, dex2);
+    }
+
+    public void test_twoDexDirect_getInstanceVariable() throws Exception {
+        createLoaderDirectAndCallMethod(
+            "test.TestMethods", "test_getInstanceVariable", dex1, dex2);
+    }
+
+    public void test_twoDexDirect_target2_static_method() throws Exception {
+        String result =
+                (String) createLoaderDirectAndCallMethod("test2.Target2", "frotz", dex1, dex2);
+        assertSame("frotz", result);
+    }
+
+    public void test_twoDexDirect_diff_constructor() throws Exception {
+        // NB Ordering dex2 then dex1 as classloader's are nested and
+        // each only supports a single DEX image. The
+        // test.TestMethods.test_diff* methods depend on dex2 hence
+        // ordering.
+        createLoaderDirectAndCallMethod("test.TestMethods", "test_diff_constructor", dex2, dex1);
+    }
+
+    public void test_twoDexDirect_diff_callStaticMethod() throws Exception {
+        // NB See comment in test_twoDexDirect_diff_constructor.
+        createLoaderDirectAndCallMethod(
+            "test.TestMethods", "test_diff_callStaticMethod", dex2, dex1);
+    }
+
+    public void test_twoDexDirect_diff_getStaticVariable() throws Exception {
+        // NB See comment in test_twoDexDirect_diff_constructor.
+        createLoaderDirectAndCallMethod(
+            "test.TestMethods", "test_diff_getStaticVariable", dex2, dex1);
+    }
+
+    public void test_twoDexDirect_diff_callInstanceMethod() throws Exception {
+        // NB See comment in test_twoDexDirect_diff_constructor.
+        createLoaderDirectAndCallMethod(
+            "test.TestMethods", "test_diff_callInstanceMethod", dex2, dex1);
+    }
+
+    public void test_twoDexDirect_diff_getInstanceVariable() throws Exception {
+        // NB See comment in test_twoDexDirect_diff_constructor.
+        createLoaderDirectAndCallMethod(
+            "test.TestMethods", "test_diff_getInstanceVariable", dex2, dex1);
+    }
+}
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index f98a55d..0beafae 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -635,4 +635,15 @@
       }
     }
   }
+
+  public void test_readlink() throws Exception {
+    // ext2 and ext4 have PAGE_SIZE limits on symlink targets.
+    String xs = "";
+    for (int i = 0; i < (4096 - 1); ++i) xs += "x";
+
+    String path = System.getProperty("java.io.tmpdir") + "/symlink";
+    Libcore.os.symlink(xs, path);
+
+    assertEquals(xs, Libcore.os.readlink(path));
+  }
 }
diff --git a/luni/src/test/java/libcore/java/lang/ClassTest.java b/luni/src/test/java/libcore/java/lang/ClassTest.java
index 69b7dc3..ba1351f 100644
--- a/luni/src/test/java/libcore/java/lang/ClassTest.java
+++ b/luni/src/test/java/libcore/java/lang/ClassTest.java
@@ -23,6 +23,10 @@
 import junit.framework.TestCase;
 
 import dalvik.system.PathClassLoader;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.TreeMap;
+import java.util.function.Function;
 
 public class ClassTest extends TestCase {
 
@@ -120,4 +124,116 @@
           fail("Got exception");
       }
     }
+
+    public void test_toString() throws Exception {
+        final String outerClassName = getClass().getName();
+        final String packageProtectedClassName = PackageProtectedClass.class.getName();
+
+        assertToString("int", int.class);
+        assertToString("class [I", int[].class);
+        assertToString("class java.lang.Object", Object.class);
+        assertToString("class [Ljava.lang.Object;", Object[].class);
+        assertToString("class java.lang.Integer", Integer.class);
+        assertToString("interface java.util.function.Function", Function.class);
+        assertToString(
+                "class " + outerClassName + "$PublicStaticInnerClass",
+                PublicStaticInnerClass.class);
+        assertToString(
+                "class " + outerClassName + "$DefaultStaticInnerClass",
+                DefaultStaticInnerClass.class);
+        assertToString(
+                "interface " + outerClassName + "$PublicInnerInterface",
+                PublicInnerInterface.class);
+        assertToString(
+                "class " + packageProtectedClassName,
+                PackageProtectedClass.class);
+        assertToString(
+                "class " + outerClassName + "$PrivateStaticInnerClass",
+                PrivateStaticInnerClass.class);
+        assertToString("interface java.lang.annotation.Retention", Retention.class);
+        assertToString("class java.lang.annotation.RetentionPolicy", RetentionPolicy.class);
+        assertToString("class java.util.TreeMap", TreeMap.class);
+        assertToString(
+                "interface " + outerClassName + "$WildcardInterface",
+                WildcardInterface.class);
+    }
+
+    private static void assertToString(String expected, Class<?> clazz) {
+        assertEquals(expected, clazz.toString());
+    }
+
+    public void test_getTypeName() throws Exception {
+        final String outerClassName = getClass().getName();
+        final String packageProtectedClassName = PackageProtectedClass.class.getName();
+
+        assertGetTypeName("int", int.class);
+        assertGetTypeName("int[]", int[].class);
+        assertGetTypeName("java.lang.Object", Object.class);
+        assertGetTypeName("java.lang.Object[]", Object[].class);
+        assertGetTypeName("java.lang.Integer", Integer.class);
+        assertGetTypeName("java.util.function.Function", Function.class);
+        assertGetTypeName(outerClassName + "$PublicStaticInnerClass", PublicStaticInnerClass.class);
+        assertGetTypeName(
+                outerClassName + "$DefaultStaticInnerClass",
+                DefaultStaticInnerClass.class);
+        assertGetTypeName(outerClassName + "$PublicInnerInterface", PublicInnerInterface.class);
+        assertGetTypeName(packageProtectedClassName, PackageProtectedClass.class);
+        assertGetTypeName(
+                outerClassName + "$PrivateStaticInnerClass",
+                PrivateStaticInnerClass.class);
+        assertGetTypeName("java.lang.annotation.Retention", Retention.class);
+        assertGetTypeName("java.lang.annotation.RetentionPolicy", RetentionPolicy.class);
+        assertGetTypeName("java.util.TreeMap", TreeMap.class);
+        assertGetTypeName(outerClassName + "$WildcardInterface", WildcardInterface.class);
+    }
+
+    private void assertGetTypeName(String expected, Class<?> clazz) {
+        assertEquals(expected, clazz.getTypeName());
+    }
+
+    public void test_toGenericString() throws Exception {
+        final String outerClassName = getClass().getName();
+        final String packageProtectedClassName = PackageProtectedClass.class.getName();
+
+        assertToGenericString("int", int.class);
+        assertToGenericString("public abstract final class [I", int[].class);
+        assertToGenericString("public class java.lang.Object", Object.class);
+        assertToGenericString("public abstract final class [Ljava.lang.Object;", Object[].class);
+        assertToGenericString("public final class java.lang.Integer", Integer.class);
+        assertToGenericString(
+                "public abstract interface java.util.function.Function<T,R>",
+                Function.class);
+        assertToGenericString("public static class " + outerClassName + "$PublicStaticInnerClass",
+                PublicStaticInnerClass.class);
+        assertToGenericString("static class " + outerClassName + "$DefaultStaticInnerClass",
+                DefaultStaticInnerClass.class);
+        assertToGenericString(
+                "public abstract static interface " + outerClassName + "$PublicInnerInterface",
+                PublicInnerInterface.class);
+        assertToGenericString("class " + packageProtectedClassName, PackageProtectedClass.class);
+        assertToGenericString(
+                "private static class " + outerClassName + "$PrivateStaticInnerClass",
+                PrivateStaticInnerClass.class);
+        assertToGenericString(
+                "public abstract @interface java.lang.annotation.Retention", Retention.class);
+        assertToGenericString("public final enum java.lang.annotation.RetentionPolicy",
+                RetentionPolicy.class);
+        assertToGenericString("public class java.util.TreeMap<K,V>", TreeMap.class);
+        assertToGenericString(
+                "abstract static interface " + outerClassName + "$WildcardInterface<T,U>",
+                WildcardInterface.class);
+    }
+
+    private static void assertToGenericString(String expected, Class<?> clazz) {
+        assertEquals(expected, clazz.toGenericString());
+    }
+
+    private static class PrivateStaticInnerClass {}
+    static class DefaultStaticInnerClass {}
+    public static class PublicStaticInnerClass {}
+    public interface PublicInnerInterface {}
+    interface WildcardInterface<
+            T extends Number,
+            U extends Function<? extends Number, ? super Number>>
+            extends Comparable<T> {}
 }
diff --git a/luni/src/test/java/libcore/java/lang/OldThreadTest.java b/luni/src/test/java/libcore/java/lang/OldThreadTest.java
index 03031ac..9632680 100644
--- a/luni/src/test/java/libcore/java/lang/OldThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldThreadTest.java
@@ -193,7 +193,7 @@
         st = new Thread() {
             public void run() {
                 try {
-                    sleep(10000);
+                    sleep(1000);
                 } catch(InterruptedException ie) {
                     wasInterrupted = true;
                 }
@@ -203,7 +203,7 @@
         st.start();
 
         try {
-            Thread.sleep(5000);
+            Thread.sleep(500);
         } catch(InterruptedException e) {
             fail("Unexpected InterruptedException was thrown");
         }
@@ -211,7 +211,7 @@
         st.interrupt();
 
         try {
-            Thread.sleep(5000);
+            Thread.sleep(500);
         } catch(InterruptedException e) {
             fail("Unexpected InterruptedException was thrown");
         }
@@ -240,7 +240,7 @@
         st = new Thread() {
             public void run() {
                 try {
-                    sleep(10000, 99999);
+                    sleep(1000, 9999);
                 } catch(InterruptedException ie) {
                     wasInterrupted = true;
                 }
@@ -250,7 +250,7 @@
         st.start();
 
         try {
-            Thread.sleep(5000, 99999);
+            Thread.sleep(500, 9999);
         } catch(InterruptedException e) {
             fail("Unexpected InterruptedException was thrown");
         }
@@ -258,7 +258,7 @@
         st.interrupt();
 
         try {
-            Thread.sleep(5000);
+            Thread.sleep(500);
         } catch(InterruptedException e) {
             fail("Unexpected InterruptedException was thrown");
         }
@@ -275,7 +275,7 @@
         }
         Counter countersYeld = new Counter(true);
         try {
-            Thread.sleep(11000);
+            Thread.sleep(1100);
         } catch(InterruptedException ie) {}
 
         for(Counter c:countersNotYeld) {
@@ -293,7 +293,7 @@
         }
 
         public void run() {
-            for(int i = 0; i < 10000; i++) {
+            for(int i = 0; i < 1000; i++) {
                 if(isDoYield)
                     yield();
                 counter ++;
diff --git a/luni/src/test/java/libcore/java/lang/PackageProtectedClass.java b/luni/src/test/java/libcore/java/lang/PackageProtectedClass.java
new file mode 100644
index 0000000..95a253c
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/PackageProtectedClass.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.lang;
+
+/**
+ * Used by {@link ClassTest}.
+ */
+class PackageProtectedClass {
+}
diff --git a/luni/src/test/java/libcore/java/lang/SystemTest.java b/luni/src/test/java/libcore/java/lang/SystemTest.java
index f16c380..2dc9d49 100644
--- a/luni/src/test/java/libcore/java/lang/SystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/SystemTest.java
@@ -126,8 +126,8 @@
     public void testArrayCopyConcurrentModification() {
         final AtomicBoolean done = new AtomicBoolean();
 
-        final Object[] source = new Object[1024 * 1024];
-        String[] target = new String[1024 * 1024];
+        final Object[] source = new Object[512 * 1024];
+        String[] target = new String[512 * 1024];
 
         new Thread() {
             @Override public void run() {
@@ -140,7 +140,7 @@
             }
         }.start();
 
-        for (int i = 0; i < 8192; i++) {
+        for (int i = 0; i < 2048; i++) {
             try {
                 System.arraycopy(source, 0, target, 0, source.length);
                 assertNull(target[source.length - 1]); // make sure the wrong type didn't sneak in
diff --git a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
index d71b5b0..55e70033 100644
--- a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
+++ b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
@@ -102,11 +102,9 @@
      * to finalize. Check that objects near that limit are okay.
      */
     public void testWatchdogDoesNotFailForObjectsThatAreNearTheDeadline() throws Exception {
-        CountDownLatch latch = new CountDownLatch(5);
+        CountDownLatch latch = new CountDownLatch(3);
         createSlowFinalizer(   1, latch);
         createSlowFinalizer(1000, latch);
-        createSlowFinalizer(2000, latch);
-        createSlowFinalizer(4000, latch);
         createSlowFinalizer(8000, latch);
         FinalizationTester.induceFinalization();
         latch.await();
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java b/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
index 0505f2f..2d395c5 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/ModifierTest.java
@@ -39,6 +39,10 @@
         assertEquals(0xd3f, Modifier.methodModifiers());
     }
 
+    public void test_parameterModifiers() {
+        assertEquals(0x10, Modifier.parameterModifiers());
+    }
+
     public void test_isAbstractI() {
         assertTrue(Modifier.isAbstract(Modifier.ABSTRACT));
         assertTrue(!Modifier.isAbstract(-1 & ~Modifier.ABSTRACT));
diff --git a/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java b/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java
index a251963..b21689e 100644
--- a/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java
+++ b/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java
@@ -73,7 +73,7 @@
      * Test for b/27763633.
      */
     public void testConcurrentServerSocketCloseReliablyThrows() {
-        int numIterations = 200;
+        int numIterations = 100;
         for (int i = 0; i < numIterations; i++) {
             checkConnectIterationAndCloseSocket("Iteration " + (i+1) + " of " + numIterations,
                     /* msecPerIteration */ 50);
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
index a45002a..1e7cefe 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
@@ -69,10 +69,12 @@
     private static final InetAddress UNICAST_IPv6_1 = lookup("2001:db8::1");
     private static final InetAddress UNICAST_IPv6_2 = lookup("2001:db8::2");
 
-    private NetworkInterface networkInterface1;
-    private NetworkInterface IPV6networkInterface1;
+    private NetworkInterface ipv4NetworkInterface;
+    private NetworkInterface ipv6NetworkInterface;
     private NetworkInterface loopbackInterface;
 
+    private boolean supportsMulticast;
+
     @Override
     protected void setUp() throws Exception {
         // The loopback interface isn't actually useful for sending/receiving multicast messages
@@ -84,39 +86,39 @@
 
         Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
 
-        // only consider interfaces that have addresses associated with them.
-        // Otherwise tests don't work so well
-        if (interfaces != null) {
-            boolean atLeastOneInterface = false;
-            while (interfaces.hasMoreElements() && (atLeastOneInterface == false)) {
-                networkInterface1 = interfaces.nextElement();
-                if (willWorkForMulticast(networkInterface1)) {
-                    atLeastOneInterface = true;
-                }
-            }
+        // Determine if the device is marked to support multicast or not. If this propery is not
+        // set we assume the device has an interface capable of supporting multicast.
+        supportsMulticast = Boolean.parseBoolean(
+                System.getProperty("android.cts.device.multicast", "true"));
+        if (!supportsMulticast) {
+            return;
+        }
 
-            assertTrue("Test environment must have at least one environment capable of multicast",
-                    atLeastOneInterface);
-
-            // Find the first multicast-compatible interface that supports IPV6 if one exists
-            interfaces = NetworkInterface.getNetworkInterfaces();
-
-            boolean found = false;
-            while (interfaces.hasMoreElements() && !found) {
-                NetworkInterface nextInterface = interfaces.nextElement();
-                if (willWorkForMulticast(nextInterface)) {
-                    Enumeration<InetAddress> addresses = nextInterface.getInetAddresses();
-                    while (addresses.hasMoreElements()) {
-                        final InetAddress nextAddress = addresses.nextElement();
-                        if (nextAddress instanceof Inet6Address) {
-                            IPV6networkInterface1 = nextInterface;
-                            found = true;
-                            break;
-                        }
+        while (interfaces.hasMoreElements()
+                && (ipv4NetworkInterface == null || ipv6NetworkInterface == null)) {
+            NetworkInterface nextInterface = interfaces.nextElement();
+            if (willWorkForMulticast(nextInterface)) {
+                Enumeration<InetAddress> addresses = nextInterface.getInetAddresses();
+                while (addresses.hasMoreElements()) {
+                    final InetAddress nextAddress = addresses.nextElement();
+                    if (nextAddress instanceof Inet6Address && ipv6NetworkInterface == null) {
+                        ipv6NetworkInterface = nextInterface;
+                    } else if (nextAddress instanceof Inet4Address
+                            && ipv4NetworkInterface == null) {
+                        ipv4NetworkInterface = nextInterface;
                     }
                 }
             }
         }
+
+        if (ipv4NetworkInterface == null) {
+            fail("Test environment must have at least one network interface capable of IPv4"
+                    + " multicast");
+        }
+        if (ipv6NetworkInterface == null) {
+            fail("Test environment must have at least one network interface capable of IPv6"
+                    + " multicast");
+        }
     }
 
     public void test_open() throws IOException {
@@ -147,19 +149,25 @@
     }
 
     public void test_joinAnySource_afterClose() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         dc.close();
         try {
-            dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+            dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
             fail();
         } catch (ClosedChannelException expected) {
         }
     }
 
     public void test_joinAnySource_nullGroupAddress() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(null, networkInterface1);
+            dc.join(null, ipv4NetworkInterface);
             fail();
         } catch (NullPointerException expected) {
         }
@@ -167,6 +175,9 @@
     }
 
     public void test_joinAnySource_nullNetworkInterface() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
             dc.join(GOOD_MULTICAST_IPv4, null);
@@ -177,9 +188,12 @@
     }
 
     public void test_joinAnySource_nonMulticastGroupAddress_IPv4() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(UNICAST_IPv4_1, networkInterface1);
+            dc.join(UNICAST_IPv4_1, ipv4NetworkInterface);
             fail();
         } catch (IllegalArgumentException expected) {
         }
@@ -187,9 +201,12 @@
     }
 
     public void test_joinAnySource_nonMulticastGroupAddress_IPv6() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(UNICAST_IPv6_1, networkInterface1);
+            dc.join(UNICAST_IPv6_1, ipv6NetworkInterface);
             fail();
         } catch (IllegalArgumentException expected) {
         }
@@ -197,18 +214,22 @@
     }
 
     public void test_joinAnySource_IPv4() throws Exception {
-        test_joinAnySource(GOOD_MULTICAST_IPv4, BAD_MULTICAST_IPv4);
+        test_joinAnySource(GOOD_MULTICAST_IPv4, BAD_MULTICAST_IPv4, ipv4NetworkInterface);
     }
 
     public void test_joinAnySource_IPv6() throws Exception {
-        test_joinAnySource(GOOD_MULTICAST_IPv6, BAD_MULTICAST_IPv6);
+        test_joinAnySource(GOOD_MULTICAST_IPv6, BAD_MULTICAST_IPv6, ipv6NetworkInterface);
     }
 
-    private void test_joinAnySource(InetAddress group, InetAddress group2) throws Exception {
-        // Set up a receiver join the group on networkInterface1
+    private void test_joinAnySource(InetAddress group, InetAddress group2,
+            NetworkInterface networkInterface) throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
+        // Set up a receiver join the group on ipv4NetworkInterface
         DatagramChannel receiverChannel = createReceiverChannel();
         InetSocketAddress localAddress = (InetSocketAddress) receiverChannel.getLocalAddress();
-        receiverChannel.join(group, networkInterface1);
+        receiverChannel.join(group, networkInterface);
 
         String msg = "Hello World";
         sendMulticastMessage(group, localAddress.getPort(), msg);
@@ -230,11 +251,14 @@
     }
 
     public void test_joinAnySource_processLimit() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         for (byte i = 1; i <= 25; i++) {
             InetAddress groupAddress = Inet4Address.getByName("239.255.0." + i);
             try {
-                dc.join(groupAddress, networkInterface1);
+                dc.join(groupAddress, ipv4NetworkInterface);
             } catch (SocketException e) {
                 // There is a limit, that's ok according to the RI docs. For this test a lower bound of 20
                 // is used, which appears to be the default linux limit.
@@ -248,8 +272,11 @@
     }
 
     public void test_joinAnySource_blockLimit() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey key = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey key = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         for (byte i = 1; i <= 15; i++) {
             InetAddress sourceAddress = Inet4Address.getByName("10.0.0." + i);
             try {
@@ -268,14 +295,20 @@
 
     /** Confirms that calling join() does not cause an implicit bind() to take place. */
     public void test_joinAnySource_doesNotCauseBind() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = DatagramChannel.open();
-        dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         assertNull(dc.getLocalAddress());
 
         dc.close();
     }
 
     public void test_joinAnySource_networkInterfaces() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         // Check that we can join on specific interfaces and that we only receive if data is
         // received on that interface. This test is only really useful on devices with multiple
         // non-loopback interfaces.
@@ -309,11 +342,11 @@
                 InetAddress firstAddress = addresses.nextElement();
                 if (firstAddress instanceof Inet4Address) {
                     group = GOOD_MULTICAST_IPv4;
-                    sendingInterface = networkInterface1;
+                    sendingInterface = ipv4NetworkInterface;
                 } else {
                     // if this interface only seems to support IPV6 addresses
                     group = GOOD_MULTICAST_IPv6;
-                    sendingInterface = IPV6networkInterface1;
+                    sendingInterface = ipv6NetworkInterface;
                 }
             }
 
@@ -340,8 +373,11 @@
 
     /** Confirms that the scope of each membership is network interface-level. */
     public void test_join_canMixTypesOnDifferentInterfaces() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = DatagramChannel.open();
-        MembershipKey membershipKey1 = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey1 = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         MembershipKey membershipKey2 = dc.join(GOOD_MULTICAST_IPv4, loopbackInterface, UNICAST_IPv4_1);
         assertNotSame(membershipKey1, membershipKey2);
 
@@ -358,43 +394,51 @@
 
     public void test_joinAnySource_multiple_joins_IPv4()
             throws Exception {
-        test_joinAnySource_multiple_joins(GOOD_MULTICAST_IPv4);
+        test_joinAnySource_multiple_joins(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
     }
 
     public void test_joinAnySource_multiple_joins_IPv6()
             throws Exception {
-        test_joinAnySource_multiple_joins(GOOD_MULTICAST_IPv6);
+        test_joinAnySource_multiple_joins(GOOD_MULTICAST_IPv6, ipv6NetworkInterface);
     }
 
-    private void test_joinAnySource_multiple_joins(InetAddress group) throws Exception {
+    private void test_joinAnySource_multiple_joins(InetAddress group,
+            NetworkInterface networkInterface) throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
 
-        MembershipKey membershipKey1 = dc.join(group, networkInterface1);
+        MembershipKey membershipKey1 = dc.join(group, networkInterface);
 
         MembershipKey membershipKey2 = dc.join(group, loopbackInterface);
         assertFalse(membershipKey1.equals(membershipKey2));
 
-        MembershipKey membershipKey1_2 = dc.join(group, networkInterface1);
+        MembershipKey membershipKey1_2 = dc.join(group, networkInterface);
         assertEquals(membershipKey1, membershipKey1_2);
 
         dc.close();
     }
 
     public void test_joinAnySource_multicastLoopOption_IPv4() throws Exception {
-        test_joinAnySource_multicastLoopOption(GOOD_MULTICAST_IPv4);
+        test_joinAnySource_multicastLoopOption(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
     }
 
     public void test_multicastLoopOption_IPv6() throws Exception {
-        test_joinAnySource_multicastLoopOption(GOOD_MULTICAST_IPv6);
+        test_joinAnySource_multicastLoopOption(GOOD_MULTICAST_IPv6, ipv6NetworkInterface);
     }
 
-    private void test_joinAnySource_multicastLoopOption(InetAddress group) throws Exception {
+    private void test_joinAnySource_multicastLoopOption(InetAddress group,
+            NetworkInterface networkInterface) throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         final String message = "Hello, world!";
 
         DatagramChannel dc = createReceiverChannel();
         dc.setOption(StandardSocketOptions.IP_MULTICAST_LOOP, true /* enable loop */);
         configureChannelForReceiving(dc);
-        dc.join(group, networkInterface1);
+        dc.join(group, networkInterface);
 
         InetSocketAddress localAddress = (InetSocketAddress) dc.getLocalAddress();
 
@@ -426,35 +470,43 @@
     }
 
     public void testMembershipKeyAccessors_IPv4() throws Exception {
-        testMembershipKeyAccessors(GOOD_MULTICAST_IPv4);
+        testMembershipKeyAccessors(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
     }
 
     public void testMembershipKeyAccessors_IPv6() throws Exception {
-        testMembershipKeyAccessors(GOOD_MULTICAST_IPv6);
+        testMembershipKeyAccessors(GOOD_MULTICAST_IPv6, ipv6NetworkInterface);
     }
 
-    private void testMembershipKeyAccessors(InetAddress group) throws Exception {
+    private void testMembershipKeyAccessors(InetAddress group,
+            NetworkInterface networkInterface) throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
 
-        MembershipKey key = dc.join(group, networkInterface1);
+        MembershipKey key = dc.join(group, networkInterface);
         assertSame(dc, key.channel());
         assertSame(group, key.group());
         assertTrue(key.isValid());
-        assertSame(networkInterface1, key.networkInterface());
+        assertSame(networkInterface, key.networkInterface());
         assertNull(key.sourceAddress());
     }
 
     public void test_dropAnySource_twice_IPv4() throws Exception {
-        test_dropAnySource_twice(GOOD_MULTICAST_IPv4);
+        test_dropAnySource_twice(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
     }
 
     public void test_dropAnySource_twice_IPv6() throws Exception {
-        test_dropAnySource_twice(GOOD_MULTICAST_IPv6);
+        test_dropAnySource_twice(GOOD_MULTICAST_IPv6, ipv6NetworkInterface);
     }
 
-    private void test_dropAnySource_twice(InetAddress group) throws Exception {
+    private void test_dropAnySource_twice(InetAddress group,
+            NetworkInterface networkInterface) throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(group, networkInterface1);
+        MembershipKey membershipKey = dc.join(group, networkInterface);
 
         assertTrue(membershipKey.isValid());
         membershipKey.drop();
@@ -467,8 +519,11 @@
     }
 
     public void test_close_invalidatesMembershipKey() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
 
         assertTrue(membershipKey.isValid());
 
@@ -478,8 +533,11 @@
     }
 
     public void test_block_null() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         try {
             membershipKey.block(null);
             fail();
@@ -490,8 +548,11 @@
     }
 
     public void test_block_mixedAddressTypes_IPv4() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         try {
             membershipKey.block(UNICAST_IPv6_1);
             fail();
@@ -502,8 +563,11 @@
     }
 
     public void test_block_mixedAddressTypes_IPv6() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv6, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv6, ipv6NetworkInterface);
         try {
             membershipKey.block(UNICAST_IPv4_1);
             fail();
@@ -514,8 +578,11 @@
     }
 
     public void test_block_cannotBlockWithSourceSpecificMembership() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1, UNICAST_IPv4_1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface, UNICAST_IPv4_1);
         try {
             membershipKey.block(UNICAST_IPv4_2);
             fail();
@@ -526,8 +593,11 @@
     }
 
     public void test_block_multipleBlocksIgnored() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         membershipKey.block(UNICAST_IPv4_1);
 
         MembershipKey membershipKey2 = membershipKey.block(UNICAST_IPv4_1);
@@ -537,8 +607,11 @@
     }
 
     public void test_block_wildcardAddress() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         try {
             membershipKey.block(WILDCARD_IPv4);
             fail();
@@ -549,8 +622,11 @@
     }
 
     public void test_unblock_multipleUnblocksFail() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
 
         try {
             membershipKey.unblock(UNICAST_IPv4_1);
@@ -573,8 +649,11 @@
     }
 
     public void test_unblock_null() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         membershipKey.block(UNICAST_IPv4_1);
 
         try {
@@ -590,8 +669,11 @@
     }
 
     public void test_unblock_mixedAddressTypes_IPv4() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface);
         try {
             membershipKey.unblock(UNICAST_IPv6_1);
             fail();
@@ -605,8 +687,11 @@
     }
 
     public void test_unblock_mixedAddressTypes_IPv6() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv6, networkInterface1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv6, ipv6NetworkInterface);
         try {
             membershipKey.unblock(UNICAST_IPv4_1);
             fail();
@@ -621,44 +706,51 @@
 
     /** Checks that block() works when the receiver is bound to the multicast group address */
     public void test_block_filtersAsExpected_groupBind_ipv4() throws Exception {
-        InetAddress ipv4LocalAddress = getLocalIpv4Address(networkInterface1);
+        InetAddress ipv4LocalAddress = getLocalIpv4Address(ipv4NetworkInterface);
         test_block_filtersAsExpected(
                 ipv4LocalAddress /* senderBindAddress */,
                 GOOD_MULTICAST_IPv4 /* receiverBindAddress */,
-                GOOD_MULTICAST_IPv4 /* groupAddress */);
+                GOOD_MULTICAST_IPv4 /* groupAddress */,
+                ipv4NetworkInterface);
     }
 
     /** Checks that block() works when the receiver is bound to the multicast group address */
     public void test_block_filtersAsExpected_groupBind_ipv6() throws Exception {
-        InetAddress ipv6LocalAddress = getLocalIpv6Address(IPV6networkInterface1);
+        InetAddress ipv6LocalAddress = getLocalIpv6Address(ipv6NetworkInterface);
         test_block_filtersAsExpected(
                 ipv6LocalAddress /* senderBindAddress */,
                 GOOD_MULTICAST_IPv6 /* receiverBindAddress */,
-                GOOD_MULTICAST_IPv6 /* groupAddress */);
+                GOOD_MULTICAST_IPv6 /* groupAddress */,
+                ipv6NetworkInterface);
     }
 
     /** Checks that block() works when the receiver is bound to the "any" address */
     public void test_block_filtersAsExpected_anyBind_ipv4() throws Exception {
-        InetAddress ipv4LocalAddress = getLocalIpv4Address(networkInterface1);
+        InetAddress ipv4LocalAddress = getLocalIpv4Address(ipv4NetworkInterface);
         test_block_filtersAsExpected(
                 ipv4LocalAddress /* senderBindAddress */,
                 WILDCARD_IPv4 /* receiverBindAddress */,
-                GOOD_MULTICAST_IPv4 /* groupAddress */);
+                GOOD_MULTICAST_IPv4 /* groupAddress */,
+                ipv4NetworkInterface);
     }
 
     /** Checks that block() works when the receiver is bound to the "any" address */
     public void test_block_filtersAsExpected_anyBind_ipv6() throws Exception {
-        InetAddress ipv6LocalAddress = getLocalIpv6Address(IPV6networkInterface1);
+        InetAddress ipv6LocalAddress = getLocalIpv6Address(ipv6NetworkInterface);
         test_block_filtersAsExpected(
                 ipv6LocalAddress /* senderBindAddress */,
                 WILDCARD_IPv6 /* receiverBindAddress */,
-                GOOD_MULTICAST_IPv6 /* groupAddress */);
+                GOOD_MULTICAST_IPv6 /* groupAddress */,
+                ipv6NetworkInterface);
     }
 
     private void test_block_filtersAsExpected(
-            InetAddress senderBindAddress, InetAddress receiverBindAddress, InetAddress groupAddress)
+            InetAddress senderBindAddress, InetAddress receiverBindAddress,
+            InetAddress groupAddress, NetworkInterface networkInterface)
             throws Exception {
-
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel sendingChannel = DatagramChannel.open();
         // In order to block a sender the sender's address must be known. The sendingChannel is
         // explicitly bound to a known, non-loopback address.
@@ -674,7 +766,7 @@
         InetSocketAddress groupSocketAddress =
                 new InetSocketAddress(groupAddress, localReceivingAddress.getPort());
         MembershipKey membershipKey =
-                receivingChannel.join(groupSocketAddress.getAddress(), networkInterface1);
+                receivingChannel.join(groupSocketAddress.getAddress(), networkInterface);
 
         ByteBuffer receiveBuffer = ByteBuffer.allocate(10);
 
@@ -711,9 +803,12 @@
     }
 
     public void test_joinSourceSpecific_nullGroupAddress() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(null, networkInterface1, UNICAST_IPv4_1);
+            dc.join(null, ipv4NetworkInterface, UNICAST_IPv4_1);
             fail();
         } catch (NullPointerException expected) {
         }
@@ -721,16 +816,22 @@
     }
 
     public void test_joinSourceSpecific_afterClose() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         dc.close();
         try {
-            dc.join(GOOD_MULTICAST_IPv4, networkInterface1, UNICAST_IPv4_1);
+            dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface, UNICAST_IPv4_1);
             fail();
         } catch (ClosedChannelException expected) {
         }
     }
 
     public void test_joinSourceSpecific_nullNetworkInterface() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
             dc.join(GOOD_MULTICAST_IPv4, null, UNICAST_IPv4_1);
@@ -741,9 +842,12 @@
     }
 
     public void test_joinSourceSpecific_nonMulticastGroupAddress_IPv4() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(UNICAST_IPv4_1, networkInterface1, UNICAST_IPv4_1);
+            dc.join(UNICAST_IPv4_1, ipv4NetworkInterface, UNICAST_IPv4_1);
             fail();
         } catch (IllegalArgumentException expected) {
         }
@@ -751,9 +855,12 @@
     }
 
     public void test_joinSourceSpecific_nonMulticastGroupAddress_IPv6() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(UNICAST_IPv6_1, IPV6networkInterface1, UNICAST_IPv6_1);
+            dc.join(UNICAST_IPv6_1, ipv6NetworkInterface, UNICAST_IPv6_1);
             fail();
         } catch (IllegalArgumentException expected) {
         }
@@ -761,9 +868,12 @@
     }
 
     public void test_joinSourceSpecific_nullSourceAddress_IPv4() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(GOOD_MULTICAST_IPv4, networkInterface1, null);
+            dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface, null);
             fail();
         } catch (NullPointerException expected) {
         }
@@ -771,9 +881,12 @@
     }
 
     public void test_joinSourceSpecific_nullSourceAddress_IPv6() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(GOOD_MULTICAST_IPv6, networkInterface1, null);
+            dc.join(GOOD_MULTICAST_IPv6, ipv6NetworkInterface, null);
             fail();
         } catch (NullPointerException expected) {
         }
@@ -781,14 +894,17 @@
     }
 
     public void test_joinSourceSpecific_mixedAddressTypes() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(GOOD_MULTICAST_IPv4, networkInterface1, UNICAST_IPv6_1);
+            dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface, UNICAST_IPv6_1);
             fail();
         } catch (IllegalArgumentException expected) {
         }
         try {
-            dc.join(GOOD_MULTICAST_IPv6, networkInterface1, UNICAST_IPv4_1);
+            dc.join(GOOD_MULTICAST_IPv6, ipv6NetworkInterface, UNICAST_IPv4_1);
             fail();
         } catch (IllegalArgumentException expected) {
         }
@@ -796,9 +912,12 @@
     }
 
     public void test_joinSourceSpecific_nonUnicastSourceAddress_IPv4() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(GOOD_MULTICAST_IPv4, networkInterface1, BAD_MULTICAST_IPv4);
+            dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface, BAD_MULTICAST_IPv4);
             fail();
         } catch (IllegalArgumentException expected) {
         }
@@ -806,9 +925,12 @@
     }
 
     public void test_joinSourceSpecific_nonUniicastSourceAddress_IPv6() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         try {
-            dc.join(GOOD_MULTICAST_IPv6, networkInterface1, BAD_MULTICAST_IPv6);
+            dc.join(GOOD_MULTICAST_IPv6, ipv6NetworkInterface, BAD_MULTICAST_IPv6);
             fail();
         } catch (IllegalArgumentException expected) {
         }
@@ -816,11 +938,14 @@
     }
 
     public void test_joinSourceSpecific_multipleSourceAddressLimit() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
         for (byte i = 1; i <= 20; i++) {
             InetAddress sourceAddress = Inet4Address.getByAddress(new byte[] { 10, 0, 0, i});
             try {
-                dc.join(GOOD_MULTICAST_IPv4, networkInterface1, sourceAddress);
+                dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface, sourceAddress);
             } catch (SocketException e) {
                 // There is a limit, that's ok according to the RI docs. For this test a lower bound of 10
                 // is used, which appears to be the default linux limit. See /proc/sys/net/ipv4/igmp_max_msf
@@ -837,12 +962,13 @@
      * address
      */
     public void test_joinSourceSpecific_null() throws Exception {
-        InetAddress ipv4LocalAddress = getLocalIpv4Address(networkInterface1);
+        InetAddress ipv4LocalAddress = getLocalIpv4Address(ipv4NetworkInterface);
         test_joinSourceSpecific(
                 ipv4LocalAddress /* senderBindAddress */,
                 GOOD_MULTICAST_IPv4 /* receiverBindAddress */,
                 GOOD_MULTICAST_IPv4 /* groupAddress */,
-                UNICAST_IPv4_1 /* badSenderAddress */);
+                UNICAST_IPv4_1 /* badSenderAddress */,
+                ipv4NetworkInterface);
     }
 
     /**
@@ -850,12 +976,13 @@
      * address
      */
     public void test_joinSourceSpecific_groupBind_ipv4() throws Exception {
-        InetAddress ipv4LocalAddress = getLocalIpv4Address(networkInterface1);
+        InetAddress ipv4LocalAddress = getLocalIpv4Address(ipv4NetworkInterface);
         test_joinSourceSpecific(
                 ipv4LocalAddress /* senderBindAddress */,
                 GOOD_MULTICAST_IPv4 /* receiverBindAddress */,
                 GOOD_MULTICAST_IPv4 /* groupAddress */,
-                UNICAST_IPv4_1 /* badSenderAddress */);
+                UNICAST_IPv4_1 /* badSenderAddress */,
+                ipv6NetworkInterface);
     }
 
     /**
@@ -863,32 +990,35 @@
      * address
      */
     public void test_joinSourceSpecific_groupBind_ipv6() throws Exception {
-        InetAddress ipv6LocalAddress = getLocalIpv6Address(IPV6networkInterface1);
+        InetAddress ipv6LocalAddress = getLocalIpv6Address(ipv6NetworkInterface);
         test_joinSourceSpecific(
                 ipv6LocalAddress /* senderBindAddress */,
                 GOOD_MULTICAST_IPv6 /* receiverBindAddress */,
                 GOOD_MULTICAST_IPv6 /* groupAddress */,
-                UNICAST_IPv6_1 /* badSenderAddress */);
+                UNICAST_IPv6_1 /* badSenderAddress */,
+                ipv6NetworkInterface);
     }
 
     /** Checks that a source-specific join() works when the receiver is bound to the "any" address */
     public void test_joinSourceSpecific_anyBind_ipv4() throws Exception {
-        InetAddress ipv4LocalAddress = getLocalIpv4Address(networkInterface1);
+        InetAddress ipv4LocalAddress = getLocalIpv4Address(ipv4NetworkInterface);
         test_joinSourceSpecific(
                 ipv4LocalAddress /* senderBindAddress */,
                 WILDCARD_IPv4 /* receiverBindAddress */,
                 GOOD_MULTICAST_IPv4 /* groupAddress */,
-                UNICAST_IPv4_1 /* badSenderAddress */);
+                UNICAST_IPv4_1 /* badSenderAddress */,
+                ipv4NetworkInterface);
     }
 
     /** Checks that a source-specific join() works when the receiver is bound to the "any" address */
     public void test_joinSourceSpecific_anyBind_ipv6() throws Exception {
-        InetAddress ipv6LocalAddress = getLocalIpv6Address(IPV6networkInterface1);
+        InetAddress ipv6LocalAddress = getLocalIpv6Address(ipv6NetworkInterface);
         test_joinSourceSpecific(
                 ipv6LocalAddress /* senderBindAddress */,
                 WILDCARD_IPv6 /* receiverBindAddress */,
                 GOOD_MULTICAST_IPv6 /* groupAddress */,
-                UNICAST_IPv6_1 /* badSenderAddress */);
+                UNICAST_IPv6_1 /* badSenderAddress */,
+                ipv6NetworkInterface);
     }
 
     /**
@@ -901,8 +1031,11 @@
      */
     private void test_joinSourceSpecific(
             InetAddress senderBindAddress, InetAddress receiverBindAddress, InetAddress groupAddress,
-            InetAddress badSenderAddress)
+            InetAddress badSenderAddress, NetworkInterface networkInterface)
             throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel sendingChannel = DatagramChannel.open();
         // In order to be source-specific the sender's address must be known. The sendingChannel is
         // explicitly bound to a known, non-loopback address.
@@ -919,7 +1052,7 @@
         InetSocketAddress groupSocketAddress =
                 new InetSocketAddress(groupAddress, localReceivingAddress.getPort());
         MembershipKey membershipKey1 = receivingChannel
-                .join(groupSocketAddress.getAddress(), networkInterface1, senderBindAddress);
+                .join(groupSocketAddress.getAddress(), networkInterface, senderBindAddress);
 
         ByteBuffer receiveBuffer = ByteBuffer.allocate(10);
 
@@ -932,7 +1065,7 @@
 
         membershipKey1.drop();
 
-        receivingChannel.join(groupSocketAddress.getAddress(), networkInterface1, badSenderAddress);
+        receivingChannel.join(groupSocketAddress.getAddress(), networkInterface, badSenderAddress);
 
         // Send a message. It should not be received.
         String msg2 = "Hello2";
@@ -946,18 +1079,24 @@
 
     public void test_dropSourceSpecific_twice_IPv4() throws Exception {
         test_dropSourceSpecific_twice(
-                GOOD_MULTICAST_IPv4 /* groupAddress */, UNICAST_IPv4_1 /* sourceAddress */);
+                GOOD_MULTICAST_IPv4 /* groupAddress */, UNICAST_IPv4_1 /* sourceAddress */,
+                ipv4NetworkInterface);
     }
 
     public void test_dropSourceSpecific_twice_IPv6() throws Exception {
         test_dropSourceSpecific_twice(
-                GOOD_MULTICAST_IPv6 /* groupAddress */, UNICAST_IPv6_1 /* sourceAddress */);
+                GOOD_MULTICAST_IPv6 /* groupAddress */, UNICAST_IPv6_1 /* sourceAddress */,
+                ipv6NetworkInterface);
     }
 
-    private void test_dropSourceSpecific_twice(InetAddress groupAddress, InetAddress sourceAddress)
+    private void test_dropSourceSpecific_twice(InetAddress groupAddress, InetAddress sourceAddress,
+            NetworkInterface networkInterface)
             throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(groupAddress, networkInterface1, sourceAddress);
+        MembershipKey membershipKey = dc.join(groupAddress, networkInterface, sourceAddress);
 
         assertTrue(membershipKey.isValid());
         membershipKey.drop();
@@ -973,22 +1112,27 @@
         test_dropSourceSpecific_sourceKeysAreIndependent(
                 GOOD_MULTICAST_IPv4 /* groupAddress */,
                 UNICAST_IPv4_1 /* sourceAddress1 */,
-                UNICAST_IPv4_2 /* sourceAddress2 */);
+                UNICAST_IPv4_2 /* sourceAddress2 */,
+                ipv4NetworkInterface);
     }
 
     public void test_dropSourceSpecific_sourceKeysAreIndependent_IPv6() throws Exception {
         test_dropSourceSpecific_sourceKeysAreIndependent(
                 GOOD_MULTICAST_IPv6 /* groupAddress */,
                 UNICAST_IPv6_1 /* sourceAddress1 */,
-                UNICAST_IPv6_2 /* sourceAddress2 */);
+                UNICAST_IPv6_2 /* sourceAddress2 */,
+                ipv6NetworkInterface);
     }
 
     private void test_dropSourceSpecific_sourceKeysAreIndependent(
-            InetAddress groupAddress, InetAddress sourceAddress1, InetAddress sourceAddress2)
-            throws Exception {
+            InetAddress groupAddress, InetAddress sourceAddress1, InetAddress sourceAddress2,
+            NetworkInterface networkInterface) throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey1 = dc.join(groupAddress, networkInterface1, sourceAddress1);
-        MembershipKey membershipKey2 = dc.join(groupAddress, networkInterface1, sourceAddress2);
+        MembershipKey membershipKey1 = dc.join(groupAddress, networkInterface, sourceAddress1);
+        MembershipKey membershipKey2 = dc.join(groupAddress, networkInterface, sourceAddress2);
         assertFalse(membershipKey1.equals(membershipKey2));
         assertTrue(membershipKey1.isValid());
         assertTrue(membershipKey2.isValid());
@@ -1002,8 +1146,11 @@
     }
 
     public void test_drop_keyBehaviorAfterDrop() throws Exception {
+        if (!supportsMulticast) {
+            return;
+        }
         DatagramChannel dc = createReceiverChannel();
-        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, networkInterface1, UNICAST_IPv4_1);
+        MembershipKey membershipKey = dc.join(GOOD_MULTICAST_IPv4, ipv4NetworkInterface, UNICAST_IPv4_1);
         membershipKey.drop();
         assertFalse(membershipKey.isValid());
 
@@ -1020,7 +1167,7 @@
         assertSame(dc, membershipKey.channel());
         assertSame(GOOD_MULTICAST_IPv4, membershipKey.group());
         assertSame(UNICAST_IPv4_1, membershipKey.sourceAddress());
-        assertSame(networkInterface1, membershipKey.networkInterface());
+        assertSame(ipv4NetworkInterface, membershipKey.networkInterface());
     }
 
     private static void configureChannelForReceiving(DatagramChannel receivingChannel)
diff --git a/luni/src/test/java/libcore/java/nio/file/DefaultFileStoreTest.java b/luni/src/test/java/libcore/java/nio/file/DefaultFileStoreTest.java
index c15aa31..763efbf 100644
--- a/luni/src/test/java/libcore/java/nio/file/DefaultFileStoreTest.java
+++ b/luni/src/test/java/libcore/java/nio/file/DefaultFileStoreTest.java
@@ -47,7 +47,7 @@
 
     @Test
     public void test_name() throws IOException, InterruptedException {
-        Path path = Paths.get(filesSetup.getTestDir(), "dir");
+        Path path = filesSetup.getPathInTestDir("dir");
         Files.createDirectory(path);
         Process p = execCmdAndWaitForTermination("df", path.toAbsolutePath().toString());
         String shellOutput = readFromInputStream(p.getInputStream()).split("\n")[1];
@@ -57,7 +57,7 @@
 
     @Test
     public void test_type() throws IOException, InterruptedException {
-        Path path = Paths.get(filesSetup.getTestDir(), "dir");
+        Path path = filesSetup.getPathInTestDir("dir");
         Files.createDirectory(path);
         String fileStore = Files.getFileStore(path).name();
         Process p = execCmdAndWaitForTermination("mount");
@@ -103,7 +103,7 @@
 
     @Test
     public void test_supportsFileAttributeView$Class() throws IOException {
-        Path path = Paths.get(filesSetup.getTestDir(), "dir");
+        Path path = filesSetup.getPathInTestDir("dir");
         Files.createDirectories(path);
         assertTrue(Files.getFileStore(path).supportsFileAttributeView(
                 BasicFileAttributeView.class));
@@ -120,7 +120,7 @@
 
     @Test
     public void test_supportsFileAttributeView$String() throws IOException {
-        Path path = Paths.get(filesSetup.getTestDir(), "dir");
+        Path path = filesSetup.getPathInTestDir("dir");
         Files.createDirectories(path);
         assertTrue(Files.getFileStore(path).supportsFileAttributeView("basic"));
         assertTrue(Files.getFileStore(path).supportsFileAttributeView("unix"));
@@ -133,7 +133,7 @@
 
     @Test
     public void test_getFileStoreAttributeView() throws IOException {
-        Path path = Paths.get(filesSetup.getTestDir(), "dir");
+        Path path = filesSetup.getPathInTestDir("dir");
         Files.createDirectories(path);
         assertNull(Files.getFileStore(path).getFileStoreAttributeView(
                 FileStoreAttributeView.class));
@@ -145,7 +145,7 @@
 
     @Test
     public void test_getAttribute() throws IOException {
-        Path p = Paths.get(filesSetup.getTestDir(), "dir");
+        Path p = filesSetup.getPathInTestDir("dir");
         Files.createDirectories(p);
         FileStore store = Files.getFileStore(p);
         assertEquals(store.getTotalSpace(), store.getAttribute("totalSpace"));
diff --git a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
new file mode 100644
index 0000000..04be662
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryNotEmptyException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.FileStore;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.NotLinkException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import static libcore.java.nio.file.FilesSetup.DATA_FILE;
+import static libcore.java.nio.file.FilesSetup.NonStandardOption;
+import static libcore.java.nio.file.FilesSetup.TEST_FILE_DATA;
+import static libcore.java.nio.file.FilesSetup.TEST_FILE_DATA_2;
+import static libcore.java.nio.file.FilesSetup.readFromFile;
+import static libcore.java.nio.file.FilesSetup.writeToFile;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+public class DefaultFileSystemProvider2Test {
+
+    @Rule
+    public FilesSetup filesSetup = new FilesSetup();
+
+    private FileSystemProvider provider;
+
+    @Before
+    public void setUp() throws Exception {
+        provider = filesSetup.getDataFilePath().getFileSystem().provider();
+    }
+
+    @Test
+    public void test_move() throws IOException {
+        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath());
+        assertEquals(TEST_FILE_DATA, readFromFile(filesSetup.getTestPath()));
+        assertFalse(Files.exists(filesSetup.getDataFilePath()));
+
+        filesSetup.reset();
+        Files.createFile(filesSetup.getTestPath());
+        // When target file exists.
+        try {
+            provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath());
+            fail();
+        } catch (FileAlreadyExistsException expected) {}
+
+        // Move to existing target file with REPLACE_EXISTING copy option.
+        filesSetup.reset();
+        Files.createFile(filesSetup.getTestPath());
+        writeToFile(filesSetup.getDataFilePath(), TEST_FILE_DATA_2);
+        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(), REPLACE_EXISTING);
+        assertEquals(TEST_FILE_DATA_2, readFromFile(filesSetup.getTestPath()));
+
+        // Copy from a non existent file.
+        filesSetup.reset();
+        try {
+            provider.move(filesSetup.getTestPath(), filesSetup.getDataFilePath(), REPLACE_EXISTING);
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @Test
+    public void test_move_CopyOption() throws IOException {
+        FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis() - 10000);
+        Files.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", fileTime);
+        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath());
+        assertEquals(fileTime.to(TimeUnit.SECONDS),
+                ((FileTime) Files.getAttribute(filesSetup.getTestPath(),
+                        "basic:lastModifiedTime")).to(TimeUnit.SECONDS));
+        assertEquals(TEST_FILE_DATA, readFromFile(filesSetup.getTestPath()));
+
+        // ATOMIC_MOVE
+        filesSetup.reset();
+        provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(), ATOMIC_MOVE);
+        assertEquals(TEST_FILE_DATA, readFromFile(filesSetup.getTestPath()));
+
+        filesSetup.reset();
+        try {
+            provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(),
+                    NonStandardOption.OPTION1);
+            fail();
+        } catch (UnsupportedOperationException expected) {}
+    }
+
+    @Test
+    public void test_move_NPE() throws IOException {
+        try {
+            provider.move(null, filesSetup.getTestPath());
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            provider.move(filesSetup.getDataFilePath(), null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            provider.move(filesSetup.getDataFilePath(), filesSetup.getTestPath(),
+                    (CopyOption[]) null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_move_directory() throws IOException {
+        Path dirPath = filesSetup.getPathInTestDir("dir1");
+        final Path nestedDirPath = filesSetup.getPathInTestDir("dir1/dir");
+        final Path dirPath2 = filesSetup.getPathInTestDir("dir2");
+
+        Files.createDirectory(dirPath);
+        Files.createDirectory(nestedDirPath);
+        Files.copy(filesSetup.getDataFilePath(),
+                filesSetup.getPathInTestDir("dir1/" + DATA_FILE));
+        provider.move(dirPath, dirPath2);
+
+        Map<Path, Boolean> pathMap = new HashMap<>();
+        try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dirPath2)) {
+            directoryStream.forEach(file -> pathMap.put(file, true));
+        }
+
+        // The files are not copied. The command is equivalent of creating a new directory.
+        assertEquals(2, pathMap.size());
+        assertEquals(TEST_FILE_DATA,
+                readFromFile(filesSetup.getPathInTestDir("dir2/" + DATA_FILE)));
+        assertFalse(Files.exists(dirPath));
+
+        filesSetup.reset();
+    }
+
+    @Test
+    public void test_move_directory_DirectoryNotEmptyException() throws IOException {
+        Path dirPath = filesSetup.getPathInTestDir("dir1");
+        Path dirPath4 = filesSetup.getPathInTestDir("dir4");
+        Files.createDirectory(dirPath);
+        Files.createDirectory(dirPath4);
+        Files.createFile(Paths.get(dirPath.toString(), DATA_FILE));
+        Files.createFile(Paths.get(dirPath4.toString(), DATA_FILE));
+        try {
+            Files.copy(dirPath, dirPath4, REPLACE_EXISTING);
+            fail();
+        } catch (DirectoryNotEmptyException expected) {}
+    }
+
+    @Test
+    public void test_readSymbolicLink() throws IOException {
+        provider.createSymbolicLink(/* Path of the symbolic link */ filesSetup.getTestPath(),
+                /* Path of the target of the symbolic link */
+                filesSetup.getDataFilePath().toAbsolutePath());
+        assertEquals(filesSetup.getDataFilePath().toAbsolutePath(),
+                Files.readSymbolicLink(filesSetup.getTestPath()));
+
+        // Sym link to itself
+        filesSetup.reset();
+        provider.createSymbolicLink(/* Path of the symbolic link */ filesSetup.getTestPath(),
+                /* Path of the target of the symbolic link */
+                filesSetup.getTestPath().toAbsolutePath());
+        assertEquals(filesSetup.getTestPath().toAbsolutePath(),
+                Files.readSymbolicLink(filesSetup.getTestPath()));
+
+        filesSetup.reset();
+        try {
+            provider.readSymbolicLink(filesSetup.getDataFilePath());
+            fail();
+        } catch (NotLinkException expected) {
+        }
+    }
+
+    @Test
+    public void test_readSymbolicLink_NPE() throws IOException {
+        try {
+            provider.readSymbolicLink(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_isSameFile() throws IOException {
+        // When both the files exists.
+        assertTrue(provider.isSameFile(filesSetup.getDataFilePath(), filesSetup.getDataFilePath()));
+
+        // When the files doesn't exist.
+        assertTrue(provider.isSameFile(filesSetup.getTestPath(), filesSetup.getTestPath()));
+
+        // With two different files.
+        try {
+            assertFalse(
+                    provider.isSameFile(filesSetup.getDataFilePath(), filesSetup.getTestPath()));
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @Test
+    public void test_isSameFile_NPE() throws IOException {
+        try {
+            provider.isSameFile(null, filesSetup.getDataFilePath());
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            provider.isSameFile(filesSetup.getDataFilePath(), null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_getFileStore() throws IOException {
+        FileStore fileStore = provider.getFileStore(filesSetup.getDataFilePath());
+        assertNotNull(fileStore);
+    }
+
+    @Test
+    public void test_getFileStore_NPE() throws IOException {
+        try {
+            provider.getFileStore(null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_isHidden() throws IOException {
+        assertFalse(provider.isHidden(filesSetup.getDataFilePath()));
+        Files.setAttribute(filesSetup.getDataFilePath(), "dos:hidden", true);
+
+        // Files can't be hid.
+        assertFalse(provider.isHidden(filesSetup.getDataFilePath()));
+    }
+
+    @Test
+    public void test_isHidden_NPE() throws IOException {
+        try {
+            provider.isHidden(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_probeContentType_NPE() throws IOException {
+        try {
+            Files.probeContentType(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_getFileAttributeView() throws IOException {
+        BasicFileAttributeView fileAttributeView = provider
+                .getFileAttributeView(filesSetup.getDataFilePath(),
+                BasicFileAttributeView.class);
+
+        assertTrue(fileAttributeView.readAttributes().isRegularFile());
+        assertFalse(fileAttributeView.readAttributes().isDirectory());
+    }
+
+    @Test
+    public void test_getFileAttributeView_NPE() throws IOException {
+        try {
+            provider.getFileAttributeView(null, BasicFileAttributeView.class);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            provider.getFileAttributeView(filesSetup.getDataFilePath(), null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_readAttributes() throws IOException {
+        FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis() - 10000);
+        Files.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", fileTime);
+        BasicFileAttributes basicFileAttributes = provider
+                .readAttributes(filesSetup.getDataFilePath(),
+                BasicFileAttributes.class);
+        FileTime lastModifiedTime = basicFileAttributes.lastModifiedTime();
+        assertEquals(fileTime.to(TimeUnit.SECONDS), lastModifiedTime.to(TimeUnit.SECONDS));
+
+        // When file is NON_EXISTENT.
+        try {
+            provider.readAttributes(filesSetup.getTestPath(), BasicFileAttributes.class);
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @Test
+    public void test_readAttributes_NPE() throws IOException {
+        try {
+            provider.readAttributes(filesSetup.getDataFilePath(),
+                    (Class<BasicFileAttributes>) null);
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            provider.readAttributes(null, BasicFileAttributes.class);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_setAttribute() throws IOException {
+        // Other tests are covered in test_readAttributes.
+        // When file is NON_EXISTENT.
+        try {
+            FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis());
+            provider.setAttribute(filesSetup.getTestPath(), "basic:lastModifiedTime", fileTime);
+            fail();
+        } catch (NoSuchFileException expected) {}
+
+        // ClassCastException
+        try {
+            provider.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", 10);
+            fail();
+        } catch (ClassCastException expected) {}
+
+        // IllegalArgumentException
+        try {
+            provider.setAttribute(filesSetup.getDataFilePath(), "xyz", 10);
+            fail();
+        } catch (IllegalArgumentException expected) {}
+
+        try {
+            provider.setAttribute(null, "xyz", 10);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            provider.setAttribute(filesSetup.getDataFilePath(), null, 10);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProviderTest.java b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProviderTest.java
index 3b1d65a..f14f68d 100644
--- a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProviderTest.java
+++ b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProviderTest.java
@@ -398,7 +398,7 @@
     @Test
     public void test_createDirectory() throws IOException {
         // Check if createDirectory is actually creating a directory.
-        Path newDirectory = Paths.get(filesSetup.getTestDir(), "newDir");
+        Path newDirectory = filesSetup.getPathInTestDir("newDir");
         assertFalse(Files.exists(newDirectory));
         assertFalse(Files.isDirectory(newDirectory));
 
@@ -415,7 +415,7 @@
         }
 
         // File with unicode name.
-        Path unicodeFilePath = Paths.get(filesSetup.getTestDir(), "टेस्ट डायरेक्टरी");
+        Path unicodeFilePath = filesSetup.getPathInTestDir("टेस्ट डायरेक्टरी");
         provider.createDirectory(unicodeFilePath);
         assertTrue(Files.exists(unicodeFilePath));
     }
@@ -430,7 +430,7 @@
         // Creating a new file and passing multiple attribute of the same name.
         perm = PosixFilePermissions.fromString("rw-------");
         FileAttribute<Set<PosixFilePermission>> attr1 = PosixFilePermissions.asFileAttribute(perm);
-        Path dirPath2 = Paths.get(filesSetup.getTestDir(), "new_file");
+        Path dirPath2 = filesSetup.getPathInTestDir("new_file");
         provider.createDirectory(dirPath2, attr, attr1);
         // Value should be equal to the last attribute passed.
         assertEquals(attr1.value(), Files.getAttribute(dirPath2, attr.name()));
@@ -547,7 +547,7 @@
         }
 
         // Delete a directory.
-        Path dirPath = Paths.get(filesSetup.getTestDir(), "dir");
+        Path dirPath = filesSetup.getPathInTestDir("dir");
         Files.createDirectory(dirPath);
         provider.delete(dirPath);
         assertFalse(Files.exists(dirPath));
@@ -555,7 +555,7 @@
 
         // Delete a non empty directory.
         Files.createDirectory(dirPath);
-        Files.createFile(Paths.get(filesSetup.getTestDir(), "dir/file"));
+        Files.createFile(filesSetup.getPathInTestDir("dir/file"));
         try {
             provider.delete(dirPath);
             fail();
@@ -580,14 +580,14 @@
         assertFalse(Files.deleteIfExists(filesSetup.getTestPath()));
 
         // Delete a directory.
-        Path dirPath = Paths.get(filesSetup.getTestDir(), "dir");
+        Path dirPath = filesSetup.getPathInTestDir("dir");
         Files.createDirectory(dirPath);
         assertTrue(Files.deleteIfExists(dirPath));
         assertFalse(Files.exists(dirPath));
 
         // Delete a non empty directory.
         Files.createDirectory(dirPath);
-        Files.createFile(Paths.get(filesSetup.getTestDir(), "dir/file"));
+        Files.createFile(filesSetup.getPathInTestDir("dir/file"));
         try {
             provider.deleteIfExists(dirPath);
             fail();
@@ -629,8 +629,8 @@
         // With target is a symbolic link file.
         try {
             filesSetup.reset();
-            Path symlink = Paths.get(filesSetup.getTestDir(), "symlink");
-            Path newFile = Paths.get(filesSetup.getTestDir(), "newDir");
+            Path symlink = filesSetup.getPathInTestDir("symlink");
+            Path newFile = filesSetup.getPathInTestDir("newDir");
             Files.createFile(newFile);
             assertTrue(Files.exists(newFile));
             Files.createSymbolicLink(symlink, filesSetup.getDataFilePath());
@@ -694,17 +694,17 @@
 
     @Test
     public void test_copy_directory() throws IOException {
-        final Path dirPath = Paths.get(filesSetup.getTestDir(), "dir1");
-        final Path dirPath2 = Paths.get(filesSetup.getTestDir(), "dir2");
+        final Path dirPath = filesSetup.getPathInTestDir("dir1");
+        final Path dirPath2 = filesSetup.getPathInTestDir("dir2");
         // Nested directory.
-        final Path dirPath3 = Paths.get(filesSetup.getTestDir(), "dir1/dir");
+        final Path dirPath3 = filesSetup.getPathInTestDir("dir1/dir");
 
         // Create dir1 and dir1/dir, and copying dir1/dir to dir2. Copy will create dir2, however,
         // it will not copy the content of the source directory.
         Files.createDirectory(dirPath);
         Files.createDirectory(dirPath3);
         provider.copy(filesSetup.getDataFilePath(),
-                Paths.get(filesSetup.getTestDir(), "dir1/" + DATA_FILE));
+                filesSetup.getPathInTestDir("dir1/" + DATA_FILE));
         provider.copy(dirPath, dirPath2);
         assertTrue(Files.exists(dirPath2));
 
@@ -718,7 +718,7 @@
 
 
         // When the target directory is not empty.
-        Path dirPath4 = Paths.get(filesSetup.getTestDir(), "dir4");
+        Path dirPath4 = filesSetup.getPathInTestDir("dir4");
         Files.createDirectories(dirPath4);
         Path file = Paths.get("file");
         Files.createFile(Paths.get(dirPath.toString(), file.toString()));
@@ -734,14 +734,14 @@
     public void test_newDirectoryStream$Path$Filter() throws IOException {
 
         // Initial setup of directory.
-        Path path_root = Paths.get(filesSetup.getTestDir(), "dir");
-        Path path_dir1 = Paths.get(filesSetup.getTestDir(), "dir/dir1");
-        Path path_dir2 = Paths.get(filesSetup.getTestDir(), "dir/dir2");
-        Path path_dir3 = Paths.get(filesSetup.getTestDir(), "dir/dir3");
+        Path path_root = filesSetup.getPathInTestDir("dir");
+        Path path_dir1 = filesSetup.getPathInTestDir("dir/dir1");
+        Path path_dir2 = filesSetup.getPathInTestDir("dir/dir2");
+        Path path_dir3 = filesSetup.getPathInTestDir("dir/dir3");
 
-        Path path_f1 = Paths.get(filesSetup.getTestDir(), "dir/f1");
-        Path path_f2 = Paths.get(filesSetup.getTestDir(), "dir/f2");
-        Path path_f3 = Paths.get(filesSetup.getTestDir(), "dir/f3");
+        Path path_f1 = filesSetup.getPathInTestDir("dir/f1");
+        Path path_f2 = filesSetup.getPathInTestDir("dir/f2");
+        Path path_f3 = filesSetup.getPathInTestDir("dir/f3");
 
         Files.createDirectory(path_root);
         Files.createDirectory(path_dir1);
@@ -776,7 +776,7 @@
     @Test
     public void test_newDirectoryStream$Filter_Exception() throws IOException {
         // Non existent directory.
-        Path path_dir1 = Paths.get(filesSetup.getTestDir(), "newDir1");
+        Path path_dir1 = filesSetup.getPathInTestDir("newDir1");
         DirectoryStream.Filter<Path> fileFilter = new DirectoryStream.Filter<Path>() {
             @Override
             public boolean accept(Path entry) throws IOException {
@@ -792,7 +792,7 @@
         }
 
         // File instead of directory.
-        Path path_file1 = Paths.get(filesSetup.getTestDir(), "newFile1");
+        Path path_file1 = filesSetup.getPathInTestDir("newFile1");
         Files.createFile(path_file1);
         try (DirectoryStream<Path> directoryStream = provider.newDirectoryStream(path_file1,
                 fileFilter)) {
@@ -816,7 +816,7 @@
         }
 
         // Non existent directory.
-        Path path_dir1 = Paths.get(filesSetup.getTestDir(), "newDir1");
+        Path path_dir1 = filesSetup.getPathInTestDir("newDir1");
         try (DirectoryStream<Path> directoryStream = provider.newDirectoryStream(path_dir1,
                 (DirectoryStream.Filter<? super Path>) null)) {
             fail();
diff --git a/luni/src/test/java/libcore/java/nio/file/Files2Test.java b/luni/src/test/java/libcore/java/nio/file/Files2Test.java
new file mode 100644
index 0000000..61b8878
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/Files2Test.java
@@ -0,0 +1,874 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.io.IOException;
+import java.nio.file.CopyOption;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemLoopException;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+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.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+import static java.nio.file.FileVisitResult.TERMINATE;
+import static junit.framework.TestCase.assertTrue;
+import static libcore.java.nio.file.FilesSetup.DATA_FILE;
+import static libcore.java.nio.file.FilesSetup.NON_EXISTENT_FILE;
+import static libcore.java.nio.file.FilesSetup.execCmdAndWaitForTermination;
+import static libcore.java.nio.file.FilesSetup.readFromInputStream;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class Files2Test {
+    @Rule
+    public FilesSetup filesSetup = new FilesSetup();
+    @Rule
+    public MockitoRule mockitoRule = MockitoJUnit.rule();
+    @Mock
+    private Path mockPath;
+    @Mock
+    private Path mockPath2;
+    @Mock
+    private FileSystem mockFileSystem;
+    @Mock
+    private FileSystemProvider mockFileSystemProvider;
+
+    @Before
+    public void setUp() throws Exception {
+        when(mockPath.getFileSystem()).thenReturn(mockFileSystem);
+        when(mockPath2.getFileSystem()).thenReturn(mockFileSystem);
+        when(mockFileSystem.provider()).thenReturn(mockFileSystemProvider);
+    }
+
+    @Test
+    public void test_move() throws IOException {
+        CopyOption mockCopyOption = mock(CopyOption.class);
+        assertEquals(mockPath2, Files.move(mockPath, mockPath2, mockCopyOption));
+        verify(mockFileSystemProvider).move(mockPath, mockPath2, mockCopyOption);
+    }
+
+    @Test
+    public void test_readSymbolicLink() throws IOException {
+        when(mockFileSystemProvider.readSymbolicLink(mockPath)).thenReturn(mockPath2);
+        assertEquals(mockPath2, Files.readSymbolicLink(mockPath));
+        verify(mockFileSystemProvider).readSymbolicLink(mockPath);
+    }
+
+    @Test
+    public void test_isSameFile() throws IOException {
+        when(mockFileSystemProvider.isSameFile(mockPath, mockPath2)).thenReturn(true);
+        when(mockFileSystemProvider.isSameFile(mockPath2, mockPath)).thenReturn(false);
+        assertTrue(Files.isSameFile(mockPath, mockPath2));
+        assertFalse(Files.isSameFile(mockPath2, mockPath));
+    }
+
+    @Test
+    public void test_getFileStore() throws IOException {
+        FileStore mockFileStore = mock(FileStore.class);
+        when(mockFileSystemProvider.getFileStore(mockPath)).thenReturn(mockFileStore);
+        assertEquals(mockFileStore, Files.getFileStore(mockPath));
+    }
+
+    @Test
+    public void test_isHidden() throws IOException {
+        when(mockFileSystemProvider.isHidden(mockPath)).thenReturn(true);
+        when(mockFileSystemProvider.isHidden(mockPath2)).thenReturn(false);
+        assertTrue(Files.isHidden(mockPath));
+        assertFalse(Files.isHidden(mockPath2));
+    }
+
+    @Test
+    public void test_probeContentType() throws IOException {
+        assertEquals("text/plain",
+                Files.probeContentType(filesSetup.getPathInTestDir("file.txt")));
+        assertEquals("text/x-java",
+                Files.probeContentType(filesSetup.getPathInTestDir("file.java")));
+    }
+
+    @Test
+    public void test_getFileAttributeView() throws IOException {
+        FileAttributeView mockFileAttributeView = mock(FileAttributeView.class);
+        when(mockFileSystemProvider.getFileAttributeView(mockPath, FileAttributeView.class,
+                LinkOption.NOFOLLOW_LINKS)).thenReturn(mockFileAttributeView);
+        assertEquals(mockFileAttributeView, Files.getFileAttributeView(mockPath,
+                FileAttributeView.class, LinkOption.NOFOLLOW_LINKS));
+    }
+
+    @Test
+    public void test_readAttributes() throws IOException {
+        BasicFileAttributes mockBasicFileAttributes = mock(BasicFileAttributes.class);
+        when(mockFileSystemProvider.readAttributes(mockPath, BasicFileAttributes.class,
+                LinkOption.NOFOLLOW_LINKS)).thenReturn(mockBasicFileAttributes);
+        assertEquals(mockBasicFileAttributes, Files.readAttributes(mockPath,
+                BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS));
+
+    }
+
+    @Test
+    public void test_setAttribute() throws IOException {
+        assertEquals(mockPath, Files.setAttribute(mockPath, "string", 10,
+                LinkOption.NOFOLLOW_LINKS));
+        verify(mockFileSystemProvider).setAttribute(mockPath, "string", 10,
+                LinkOption.NOFOLLOW_LINKS);
+    }
+
+    @Test
+    public void test_getAttribute() throws IOException {
+        // Other tests are covered in test_readAttributes.
+        // When file is NON_EXISTENT.
+        try {
+            Files.getAttribute(filesSetup.getTestPath(), "basic:lastModifiedTime");
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @Test
+    public void test_getAttribute_Exception() throws IOException {
+        // IllegalArgumentException
+        try {
+            Files.getAttribute(filesSetup.getDataFilePath(), "xyz");
+            fail();
+        } catch (IllegalArgumentException expected) {}
+
+        try {
+            Files.getAttribute(null, "xyz");
+            fail();
+        } catch(NullPointerException expected) {}
+
+        try {
+            Files.getAttribute(filesSetup.getDataFilePath(), null);
+            fail();
+        } catch(NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_getPosixFilePermissions() throws IOException {
+        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
+        FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perm);
+        Files.createFile(filesSetup.getTestPath(), attr);
+        assertEquals(attr.value(), Files.getPosixFilePermissions(filesSetup.getTestPath()));
+    }
+
+    @Test
+    public void test_getPosixFilePermissions_NPE() throws IOException {
+        try {
+            Files.getPosixFilePermissions(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_setPosixFilePermissions() throws IOException {
+        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
+        FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perm);
+        Files.setPosixFilePermissions(filesSetup.getDataFilePath(), perm);
+        assertEquals(attr.value(), Files.getPosixFilePermissions(filesSetup.getDataFilePath()));
+    }
+
+    @Test
+    public void test_setPosixFilePermissions_NPE() throws IOException {
+        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
+        FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perm);
+        try {
+            Files.setPosixFilePermissions(null, perm);
+        } catch(NullPointerException expected) {}
+
+        try {
+            Files.setPosixFilePermissions(filesSetup.getDataFilePath(), null);
+        } catch(NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_getOwner() throws IOException, InterruptedException {
+        String[] statCmd = { "stat", "-c", "%U", filesSetup.getTestDir() + "/" + DATA_FILE };
+        Process statProcess = execCmdAndWaitForTermination(statCmd);
+        String owner = readFromInputStream(statProcess.getInputStream()).trim();
+        assertEquals(owner, Files.getOwner(filesSetup.getDataFilePath()).getName());
+    }
+
+    @Test
+    public void test_getOwner_NPE() throws IOException, InterruptedException {
+        try {
+            Files.getOwner(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_setOwner() throws IOException {
+        // TODO: unable to set the owner due to insufficient permissions.
+    }
+
+    @Test
+    public void test_isSymbolicLink() throws IOException, InterruptedException {
+        assertFalse(Files.isSymbolicLink(filesSetup.getTestPath()));
+        assertFalse(Files.isSymbolicLink(filesSetup.getDataFilePath()));
+
+        // Creating a symbolic link.
+        String[] symLinkCmd = { "ln", "-s", DATA_FILE,
+                filesSetup.getTestDir() + "/" + NON_EXISTENT_FILE };
+        execCmdAndWaitForTermination(symLinkCmd);
+        assertTrue(Files.isSymbolicLink(filesSetup.getTestPath()));
+    }
+
+    @Test
+    public void test_isSymbolicLink_NPE() throws IOException, InterruptedException {
+        try {
+            Files.isSymbolicLink(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_isDirectory() throws IOException, InterruptedException {
+        assertFalse(Files.isDirectory(filesSetup.getDataFilePath()));
+        // When file doesn't exist.
+        assertFalse(Files.isDirectory(filesSetup.getTestPath()));
+
+        // Creating a directory.
+        String dirName = "newDir";
+        Path dirPath = filesSetup.getPathInTestDir(dirName);
+        String mkdir[] = { "mkdir", filesSetup.getTestDir() + "/" + dirName };
+        execCmdAndWaitForTermination(mkdir);
+        assertTrue(Files.isDirectory(dirPath));
+    }
+
+    @Test
+    public void test_isDirectory_NPE() throws IOException {
+        try {
+            Files.isDirectory(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_isRegularFile() throws IOException, InterruptedException {
+        assertTrue(Files.isRegularFile(filesSetup.getDataFilePath()));
+        // When file doesn't exist.
+        assertFalse(Files.isRegularFile(filesSetup.getTestPath()));
+
+        // Check directories.
+        Path dirPath = filesSetup.getPathInTestDir("dir");
+        Files.createDirectory(dirPath);
+        assertFalse(Files.isRegularFile(dirPath));
+
+        // Check symbolic link.
+        // When linked to itself.
+        Files.createSymbolicLink(filesSetup.getTestPath(),
+                filesSetup.getTestPath().toAbsolutePath());
+        assertFalse(Files.isRegularFile(filesSetup.getTestPath()));
+
+        // When linked to some other file.
+        filesSetup.reset();
+        Files.createSymbolicLink(filesSetup.getTestPath(),
+                filesSetup.getDataFilePath().toAbsolutePath());
+        assertTrue(Files.isRegularFile(filesSetup.getTestPath()));
+
+        // When asked to not follow the link.
+        assertFalse(Files.isRegularFile(filesSetup.getTestPath(), LinkOption.NOFOLLOW_LINKS));
+
+        // Device file.
+        Path deviceFilePath = Paths.get("/dev/null");
+        assertTrue(Files.exists(deviceFilePath));
+        assertFalse(Files.isRegularFile(deviceFilePath));
+    }
+
+    @Test
+    public void test_isRegularFile_NPE() throws IOException {
+        try {
+            Files.isReadable(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_getLastModifiedTime() throws IOException, InterruptedException {
+        String touchCmd[] = { "touch", "-d", "2015-10-09T00:00:00",
+                filesSetup.getTestDir() + "/" + DATA_FILE };
+        execCmdAndWaitForTermination(touchCmd);
+        assertEquals("2015-10-09T00:00:00Z",
+                Files.getLastModifiedTime(filesSetup.getDataFilePath()).toString());
+
+        // Non existent file.
+        try {
+            Files.getLastModifiedTime(filesSetup.getTestPath()).toString();
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @Test
+    public void test_getLastModifiedTime_NPE() throws IOException {
+        try {
+            Files.getLastModifiedTime(null, LinkOption.NOFOLLOW_LINKS);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            Files.getLastModifiedTime(filesSetup.getDataFilePath(), (LinkOption[]) null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_setLastModifiedTime() throws IOException, InterruptedException {
+        long timeInMillisToBeSet = System.currentTimeMillis() - 10000;
+        Files.setLastModifiedTime(filesSetup.getDataFilePath(),
+                FileTime.fromMillis(timeInMillisToBeSet));
+        assertEquals(timeInMillisToBeSet/1000,
+                Files.getLastModifiedTime(filesSetup.getDataFilePath()).to(TimeUnit.SECONDS));
+
+        // Non existent file.
+        try {
+            Files.setLastModifiedTime(filesSetup.getTestPath(),
+                    FileTime.fromMillis(timeInMillisToBeSet));
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @Test
+    public void test_setLastModifiedTime_NPE() throws IOException, InterruptedException {
+        try {
+            Files.setLastModifiedTime(null, FileTime.fromMillis(System.currentTimeMillis()));
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // No NullPointerException.
+        Files.setLastModifiedTime(filesSetup.getDataFilePath(), null);
+    }
+
+    @Test
+    public void test_size() throws IOException, InterruptedException {
+        int testSizeInBytes = 5000;
+        String ddCmd[] = { "dd", "if=/dev/zero", "of=" + filesSetup.getTestDir() + "/" + DATA_FILE,
+                "bs="
+                + testSizeInBytes, "count=1"};
+        execCmdAndWaitForTermination(ddCmd);
+
+        assertEquals(testSizeInBytes, Files.size(filesSetup.getDataFilePath()));
+
+        try {
+            Files.size(filesSetup.getTestPath());
+            fail();
+        } catch (NoSuchFileException expected) {}
+    }
+
+    @Test
+    public void test_size_NPE() throws IOException, InterruptedException {
+        try {
+            Files.size(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_exists() throws IOException {
+        // When file exists.
+        assertTrue(Files.exists(filesSetup.getDataFilePath()));
+
+        // When file doesn't exist.
+        assertFalse(Files.exists(filesSetup.getTestPath()));
+
+        // SymLink
+        Files.createSymbolicLink(filesSetup.getTestPath(),
+                filesSetup.getDataFilePath().toAbsolutePath());
+        assertTrue(Files.exists(filesSetup.getTestPath()));
+
+        // When link shouldn't be followed
+        assertTrue(Files.exists(filesSetup.getTestPath(), LinkOption.NOFOLLOW_LINKS));
+
+        // When the target file doesn't exist.
+        Files.delete(filesSetup.getDataFilePath());
+        assertTrue(Files.exists(filesSetup.getTestPath(), LinkOption.NOFOLLOW_LINKS));
+        assertFalse(Files.exists(filesSetup.getTestPath()));
+
+        // Symlink to itself
+        filesSetup.reset();
+        Files.createSymbolicLink(filesSetup.getTestPath(),
+                filesSetup.getTestPath().toAbsolutePath());
+        assertFalse(Files.exists(filesSetup.getTestPath()));
+        assertTrue(Files.exists(filesSetup.getTestPath(), LinkOption.NOFOLLOW_LINKS));
+    }
+
+    @Test
+    public void test_exists_NPE() throws IOException {
+        try {
+            Files.exists(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_notExists() throws IOException {
+        // When file exists.
+        assertFalse(Files.notExists(filesSetup.getDataFilePath()));
+
+        // When file doesn't exist.
+        assertTrue(Files.notExists(filesSetup.getTestPath()));
+
+        // SymLink
+        Files.createSymbolicLink(filesSetup.getTestPath(),
+                filesSetup.getDataFilePath().toAbsolutePath());
+        assertFalse(Files.notExists(filesSetup.getTestPath()));
+
+        // When link shouldn't be followed
+        assertFalse(Files.notExists(filesSetup.getTestPath(), LinkOption.NOFOLLOW_LINKS));
+
+        // When the target file doesn't exist.
+        Files.delete(filesSetup.getDataFilePath());
+        assertFalse(Files.notExists(filesSetup.getTestPath(), LinkOption.NOFOLLOW_LINKS));
+        assertTrue(Files.notExists(filesSetup.getTestPath()));
+
+        // Symlink to itself
+        filesSetup.reset();
+        Files.createSymbolicLink(filesSetup.getTestPath(),
+                filesSetup.getTestPath().toAbsolutePath());
+        assertFalse(Files.notExists(filesSetup.getTestPath()));
+        assertFalse(Files.notExists(filesSetup.getTestPath(), LinkOption.NOFOLLOW_LINKS));
+    }
+
+    @Test
+    public void test_notExists_NPE() throws IOException {
+        try {
+            Files.notExists(null);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            Files.notExists(filesSetup.getDataFilePath(), (LinkOption[]) null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_isReadable() throws IOException {
+        // When a readable file is available.
+        assertTrue(Files.isReadable(filesSetup.getDataFilePath()));
+
+        // When a file doesn't exist.
+        assertFalse(Files.isReadable(filesSetup.getTestPath()));
+
+        // Setting non readable permission for user
+        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("-wxrwxrwx");
+        Files.setPosixFilePermissions(filesSetup.getDataFilePath(), perm);
+        assertFalse(Files.isReadable(filesSetup.getDataFilePath()));
+    }
+
+    @Test
+    public void test_isReadable_NPE() throws IOException {
+        try {
+            Files.isReadable(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_isWritable() throws IOException {
+        // When a readable file is available.
+        assertTrue(Files.isWritable(filesSetup.getDataFilePath()));
+
+        // When a file doesn't exist.
+        assertFalse(Files.isWritable(filesSetup.getTestPath()));
+
+        // Setting non writable permission for user
+        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("r-xrwxrwx");
+        Files.setPosixFilePermissions(filesSetup.getDataFilePath(), perm);
+        assertFalse(Files.isWritable(filesSetup.getDataFilePath()));
+    }
+
+    @Test
+    public void test_isWritable_NPE() {
+        try {
+            Files.isWritable(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_isExecutable() throws IOException {
+        // When a readable file is available.
+        assertFalse(Files.isExecutable(filesSetup.getDataFilePath()));
+
+        // When a file doesn't exist.
+        assertFalse(Files.isExecutable(filesSetup.getTestPath()));
+
+        // Setting non executable permission for user
+        Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rw-rwxrwx");
+        Files.setPosixFilePermissions(filesSetup.getDataFilePath(), perm);
+        assertFalse(Files.isExecutable(filesSetup.getDataFilePath()));
+    }
+
+    @Test
+    public void test_isExecutable_NPE() {
+        try {
+            Files.isExecutable(null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_walkFileTree$Path$Set$int$FileVisitor_symbolicLinkFollow()
+            throws IOException, InterruptedException {
+        // Directory structure.
+        //        root
+        //        ├── dir1
+        //        │   └── dir2 ─ dir3-file1 - file3
+        //        │
+        //        └── file2
+        //
+        // With follow link it should be able to traverse to dir3 and file1 when started from file2.
+
+        // Directory setup.
+        Path rootDir = filesSetup.getPathInTestDir("root");
+        Path dir1 = filesSetup.getPathInTestDir("root/dir1");
+        Path dir2 = filesSetup.getPathInTestDir("root/dir1/dir2");
+        Path dir3 = filesSetup.getPathInTestDir("root/dir1/dir2/dir3");
+        Path file1 = filesSetup.getPathInTestDir("root/dir1/dir2/dir3/file1");
+        Path file2 = filesSetup.getPathInTestDir("root/file2");
+
+        Files.createDirectories(dir3);
+        Files.createFile(file1);
+        Files.createSymbolicLink(file2, dir2.toAbsolutePath());
+        assertTrue(Files.isSymbolicLink(file2));
+
+        Map<Object, VisitOption> dirMap = new HashMap<>();
+        Map<Object, VisitOption> expectedDirMap = new HashMap<>();
+        Set<FileVisitOption> option = new HashSet<>();
+        option.add(FileVisitOption.FOLLOW_LINKS);
+        Files.walkFileTree(file2, option, 50, new TestFileVisitor(dirMap, option));
+
+        expectedDirMap.put(file1.getFileName(), VisitOption.VISIT_FILE);
+        expectedDirMap.put(file2.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(dir3.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+
+        assertEquals(expectedDirMap, dirMap);
+    }
+
+    @Test
+    public void test_walkFileTree$Path$FileVisitor() throws IOException {
+        // Directory structure.
+        //    .
+        //    ├── DATA_FILE
+        //    └── root
+        //        ├── dir1
+        //        │   ├── dir2
+        //        │   │   ├── dir3
+        //        │   │   └── file5
+        //        │   ├── dir4
+        //        │   └── file3
+        //        ├── dir5
+        //        └── file1
+        //
+
+        // Directory Setup.
+        Path rootDir = filesSetup.getPathInTestDir("root");
+        Path dir1 = filesSetup.getPathInTestDir("root/dir1");
+        Path dir2 = filesSetup.getPathInTestDir("root/dir1/dir2");
+        Path dir3 = filesSetup.getPathInTestDir("root/dir1/dir2/dir3");
+        Path dir4 = filesSetup.getPathInTestDir("root/dir1/dir4");
+        Path dir5 = filesSetup.getPathInTestDir("root/dir5");
+        Path file1 = filesSetup.getPathInTestDir("root/file1");
+        Path file3 = filesSetup.getPathInTestDir("root/dir1/file3");
+        Path file5 = filesSetup.getPathInTestDir("root/dir1/dir2/file5");
+
+        Files.createDirectories(dir3);
+        Files.createDirectories(dir4);
+        Files.createDirectories(dir5);
+        Files.createFile(file3);
+        Files.createFile(file5);
+        Files.createSymbolicLink(file1, filesSetup.getDataFilePath().toAbsolutePath());
+
+        Map<Object, VisitOption> dirMap = new HashMap<>();
+        Map<Object, VisitOption> expectedDirMap = new HashMap<>();
+        Path returnedPath = Files.walkFileTree(rootDir, new Files2Test.TestFileVisitor(dirMap));
+
+        assertEquals(rootDir, returnedPath);
+
+        expectedDirMap.put(rootDir.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(dir1.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(dir2.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(dir3.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(file5.getFileName(), VisitOption.VISIT_FILE);
+        expectedDirMap.put(dir4.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(file3.getFileName(), VisitOption.VISIT_FILE);
+        expectedDirMap.put(dir5.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(file1.getFileName(), VisitOption.VISIT_FILE);
+        assertEquals(expectedDirMap, dirMap);
+    }
+
+    @Test
+    public void test_walkFileTree_depthFirst() throws IOException {
+        // Directory structure.
+        //    .
+        //    ├── DATA_FILE
+        //    └── root
+        //        ├── dir1 ── file1
+        //        └── dir2 ── file2
+
+        // Directory Setup.
+        Path rootDir = filesSetup.getPathInTestDir("root");
+        Path dir1 = filesSetup.getPathInTestDir("root/dir1");
+        Path dir2 = filesSetup.getPathInTestDir("root/dir2");
+        Path file1 = filesSetup.getPathInTestDir("root/dir1/file1");
+        Path file2 = filesSetup.getPathInTestDir("root/dir2/file2");
+
+        Files.createDirectories(dir1);
+        Files.createDirectories(dir2);
+        Files.createFile(file1);
+        Files.createFile(file2);
+
+        Map<Object, VisitOption> dirMap = new HashMap<>();
+        List<Object> keyList = new ArrayList<>();
+        Files.walkFileTree(rootDir,
+                new Files2Test.TestFileVisitor(dirMap, keyList));
+        assertEquals(rootDir.getFileName(), keyList.get(0));
+        if (keyList.get(1).equals(dir1.getFileName())) {
+            assertEquals(file1.getFileName(), keyList.get(2));
+            assertEquals(dir2.getFileName(), keyList.get(3));
+            assertEquals(file2.getFileName(), keyList.get(4));
+        } else if (keyList.get(1).equals(dir2.getFileName())){
+            assertEquals(file2.getFileName(), keyList.get(2));
+            assertEquals(dir1.getFileName(), keyList.get(3));
+            assertEquals(file1.getFileName(), keyList.get(4));
+        } else {
+            fail();
+        }
+    }
+
+    @Test
+    public void test_walkFileTree_negativeDepth() throws IOException {
+        Path rootDir = filesSetup.getPathInTestDir("root");
+        Path dir1 = filesSetup.getPathInTestDir("root/dir1");
+
+        Files.createDirectories(dir1);
+
+        Map<Object, VisitOption> dirMap = new HashMap<>();
+        Set<FileVisitOption> option = new HashSet<>();
+        option.add(FileVisitOption.FOLLOW_LINKS);
+        try {
+            Files.walkFileTree(rootDir, option, -1,
+                    new Files2Test.TestFileVisitor(dirMap));
+            fail();
+        } catch (IllegalArgumentException expected) {}
+    }
+
+    @Test
+    public void test_walkFileTree_maximumDepth() throws IOException {
+        // Directory structure.
+        //        root
+        //        ├── dir1
+        //        │   ├── dir2
+        //        │   │   ├── dir3
+        //        │   │   └── file5
+        //        │   ├── dir4
+        //        │   └── file3
+        //        ├── dir5
+        //        └── file1
+        //
+        // depth will be 2. file5, dir3 is not reachable.
+        // Directory Setup.
+        Path rootDir = filesSetup.getPathInTestDir("root");
+        Path dir1 = filesSetup.getPathInTestDir("root/dir1");
+        Path dir2 = filesSetup.getPathInTestDir("root/dir1/dir2");
+        Path dir3 = filesSetup.getPathInTestDir("root/dir1/dir2/dir3");
+        Path dir4 = filesSetup.getPathInTestDir("root/dir1/dir4");
+        Path dir5 = filesSetup.getPathInTestDir("root/dir5");
+        Path file1 = filesSetup.getPathInTestDir("root/file1");
+        Path file3 = filesSetup.getPathInTestDir("root/dir1/file3");
+        Path file5 = filesSetup.getPathInTestDir("root/dir1/dir2/file5");
+
+        Files.createDirectories(dir3);
+        Files.createDirectories(dir4);
+        Files.createDirectories(dir5);
+        Files.createFile(file1);
+        Files.createFile(file3);
+        Files.createFile(file5);
+
+        Map<Object, VisitOption> dirMap = new HashMap<>();
+        Map<Object, VisitOption> expectedDirMap = new HashMap<>();
+        Set<FileVisitOption> option = new HashSet<>();
+        option.add(FileVisitOption.FOLLOW_LINKS);
+        Files.walkFileTree(rootDir, option, 2, new Files2Test.TestFileVisitor(dirMap));
+        assertTrue(Files.isDirectory(dir4));
+        expectedDirMap.put(rootDir.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(dir1.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        // Both of the directories are at maximum depth, therefore, will be treated as simple file.
+        expectedDirMap.put(dir2.getFileName(), VisitOption.VISIT_FILE);
+        expectedDirMap.put(dir4.getFileName(), VisitOption.VISIT_FILE);
+        expectedDirMap.put(dir5.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+        expectedDirMap.put(file1.getFileName(), VisitOption.VISIT_FILE);
+        expectedDirMap.put(file3.getFileName(), VisitOption.VISIT_FILE);
+
+        assertEquals(expectedDirMap, dirMap);
+    }
+
+    @Test
+    public void test_walkFileTree$Path$FileVisitor_NPE() throws IOException {
+        Path rootDir = filesSetup.getPathInTestDir("root");
+        try {
+            Files.walkFileTree(null,
+                    new Files2Test.TestFileVisitor(new HashMap<>()));
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            Files.walkFileTree(rootDir, null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_walkFileTree$Path$FileVisitor_FileSystemLoopException() throws IOException {
+        // Directory structure.
+        //    .
+        //    ├── DATA_FILE
+        //    └── root
+        //        └── dir1
+        //             └── file1
+        //
+        // file1 is symlink to dir1
+
+        // Directory Setup.
+        Path rootDir = filesSetup.getPathInTestDir("root");
+        Path dir1 = filesSetup.getPathInTestDir("root/dir1");
+        Path file1 = filesSetup.getPathInTestDir("root/dir1/file1");
+
+        Files.createDirectories(dir1);
+        Files.createSymbolicLink(file1, dir1.toAbsolutePath());
+        assertEquals(dir1.getFileName(), Files.readSymbolicLink(file1).getFileName());
+
+        Map<Object, VisitOption> dirMap = new HashMap<>();
+        Set<FileVisitOption> option = new HashSet<>();
+        option.add(FileVisitOption.FOLLOW_LINKS);
+        try {
+            Files.walkFileTree(rootDir, option, Integer.MAX_VALUE,
+                    new Files2Test.TestFileVisitor(dirMap));
+            fail();
+        } catch (FileSystemLoopException expected) {}
+    }
+
+    // -- Mock Class --
+
+    private static class TestFileVisitor implements FileVisitor<Path> {
+
+        final Map<Object, VisitOption> dirMap;
+        LinkOption option[];
+        List<Object> keyList;
+
+        public TestFileVisitor(Map<Object, VisitOption> dirMap) {
+            this(dirMap, (List<Object>) null);
+        }
+
+        public TestFileVisitor(Map<Object, VisitOption> dirMap, Set<FileVisitOption> option) {
+            this.dirMap = dirMap;
+            for (FileVisitOption fileVisitOption : option) {
+                if (fileVisitOption.equals(FileVisitOption.FOLLOW_LINKS)) {
+                    this.option = new LinkOption[0];
+                }
+            }
+
+            if (this.option == null) {
+                this.option = new LinkOption[] {LinkOption.NOFOLLOW_LINKS};
+            }
+        }
+
+        public TestFileVisitor(Map<Object, VisitOption> dirMap, List<Object> pathList) {
+            this.dirMap = dirMap;
+            this.option = new LinkOption[] {LinkOption.NOFOLLOW_LINKS};
+            keyList = pathList;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+                throws IOException {
+            if (keyList != null) {
+                keyList.add(dir.getFileName());
+            }
+            dirMap.put(dir.getFileName(), VisitOption.PRE_VISIT_DIRECTORY);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+            if (keyList != null) {
+                keyList.add(file.getFileName());
+            }
+            dirMap.put(file.getFileName(), VisitOption.VISIT_FILE);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+            if (exc != null) {
+                throw exc;
+            }
+            return TERMINATE;
+        }
+
+        @Override
+        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+            if (exc != null) {
+                throw exc;
+            }
+            if (dirMap.getOrDefault(dir.getFileName(), VisitOption.UNVISITED)
+                    != VisitOption.PRE_VISIT_DIRECTORY) {
+                return TERMINATE;
+            } else {
+                dirMap.put(dir.getFileName(), VisitOption.POST_VISIT_DIRECTORY);
+                return CONTINUE;
+            }
+        }
+    }
+
+    private enum VisitOption {
+        PRE_VISIT_DIRECTORY,
+        VISIT_FILE,
+        POST_VISIT_DIRECTORY,
+        UNVISITED,
+    }
+}
diff --git a/luni/src/test/java/libcore/java/nio/file/FilesSetup.java b/luni/src/test/java/libcore/java/nio/file/FilesSetup.java
index 6931978..66201d9 100644
--- a/luni/src/test/java/libcore/java/nio/file/FilesSetup.java
+++ b/luni/src/test/java/libcore/java/nio/file/FilesSetup.java
@@ -51,6 +51,8 @@
 
     private Path testPath;
 
+    private Path testDirPath;
+
     private boolean filesInitialized = false;
 
     void setUp() throws Exception {
@@ -63,7 +65,8 @@
     }
 
     private void initializeFiles() throws IOException {
-        testDir = Files.createTempDirectory("testDir").toString();
+        testDirPath = Files.createTempDirectory("testDir");
+        testDir = testDirPath.toString();
         dataFilePath = Paths.get(testDir, DATA_FILE);
         testPath = Paths.get(testDir, NON_EXISTENT_FILE);
         File testInputFile = new File(testDir, DATA_FILE);
@@ -87,6 +90,11 @@
         return dataFilePath;
     }
 
+    Path getTestDirPath() {
+        checkState();
+        return testDirPath;
+    }
+
     String getTestDir() {
         checkState();
         return testDir;
@@ -169,6 +177,10 @@
         };
     }
 
+    Path getPathInTestDir(String path) {
+        return Paths.get(getTestDir(), path);
+    }
+
     /**
      * Non Standard CopyOptions.
      */
@@ -176,9 +188,4 @@
         OPTION1,
     }
 
-    static Object getFileKey(Path file) throws IOException {
-        return Files.readAttributes(file, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)
-                .fileKey();
-    }
-
 }
diff --git a/luni/src/test/java/libcore/java/nio/file/FilesTest.java b/luni/src/test/java/libcore/java/nio/file/FilesTest.java
index 3f967c9..e1250a0 100644
--- a/luni/src/test/java/libcore/java/nio/file/FilesTest.java
+++ b/luni/src/test/java/libcore/java/nio/file/FilesTest.java
@@ -38,7 +38,6 @@
 import java.nio.file.NotDirectoryException;
 import java.nio.file.OpenOption;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.nio.file.attribute.FileAttribute;
 import java.nio.file.attribute.PosixFilePermission;
 import java.nio.file.attribute.PosixFilePermissions;
@@ -127,7 +126,7 @@
         assertTrue(Files.exists(filesSetup.getTestPath()));
 
         // File with unicode name.
-        Path unicodeFilePath = Paths.get(filesSetup.getTestDir(), "परीक्षण फ़ाइल");
+        Path unicodeFilePath = filesSetup.getPathInTestDir("परीक्षण फ़ाइल");
         Files.createFile(unicodeFilePath);
         Files.exists(unicodeFilePath);
 
@@ -156,7 +155,7 @@
         // Creating a new file and passing multiple attribute of the same name.
         perm = PosixFilePermissions.fromString("rw-------");
         FileAttribute<Set<PosixFilePermission>> attr1 = PosixFilePermissions.asFileAttribute(perm);
-        Path filePath2 = Paths.get(filesSetup.getTestDir(), "new_file");
+        Path filePath2 = filesSetup.getPathInTestDir("new_file");
         Files.createFile(filePath2, attr, attr1);
         // Value should be equal to the last attribute passed.
         assertEquals(attr1.value(), Files.getAttribute(filePath2, attr.name()));
@@ -179,7 +178,7 @@
     @Test
     public void test_createDirectories() throws IOException {
         // Should be able to create parent directories.
-        Path dirPath = Paths.get(filesSetup.getTestDir(), "dir1/dir2/dir3");
+        Path dirPath = filesSetup.getPathInTestDir("dir1/dir2/dir3");
         assertFalse(Files.exists(dirPath));
         Files.createDirectories(dirPath);
         assertTrue(Files.isDirectory(dirPath));
@@ -198,7 +197,7 @@
 
     @Test
     public void test_createDirectories$Path$Attr() throws IOException {
-        Path dirPath = Paths.get(filesSetup.getTestDir(), "dir1/dir2/dir3");
+        Path dirPath = filesSetup.getPathInTestDir("dir1/dir2/dir3");
         Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
         FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perm);
         assertFalse(Files.exists(dirPath));
@@ -214,7 +213,7 @@
         assertEquals(attr.value(), Files.getAttribute(dirPath, attr.name()));
 
         // Creating a new directory and passing multiple attribute of the same name.
-        Path dirPath2 = Paths.get(filesSetup.getTestDir(), "dir1/dir2/dir4");
+        Path dirPath2 = filesSetup.getPathInTestDir("dir1/dir2/dir4");
         Files.createDirectories(dirPath2, attr, attr1);
         // Value should be equal to the last attribute passed.
         assertEquals(attr1.value(), Files.getAttribute(dirPath2, attr.name()));
@@ -222,7 +221,7 @@
 
     @Test
     public void test_createDirectories$Path$Attr_NPE() throws IOException {
-        Path dirPath = Paths.get(filesSetup.getTestDir(), "dir1/dir2/dir3");
+        Path dirPath = filesSetup.getPathInTestDir("dir1/dir2/dir3");
         Set<PosixFilePermission> perm = PosixFilePermissions.fromString("rwx------");
         FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perm);
         try {
@@ -239,12 +238,12 @@
     @Test
     public void test_newDirectoryStream() throws IOException {
         // Directory setup.
-        Path path_dir1 = Paths.get(filesSetup.getTestDir(), "newDir1");
-        Path path_dir2 = Paths.get(filesSetup.getTestDir(), "newDir1/newDir2");
-        Path path_dir3 = Paths.get(filesSetup.getTestDir(), "newDir1/newDir3");
-        Path path_file1 = Paths.get(filesSetup.getTestDir(), "newDir1/newFile1");
-        Path path_file2 = Paths.get(filesSetup.getTestDir(), "newDir1/newFile2");
-        Path path_file3 = Paths.get(filesSetup.getTestDir(), "newDir1/newDir2/newFile3");
+        Path path_dir1 = filesSetup.getPathInTestDir("newDir1");
+        Path path_dir2 = filesSetup.getPathInTestDir("newDir1/newDir2");
+        Path path_dir3 = filesSetup.getPathInTestDir("newDir1/newDir3");
+        Path path_file1 = filesSetup.getPathInTestDir("newDir1/newFile1");
+        Path path_file2 = filesSetup.getPathInTestDir("newDir1/newFile2");
+        Path path_file3 = filesSetup.getPathInTestDir("newDir1/newDir2/newFile3");
 
         Files.createDirectory(path_dir1);
         Files.createDirectory(path_dir2);
@@ -270,14 +269,14 @@
     public void test_newDirectoryStream_Exception() throws IOException {
 
         // Non existent directory.
-        Path path_dir1 = Paths.get(filesSetup.getTestDir(), "newDir1");
+        Path path_dir1 = filesSetup.getPathInTestDir("newDir1");
         try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path_dir1)) {
             fail();
         } catch (NoSuchFileException expected) {
         }
 
         // File instead of directory.
-        Path path_file1 = Paths.get(filesSetup.getTestDir(), "newFile1");
+        Path path_file1 = filesSetup.getPathInTestDir("newFile1");
         Files.createFile(path_file1);
         try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path_file1)) {
             fail();
@@ -293,14 +292,14 @@
     @Test
     public void test_newDirectoryStream$Path$String() throws IOException {
         // Directory setup.
-        Path path_root = Paths.get(filesSetup.getTestDir(), "dir");
-        Path path_java1 = Paths.get(filesSetup.getTestDir(), "dir/f1.java");
-        Path path_java2 = Paths.get(filesSetup.getTestDir(), "dir/f2.java");
-        Path path_java3 = Paths.get(filesSetup.getTestDir(), "dir/f3.java");
+        Path path_root = filesSetup.getPathInTestDir("dir");
+        Path path_java1 = filesSetup.getPathInTestDir("dir/f1.java");
+        Path path_java2 = filesSetup.getPathInTestDir("dir/f2.java");
+        Path path_java3 = filesSetup.getPathInTestDir("dir/f3.java");
 
-        Path path_txt1 = Paths.get(filesSetup.getTestDir(), "dir/f1.txt");
-        Path path_txt2 = Paths.get(filesSetup.getTestDir(), "dir/f2.txt");
-        Path path_txt3 = Paths.get(filesSetup.getTestDir(), "dir/f3.txt");
+        Path path_txt1 = filesSetup.getPathInTestDir("dir/f1.txt");
+        Path path_txt2 = filesSetup.getPathInTestDir("dir/f2.txt");
+        Path path_txt3 = filesSetup.getPathInTestDir("dir/f3.txt");
 
         Files.createDirectory(path_root);
         // A directory with .java extension.
@@ -328,14 +327,14 @@
     public void test_newDirectoryStream$Path$String_Exception() throws IOException {
 
         // Non existent directory.
-        Path path_dir1 = Paths.get(filesSetup.getTestDir(), "newDir1");
+        Path path_dir1 = filesSetup.getPathInTestDir("newDir1");
         try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path_dir1, "*.c")) {
             fail();
         } catch (NoSuchFileException expected) {
         }
 
         // File instead of directory.
-        Path path_file1 = Paths.get(filesSetup.getTestDir(), "newFile1");
+        Path path_file1 = filesSetup.getPathInTestDir("newFile1");
         Files.createFile(path_file1);
         try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path_file1, "*.c")) {
             fail();
diff --git a/luni/src/test/java/libcore/java/nio/file/LinuxPathTest.java b/luni/src/test/java/libcore/java/nio/file/LinuxPathTest.java
new file mode 100644
index 0000000..e95f5bc
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/file/LinuxPathTest.java
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package libcore.java.nio.file;
+
+import com.sun.nio.file.ExtendedWatchEventModifier;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
+import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class LinuxPathTest {
+
+    @Rule
+    public FilesSetup filesSetup = new FilesSetup();
+
+    /**
+     * CTS doesn't allow creating files in the test directory, however, Vogar allows creation of
+     * new files in the test directory. Therefore, for the tests which don't require write
+     * permission, dummyPath would serve the purpose, however, for the others, {@link
+     * FilesSetup#getTestDirPath()} should be used.
+     */
+    private static final Path dummyPath = Paths.get("dummyPath");
+
+    @Test
+    public void test_getFileSystem() {
+        assertTrue(dummyPath.getFileSystem().provider() instanceof
+                sun.nio.fs.LinuxFileSystemProvider);
+    }
+
+    @Test
+    public void test_isAbsolute() {
+        assertFalse(dummyPath.isAbsolute());
+        Path absolutePath = dummyPath.toAbsolutePath();
+        assertTrue(absolutePath.isAbsolute());
+    }
+
+    @Test
+    public void test_getRoot() {
+        assertEquals(Paths.get("/"), dummyPath.toAbsolutePath().getRoot());
+        assertNull(dummyPath.getRoot());
+    }
+
+    @Test
+    public void test_getFileName() {
+        assertEquals(dummyPath, dummyPath.getFileName());
+        assertEquals(dummyPath, dummyPath.toAbsolutePath().getFileName());
+        assertNull(dummyPath.getRoot());
+        assertEquals(Paths.get("data"), Paths.get("/data").getFileName());
+        assertEquals(Paths.get("data"), Paths.get("/data/").getFileName());
+        assertEquals(Paths.get(".."), Paths.get("/data/dir1/..").getFileName());
+    }
+
+    @Test
+    public void test_getParent() {
+        assertNull(dummyPath.getParent());
+        assertEquals(Paths.get("rootDir"), Paths.get("rootDir/dir").getParent());
+    }
+
+    @Test
+    public void test_getNameCount() {
+        assertEquals(0, Paths.get("/").getNameCount());
+        assertEquals(1, Paths.get("/dir").getNameCount());
+        assertEquals(2, Paths.get("/dir/dir").getNameCount());
+        assertEquals(2, Paths.get("/dir/..").getNameCount());
+    }
+
+    @Test
+    public void test_getName() {
+        assertEquals(Paths.get("t"), Paths.get("/t/t1/t2/t3").getName(0));
+        assertEquals(Paths.get("t2"), Paths.get("/t/t1/t2/t3").getName(2));
+        assertEquals(Paths.get("t3"), Paths.get("/t/t1/t2/t3").getName(3));
+
+        // Without root.
+        assertEquals(Paths.get("t3"), Paths.get("t/t1/t2/t3").getName(3));
+
+        // Invalid index.
+        try {
+            Paths.get("/t/t1/t2/t3").getName(4);
+            fail();
+        } catch (IllegalArgumentException expected) {}
+
+        // Negative index value.
+        try {
+            Paths.get("/t/t1/t2/t3").getName(-1);
+            fail();
+        } catch (IllegalArgumentException expected) {}
+    }
+
+    @Test
+    public void test_subPath() {
+        assertEquals(Paths.get("t1/t2"), Paths.get("t1/t2/t3").subpath(0, 2));
+        assertEquals(Paths.get("t2"), Paths.get("t1/t2/t3").subpath(1, 2));
+
+        try {
+            Paths.get("t1/t2/t3").subpath(1, 1);
+            fail();
+        } catch (IllegalArgumentException expected) {}
+
+        try {
+            assertEquals(Paths.get("t1/t1"), Paths.get("t1/t2/t3").subpath(1, 0));
+            fail();
+        } catch (IllegalArgumentException expected) {}
+
+        try {
+            assertEquals(Paths.get("t1/t1"), Paths.get("t1/t2/t3").subpath(1, 5));
+            fail();
+        } catch (IllegalArgumentException expected) {}
+    }
+
+    @Test
+    public void test_startsWith$String() {
+        assertTrue(Paths.get("t1/t2").startsWith("t1"));
+        assertTrue(dummyPath.toAbsolutePath().startsWith("/"));
+        assertTrue(Paths.get("t1/t2/t3").startsWith("t1/t2"));
+        assertFalse(Paths.get("t1/t2").startsWith("t2"));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_startsWith$String_NPE() {
+        filesSetup.getTestPath().startsWith((String) null);
+    }
+
+    @Test
+    public void test_startsWith$Path() {
+        assertTrue(Paths.get("t1/t2").startsWith(Paths.get("t1")));
+        assertTrue(dummyPath.toAbsolutePath().startsWith(Paths.get("/")));
+        assertTrue(Paths.get("t1/t2/t3").startsWith(Paths.get("t1/t2")));
+        assertFalse(Paths.get("t1/t2").startsWith(Paths.get("t2")));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_startsWith$Path_NPE() {
+        filesSetup.getTestPath().startsWith((Path) null);
+    }
+
+    @Test
+    public void test_endsWith$Path() {
+        assertTrue(Paths.get("t1/t2").endsWith(Paths.get("t2")));
+        assertTrue(Paths.get("t1/t2/t3").endsWith(Paths.get("t2/t3")));
+        assertFalse(Paths.get("t1/t2").endsWith(Paths.get("t1")));
+        assertTrue(Paths.get("/").endsWith(Paths.get("/")));
+        assertFalse(Paths.get("/data/").endsWith(Paths.get("/")));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_endsWith$Path_NPE() {
+        filesSetup.getTestPath().endsWith((Path)null);
+    }
+
+    @Test
+    public void test_endsWith$String() {
+        assertTrue(Paths.get("t1/t2").endsWith("t2"));
+        assertTrue(Paths.get("t1/t2/t3").endsWith("t2/t3"));
+        assertFalse(Paths.get("t1/t2").endsWith("t1"));
+        assertTrue(Paths.get("/").endsWith("/"));
+        assertFalse(Paths.get("/data/").endsWith("/"));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_endsWith$String_NPE() {
+        filesSetup.getTestPath().endsWith((String)null);
+    }
+
+    @Test
+    public void test_normalize() {
+        assertEquals(Paths.get("t2/t3"), Paths.get("t1/../t2/t3").normalize());
+        assertEquals(Paths.get("../t2/t3"), Paths.get("t1/../../t2/t3").normalize());
+        assertEquals(Paths.get("t1/t2/t3"), Paths.get("t1/./t2/t3").normalize());
+        assertEquals(Paths.get("t1/t2/t3"), Paths.get("t1/././t2/t3").normalize());
+        assertEquals(Paths.get("t1/t2/t3"), Paths.get("t1/././t2/t3").normalize());
+        assertEquals(Paths.get("t1"), Paths.get("t1/"));
+    }
+
+    @Test
+    public void test_resolve$Path() {
+        Path p = Paths.get("p");
+        Path p1 = Paths.get("p1");
+        Path p1p = Paths.get("p1/p");
+        assertEquals(p1p, p1.resolve(p));
+        assertEquals(p.toAbsolutePath(), p1.resolve(p.toAbsolutePath()));
+        assertEquals(p1p.toAbsolutePath(), p1.toAbsolutePath().resolve(p));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_resolve$Path_NPE() {
+        dummyPath.resolve((Path)null);
+    }
+
+    @Test
+    public void test_resolve$String() {
+        Path p = Paths.get("p");
+        Path p1 = Paths.get("p1");
+        Path p1p = Paths.get("p1/p");
+        assertEquals(p1p, p1.resolve("p"));
+        assertEquals(p1p.toAbsolutePath(), p1.toAbsolutePath().resolve("p"));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_resolve$String_NPE() {
+        dummyPath.resolve((String)null);
+    }
+
+    @Test
+    public void test_resolveSibling$Path() {
+        Path c2 = Paths.get("c2");
+        Path parent_c1 = Paths.get("parent/c1");
+        Path parent_c2 = Paths.get("parent/c2");
+        assertEquals(parent_c2, parent_c1.resolveSibling(c2));
+        assertEquals(c2.toAbsolutePath(), parent_c1.resolveSibling(c2.toAbsolutePath()));
+        assertEquals(parent_c2.toAbsolutePath(), parent_c1.toAbsolutePath().resolveSibling(c2));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_resolveSibling$String_Path() {
+        dummyPath.resolveSibling((Path) null);
+    }
+
+    @Test
+    public void test_resolveSibling$String() {
+        Path c2 = Paths.get("c2");
+        Path parent_c1 = Paths.get("parent/c1");
+        Path parent_c2 = Paths.get("parent/c2");
+        assertEquals(parent_c2, parent_c1.resolveSibling(c2.toString()));
+        assertEquals(c2.toAbsolutePath(), parent_c1.resolveSibling(c2.toAbsolutePath().toString()));
+        assertEquals(parent_c2.toAbsolutePath(), parent_c1.toAbsolutePath()
+                .resolveSibling(c2.toString()));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_resolveSibling$String_NPE() {
+        dummyPath.resolveSibling((String)null);
+    }
+
+    @Test
+    public void test_relativize() {
+        Path p1 = Paths.get("t1/t2/t3");
+        Path p2 = Paths.get("t1/t2");
+        assertEquals(Paths.get(".."), p1.relativize(p2));
+        assertEquals(Paths.get(".."), p1.toAbsolutePath().relativize(p2.toAbsolutePath()));
+        assertEquals(Paths.get("t3"), p2.relativize(p1));
+
+        // Can't be relativized as either of the paths are relative and the other is not.
+        try {
+            p1.relativize(p2.toAbsolutePath());
+            fail();
+        } catch (IllegalArgumentException expected) {}
+
+        try {
+            p1.toAbsolutePath().relativize(p2);
+            fail();
+        } catch (IllegalArgumentException expected) {}
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_relativize_NPE() {
+        dummyPath.relativize(null);
+    }
+
+    @Test
+    public void test_toURI() throws URISyntaxException {
+        assertEquals(new URI("file://" + dummyPath.toAbsolutePath().toString()), dummyPath.toUri());
+        assertEquals(new URI("file:///"), Paths.get("/").toUri());
+        assertEquals(new URI("file:///dir/.."), Paths.get(("/dir/..")).toUri());
+        assertEquals(new URI("file:///../"), Paths.get(("/..")).toUri());
+        assertEquals(new URI("file:///dir/.."), Paths.get(("/dir/..")).toUri());
+        assertEquals(new URI("file:///./"), Paths.get(("/.")).toUri());
+        assertEquals(new URI("file:///dir/."), Paths.get(("/dir/.")).toUri());
+        // For unicode characters.
+        assertEquals(new URI("file:///%E0%A4%B0%E0%A4%BE%E0%A4%B9."), Paths.get(("/राह.")).toUri());
+    }
+
+    @Test
+    public void test_toAbsolutePath() {
+        assertFalse(dummyPath.isAbsolute());
+        assertTrue(dummyPath.toAbsolutePath().isAbsolute());
+    }
+
+    @Test
+    public void test_toRealPath() throws IOException {
+        // When file doesn't exist.
+        try {
+            dummyPath.toRealPath();
+            fail();
+        } catch (NoSuchFileException expected) {}
+        Files.createFile(filesSetup.getTestPath());
+        Path realPath = filesSetup.getTestPath().toRealPath();
+        assertTrue(Files.isSameFile(filesSetup.getTestPath().toAbsolutePath(), realPath));
+        assertTrue(realPath.isAbsolute());
+        assertFalse(Files.isSymbolicLink(realPath));
+
+        Path dir = Paths.get(filesSetup.getTestDir(), "dir1/dir2");
+        Path file = Paths.get(filesSetup.getTestDir(), "dir1/dir2/../../file");
+        Files.createDirectories(dir);
+        Files.createFile(file);
+        realPath = file.toRealPath();
+        assertTrue(Files.isSameFile(file.toAbsolutePath(), realPath));
+        assertTrue(realPath.isAbsolute());
+        assertFalse(Files.isSymbolicLink(realPath));
+
+        // Sym links.
+        Path symLink = Paths.get(filesSetup.getTestDir(), "symlink");
+        Files.createSymbolicLink(symLink, filesSetup.getTestPath().toAbsolutePath());
+        realPath = symLink.toRealPath();
+        assertTrue(Files.isSameFile(symLink, realPath));
+        assertTrue(realPath.isAbsolute());
+        assertFalse(Files.isSymbolicLink(realPath));
+
+        realPath = symLink.toRealPath(LinkOption.NOFOLLOW_LINKS);
+        assertTrue(Files.isSameFile(symLink, realPath));
+        assertTrue(realPath.isAbsolute());
+        assertTrue(Files.isSymbolicLink(realPath));
+    }
+
+    @Test
+    public void test_toFile() {
+        File file = dummyPath.toFile();
+        assertEquals(dummyPath.toAbsolutePath().toString(), file.getAbsolutePath());
+    }
+
+    @Test
+    public void test_register$WatchService$WatchEvent_Kind() throws IOException,
+            InterruptedException {
+        WatchService watchService = FileSystems.getDefault().newWatchService();
+        WatchEvent.Kind<?>[] events = {ENTRY_CREATE, ENTRY_DELETE};
+        Path file = Paths.get(filesSetup.getTestDir(), "directory/file");
+        assertFalse(Files.exists(file));
+        Path directory = Paths.get(filesSetup.getTestDir(), "directory");
+        Files.createDirectories(directory);
+        WatchKey key = directory.register(watchService, events);
+
+        // Creating, modifying and deleting the file.
+        Files.createFile(file);
+        assertTrue(Files.exists(file));
+        // EVENT_MODIFY should not be logged.
+        Files.newOutputStream(file).write("hello".getBytes());
+        Files.delete(file);
+        assertFalse(Files.exists(file));
+
+        assertTrue(key.isValid());
+        assertEquals(directory, key.watchable());
+        List<WatchEvent<?>> eventList = new ArrayList<>();
+
+        // Wait for the events to be recorded by WatchService.
+        while(true) {
+            eventList.addAll(key.pollEvents());
+            if (eventList.size() == 2) break;
+            Thread.sleep(1000);
+        }
+        // Wait for the events to be recorded by watchService.
+        assertEquals(2, eventList.size());
+        assertEquals(ENTRY_CREATE, eventList.get(0).kind());
+        assertEquals(ENTRY_DELETE, eventList.get(1).kind());
+    }
+
+    @Test
+    public void test_register$WatchService$WatchEvent_Kind_NPE() throws IOException,
+            InterruptedException {
+        WatchService watchService = FileSystems.getDefault().newWatchService();
+        WatchEvent.Kind<?>[] events = {ENTRY_CREATE, ENTRY_DELETE};
+        Path directory = Paths.get(filesSetup.getTestDir(), "directory");
+        Files.createDirectories(directory);
+        try {
+            directory.register(null, events);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            directory.register(watchService, (WatchEvent.Kind<?>) null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_register$WatchService$WatchEvent_Kind_Exception() throws IOException {
+        WatchService watchService = FileSystems.getDefault().newWatchService();
+        Path directory = Paths.get(filesSetup.getTestDir(), "directory1");
+        Files.createFile(directory);
+
+        // When file is not a directory.
+        try {
+            directory.register(watchService, ENTRY_CREATE);
+            fail();
+        } catch (NotDirectoryException expected) {}
+
+        // When the events are not supported.
+        Files.deleteIfExists(directory);
+        Files.createDirectories(directory);
+        WatchEvent.Kind<?>[] events = {new NonStandardEvent<>()};
+        try {
+            directory.register(watchService, events);
+            fail();
+        } catch (UnsupportedOperationException expected) {}
+
+        // When the watch service is closed.
+        watchService.close();
+        try {
+            directory.register(watchService, ENTRY_CREATE);
+            fail();
+        } catch (ClosedWatchServiceException expected) {}
+    }
+
+    @Test
+    public void test_register$WatchService$WatchEvent_Kind_Exception_NPE() throws IOException {
+        WatchService watchService = FileSystems.getDefault().newWatchService();
+        Path directory = Paths.get(filesSetup.getTestDir(), "directory1");
+        Files.createDirectories(directory);
+
+        // When file is not a directory.
+        try {
+            directory.register(null, ENTRY_CREATE);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            directory.register(watchService, null);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_register$WatchService$WatchEvent_Kind$WatchEvent_Modifier() throws IOException
+    {
+        WatchService watchService = FileSystems.getDefault().newWatchService();
+        WatchEvent.Kind<?>[] events = {ENTRY_CREATE};
+        Path dirRoot = Paths.get(filesSetup.getTestDir(), "dir");
+        Files.createDirectories(dirRoot);
+        try {
+            WatchKey key = dirRoot.register(watchService, events,
+                    ExtendedWatchEventModifier.FILE_TREE);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+            assertTrue(expected.getMessage().contains("Modifier not supported"));
+        }
+    }
+
+    @Test
+    public void test_register$WatchService$WatchEvent_Kind$WatchEvent_Modifier_NPE()
+            throws IOException {
+        WatchService watchService = FileSystems.getDefault().newWatchService();
+        WatchEvent.Kind<?>[] events = {ENTRY_CREATE};
+        Path dirRoot = Paths.get(filesSetup.getTestDir(), "dir");
+        Files.createDirectories(dirRoot);
+        try {
+            WatchKey key = dirRoot.register(null, events,
+                    ExtendedWatchEventModifier.FILE_TREE);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        try {
+            WatchKey key = dirRoot.register(watchService, null,
+                    ExtendedWatchEventModifier.FILE_TREE);
+            fail();
+        } catch (NullPointerException expected) {}
+    }
+
+    @Test
+    public void test_iterator() {
+        Path p = Paths.get("f1/f2/f3");
+        Iterator<Path> pathIterator = p.iterator();
+        assertEquals(Paths.get("f1"), pathIterator.next());
+        assertEquals(Paths.get("f2"), pathIterator.next());
+        assertEquals(Paths.get("f3"), pathIterator.next());
+        assertFalse(pathIterator.hasNext());
+    }
+
+    @Test
+    public void test_iterator_hasRoot() {
+        Path p = Paths.get("/f1/f2/f3");
+        Iterator<Path> pathIterator = p.iterator();
+        assertEquals(Paths.get("f1"), pathIterator.next());
+        assertEquals(Paths.get("f2"), pathIterator.next());
+        assertEquals(Paths.get("f3"), pathIterator.next());
+        assertFalse(pathIterator.hasNext());
+    }
+
+    @Test
+    public void test_compareTo() {
+        Path p1 = Paths.get("d/a");
+        Path p2 = Paths.get("d/b");
+        assertTrue(p1.compareTo(p2) < 0);
+        assertTrue(p2.compareTo(p1) > 0);
+        assertTrue(p1.compareTo(p1) == 0);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void test_compareTo_NPE() {
+        filesSetup.getTestPath().compareTo(null);
+    }
+
+    @Test
+    public void test_equals() {
+        Path p1 = Paths.get("a/b");
+        Path p2 = Paths.get("a/../a/b");
+        Path p3 = p1.toAbsolutePath();
+        assertFalse(p1.equals(p2));
+        assertTrue(p1.equals(p1));
+        assertFalse(p1.equals(p3));
+    }
+
+    @Test
+    public void test_equals_NPE() {
+        // Should not throw NPE.
+        filesSetup.getTestPath().equals(null);
+    }
+
+    @Test
+    public void test_hashCode() {
+        Path p1 = Paths.get("f1/f2/f3");
+        assertEquals(-642657684, p1.hashCode());
+
+        // With root component.
+        Path p2 = Paths.get("/f1/f2/f3");
+        assertEquals(306328475, p2.hashCode());
+    }
+
+    @Test
+    public void test_toString() {
+        Path p = Paths.get("f1/f2/f3");
+        assertEquals("f1/f2/f3", p.toString());
+
+        p = Paths.get("");
+        assertEquals("", p.toString());
+
+        p = Paths.get("..");
+        assertEquals("..", p.toString());
+
+        p = Paths.get(".");
+        assertEquals(".", p.toString());
+
+        p = Paths.get("dir/");
+        assertEquals("dir", p.toString());
+
+        p = Paths.get("/dir");
+        assertEquals("/dir", p.toString());
+    }
+
+    private static class NonStandardEvent<T> implements WatchEvent.Kind<T> {
+
+        @Override
+        public String name() {
+            return null;
+        }
+
+        @Override
+        public Class<T> type() {
+            return null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/luni/src/test/java/libcore/java/security/DomainLoadStoreParameterTest.java b/luni/src/test/java/libcore/java/security/DomainLoadStoreParameterTest.java
new file mode 100644
index 0000000..2c2e4b8
--- /dev/null
+++ b/luni/src/test/java/libcore/java/security/DomainLoadStoreParameterTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.java.security;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+import java.security.KeyStore;
+import java.security.DomainLoadStoreParameter;
+import java.util.HashMap;
+import java.util.Map;
+
+public class DomainLoadStoreParameterTest extends TestCase {
+    private static final String KEY_STORE_NAME = "keyStoreName";
+    private KeyStore.ProtectionParameter protectionParameter;
+    private URI validConfigurationURI;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        protectionParameter = new KeyStore.ProtectionParameter() {};
+        validConfigurationURI = new URI("http://UriForConfiguration.SergioRulesTheWorld.com/");
+    }
+
+    public void testConstructor_nullValues_throwException() throws Exception {
+        try {
+            new DomainLoadStoreParameter(null /* configuration */,
+                    createNonEmptyParameters(KEY_STORE_NAME, protectionParameter));
+            fail("configuration can't be null when creating DomainLoadStoreParameter");
+        } catch (NullPointerException expected) {
+        }
+
+        try {
+            new DomainLoadStoreParameter(validConfigurationURI, null /* protectionParameters */);
+            fail("protection parameters can't be null when creating DomainLoadStoreParameter");
+        } catch (NullPointerException expected) {
+        }
+    }
+
+    /**
+     * Check that it returns the configuration specified in the constructor.
+     */
+    public void testGetConfiguration() {
+        DomainLoadStoreParameter domainLoadStoreParameter =
+                new DomainLoadStoreParameter(validConfigurationURI,
+                        createNonEmptyParameters(KEY_STORE_NAME, protectionParameter));
+        assertSame(validConfigurationURI, domainLoadStoreParameter.getConfiguration());
+    }
+
+    public void testGetProtectionParams() {
+        Map<String, KeyStore.ProtectionParameter> protectionParameters =
+                createNonEmptyParameters(KEY_STORE_NAME, protectionParameter);
+        DomainLoadStoreParameter domainLoadStoreParameter =
+                new DomainLoadStoreParameter(validConfigurationURI, protectionParameters);
+        Map<String, KeyStore.ProtectionParameter> returnedParams =
+                domainLoadStoreParameter.getProtectionParams();
+        assertEquals(protectionParameters, returnedParams);
+
+        // Trying to add to the returned set throws an exception
+        try {
+            returnedParams.put("some_other_keystore", protectionParameter);
+            fail("The parameters returned by getProtectionParams should be unmodifiable");
+        } catch (UnsupportedOperationException expected) {
+        }
+
+        // Adding to the map passed as parameter doesn't change value in the
+        // {@code DomainLoadStoreParameter}, ie, it holds a copy.
+        Map<String, KeyStore.ProtectionParameter> originalProtectionParameters
+                = new HashMap<>(protectionParameters);
+        protectionParameters.put("some_other_keystore", protectionParameter);
+        assertEquals(originalProtectionParameters,
+                domainLoadStoreParameter.getProtectionParams());
+
+    }
+
+    /**
+     * Getter for the protection parameters in this domain.
+     *
+     * Check that always returns null. Keystore domains do not support a protection parameter.
+     */
+    public void testGetProtectionParameter() {
+        DomainLoadStoreParameter domainLoadStoreParameter =
+                new DomainLoadStoreParameter(validConfigurationURI,
+                        createNonEmptyParameters("keyStoreName", protectionParameter));
+        // Check that always returns null. Keystore domains do not support a protection parameter.
+        assertNull(domainLoadStoreParameter.getProtectionParameter());
+    }
+
+    private Map<String, KeyStore.ProtectionParameter> createNonEmptyParameters(
+            String keyStoreName, KeyStore.ProtectionParameter protectionParameter) {
+        Map<String, KeyStore.ProtectionParameter> protectionParameters = new HashMap<>();
+        protectionParameters.put(keyStoreName, protectionParameter);
+        return protectionParameters;
+    }
+}
diff --git a/luni/src/test/java/libcore/java/security/PrincipalTest.java b/luni/src/test/java/libcore/java/security/PrincipalTest.java
new file mode 100644
index 0000000..de20325
--- /dev/null
+++ b/luni/src/test/java/libcore/java/security/PrincipalTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package java.security;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.HashSet;
+
+import javax.security.auth.Subject;
+
+
+public class PrincipalTest extends TestCase {
+    /**
+     * Default implementation of {@code implies} returns true iff the principal is one
+     * of the subject's principals, or if the subject is null.
+     */
+    public void test_Principal_implies() throws Exception {
+        HashSet<Principal> subjectPrincipals = new HashSet<>();
+        subjectPrincipals.add(new PrincipalWithEqualityByName("a"));
+        subjectPrincipals.add(new PrincipalWithEqualityByName("b"));
+        Subject subject = new Subject(
+                true /* readOnly */,
+                subjectPrincipals,
+                Collections.EMPTY_SET /* pubCredentials */,
+                Collections.EMPTY_SET /* privCredentials */);
+        Principal principalA = new PrincipalWithEqualityByName("a");
+        assertTrue(principalA.implies(subject));
+        Principal principalC = new PrincipalWithEqualityByName("c");
+        assertFalse(principalC.implies(subject));
+        assertFalse(principalC.implies(null));
+    }
+
+    private static class PrincipalWithEqualityByName implements Principal {
+
+        private final String name;
+
+        PrincipalWithEqualityByName(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof PrincipalWithEqualityByName)) {
+                return false;
+            }
+            return this.name.equals(((PrincipalWithEqualityByName) other).getName());
+        }
+    }
+}
\ No newline at end of file
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index 7d9e633..d525cf0 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -43,6 +43,7 @@
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.function.Consumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import javax.crypto.Cipher;
@@ -661,6 +662,119 @@
         }
     }
 
+    // TODO(29631070): this is a general testing mechanism to test other operations that are
+    // going to be added.
+    public void testHashMapOperations() {
+        performHashMapOperationAndCheckResults(
+                PUT /* operation */,
+                mapOf("class1.algorithm1", "impl1") /* initialStatus */,
+                new Pair("class2.algorithm2", "impl2") /* operationParameters */,
+                mapOf("class1.algorithm1", "impl1",
+                        "class2.algorithm2", "impl2"),
+                true /* mustChangeSecurityVersion */);
+        performHashMapOperationAndCheckResults(
+                PUT_ALL,
+                mapOf("class1.algorithm1", "impl1"),
+                mapOf("class2.algorithm2", "impl2", "class3.algorithm3", "impl3"),
+                mapOf("class1.algorithm1", "impl1",
+                        "class2.algorithm2", "impl2",
+                        "class3.algorithm3", "impl3"),
+                true /* mustChangeSecurityVersion */);
+        performHashMapOperationAndCheckResults(
+                REMOVE,
+                mapOf("class1.algorithm1", "impl1"),
+                "class1.algorithm1",
+                mapOf(),
+                true /* mustChangeSecurityVersion */);
+        performHashMapOperationAndCheckResults(
+                REMOVE,
+                mapOf("class1.algorithm1", "impl1"),
+                "class2.algorithm1",
+                mapOf("class1.algorithm1", "impl1"),
+                true /* mustChangeSecurityVersion */);
+    }
+
+    private static class Pair<A, B> {
+        private final A first;
+        private final B second;
+        Pair(A first, B second) {
+            this.first = first;
+            this.second = second;
+        }
+    }
+
+    /* Holder class for the provider parameter and the parameter for the operation. */
+    private static class ProviderAndOperationParameter<T> {
+        private final Provider provider;
+        private final T operationParameters;
+        ProviderAndOperationParameter(Provider p, T o) {
+            provider = p;
+            operationParameters = o;
+        }
+    }
+
+    private static final Consumer<ProviderAndOperationParameter<Pair<String, String>>> PUT =
+            (ProviderAndOperationParameter<Pair<String, String>> provAndParam) ->
+                {
+                    provAndParam.provider.put(provAndParam.operationParameters.first,
+                            provAndParam.operationParameters.second);
+                };
+    private static final Consumer<ProviderAndOperationParameter<Map<String, String>>> PUT_ALL =
+            (ProviderAndOperationParameter<Map<String, String>> provAndParam) ->
+                    provAndParam.provider.putAll(provAndParam.operationParameters);
+    private static final Consumer<ProviderAndOperationParameter<String>> REMOVE =
+            (ProviderAndOperationParameter<String> provAndParam) ->
+                    provAndParam.provider.remove(provAndParam.operationParameters);
+
+
+    private static Map<String, String> mapOf(String... elements) {
+        Map<String, String> ret = new HashMap<String, String>();
+        for (int i = 0; i < elements.length; i += 2) {
+            ret.put(elements[i], elements[i + 1]);
+        }
+        return ret;
+    }
+
+
+    private <A> void performHashMapOperationAndCheckResults(
+            Consumer<ProviderAndOperationParameter<A>> operation,
+            Map<String, String> initialState,
+            A operationParameters,
+            Map<String, String> expectedResult,
+            boolean mustChangeVersion) {
+        Provider p = new MockProvider("MockProvider");
+        // Need to set as registered so that the security version will change on update.
+        p.setRegistered();
+        int securityVersionBeforeOperation = Security.getVersion();
+        p.putAll(initialState);
+
+        // Perform the operation.
+        operation.accept(new ProviderAndOperationParameter<A>(p, operationParameters));
+
+        // Check that elements are correctly mapped to services.
+        HashMap<String, String> services = new HashMap<String, String>();
+        for (Provider.Service s : p.getServices()) {
+            services.put(s.getType() + "." + s.getAlgorithm(), s.getClassName());
+        }
+        assertEquals(expectedResult.entrySet(), services.entrySet());
+
+        // Check that elements are in the provider hash map.
+        // The hash map in the provider has info other than services, include those in the
+        // expected results.
+        HashMap<String, String> hashExpectedResult = new HashMap<String, String>();
+        hashExpectedResult.putAll(expectedResult);
+        hashExpectedResult.put("Provider.id info", p.getInfo());
+        hashExpectedResult.put("Provider.id className", p.getClass().getName());
+        hashExpectedResult.put("Provider.id version", String.valueOf(p.getVersion()));
+        hashExpectedResult.put("Provider.id name", p.getName());
+
+        assertEquals(hashExpectedResult.entrySet(), p.entrySet());
+
+        if (mustChangeVersion) {
+            assertTrue(securityVersionBeforeOperation != Security.getVersion());
+        }
+    }
+
     @SuppressWarnings("serial")
     private static class MockProvider extends Provider {
         public MockProvider(String name) {
diff --git a/luni/src/test/java/libcore/java/security/SecureRandomTest.java b/luni/src/test/java/libcore/java/security/SecureRandomTest.java
index 7eb3b45..2224c70 100644
--- a/luni/src/test/java/libcore/java/security/SecureRandomTest.java
+++ b/luni/src/test/java/libcore/java/security/SecureRandomTest.java
@@ -174,4 +174,40 @@
                     SecureRandom.DEFAULT_SDK_TARGET_FOR_CRYPTO_PROVIDER_WORKAROUND);
         }
     }
+
+    /**
+     * Test that the strong instance is from OpenSSLProvider (as specified in security.properties)
+     * even if there are other providers installed.
+     */
+    public void testGetInstanceStrong() throws Exception {
+        Provider openSSLProvider = null;
+        for (Provider p : Security.getProviders()) {
+            if (p.getClass().getName().equals("com.android.org.conscrypt.OpenSSLProvider")) {
+                openSSLProvider = p;
+            }
+        }
+        if (openSSLProvider == null) {
+            throw new IllegalStateException("OpenSSLProvider not found");
+        }
+
+        // Default comes from the OpenSSLProvider
+        assertEquals(openSSLProvider, SecureRandom.getInstance("SHA1PRNG").getProvider());
+        assertEquals(openSSLProvider, new SecureRandom().getProvider());
+
+        Provider weakProvider = new Provider("MockWeakSecureRandomProvider", 1.0, "For testing") {
+        };
+        weakProvider.put("SecureRandom.SHA1PRNG", ProviderTest.SecureRandom1.class.getName());
+
+        // Insert a different provider with highest priority.
+        try {
+            Security.insertProviderAt(weakProvider, 1);
+            // Default comes from the weak provider.
+            assertEquals(weakProvider, SecureRandom.getInstance("SHA1PRNG").getProvider());
+            assertEquals(weakProvider, new SecureRandom().getProvider());
+            // Strong SecureRandom comes from the OpenSSLProvider.
+            assertEquals(openSSLProvider, SecureRandom.getInstanceStrong().getProvider());
+        } finally {
+            Security.removeProvider(weakProvider.getName());
+        }
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/AbstractCollectionTest.java b/luni/src/test/java/libcore/java/util/AbstractCollectionTest.java
index 2a9e5ef..4f6e170 100644
--- a/luni/src/test/java/libcore/java/util/AbstractCollectionTest.java
+++ b/luni/src/test/java/libcore/java/util/AbstractCollectionTest.java
@@ -18,6 +18,8 @@
 
 import java.io.Serializable;
 import java.util.AbstractCollection;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.ConcurrentHashMap;
 import junit.framework.TestCase;
@@ -55,4 +57,31 @@
     reader.join();
     mutator.join();
   }
+
+  // http://b/31052838
+  public void test_empty_removeAll_null() {
+    try {
+      new EmptyCollection().removeAll(null);
+      fail("Should have thrown");
+    } catch (NullPointerException expected) {
+    }
+  }
+
+  // http://b/31052838
+  public void test_empty_retainAll_null() {
+    try {
+      new EmptyCollection().retainAll(null);
+      fail("Should have thrown");
+    } catch (NullPointerException expected) {
+    }
+  }
+
+  /**
+   * An AbstractCollection that does not override removeAll() / retainAll().
+   */
+  private static class EmptyCollection extends AbstractCollection<Object> {
+    @Override public Iterator iterator() { return Collections.emptySet().iterator(); }
+    @Override public int size() { return 0; }
+  }
+
 }
diff --git a/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java b/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
index deb0626..0116a31 100644
--- a/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
+++ b/luni/src/test/java/libcore/java/util/regex/OldMatcherTest.java
@@ -576,10 +576,10 @@
         final Matcher m = p.matcher("");
 
         ArrayList<Thread> threads = new ArrayList<Thread>();
-        for (int i = 0; i < 10; ++i) {
+        for (int i = 0; i < 5; ++i) {
             Thread t = new Thread(new Runnable() {
                 public void run() {
-                    for (int i = 0; i < 4096; ++i) {
+                    for (int i = 0; i < 1024; ++i) {
                         String s = "some example text";
                         m.reset(s);
                         try {
diff --git a/luni/src/test/java/libcore/net/MimeUtilsTest.java b/luni/src/test/java/libcore/net/MimeUtilsTest.java
index 156c9c4..ac0c017 100644
--- a/luni/src/test/java/libcore/net/MimeUtilsTest.java
+++ b/luni/src/test/java/libcore/net/MimeUtilsTest.java
@@ -18,8 +18,6 @@
 
 import junit.framework.TestCase;
 
-import libcore.net.MimeUtils;
-
 public class MimeUtilsTest extends TestCase {
   public void test_15715370() {
     assertEquals("audio/flac", MimeUtils.guessMimeTypeFromExtension("flac"));
@@ -71,4 +69,11 @@
     assertNull(MimeUtils.guessMimeTypeFromExtension(""));
     assertNull(MimeUtils.guessExtensionFromMimeType("doesnotexist"));
   }
+
+  public void test_30793548() {
+    assertEquals("video/3gpp", MimeUtils.guessMimeTypeFromExtension("3gpp"));
+    assertEquals("video/3gpp", MimeUtils.guessMimeTypeFromExtension("3gp"));
+    assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3gpp2"));
+    assertEquals("video/3gpp2", MimeUtils.guessMimeTypeFromExtension("3g2"));
+  }
 }
diff --git a/non_openjdk_java_files.mk b/non_openjdk_java_files.mk
index 14fd77b..839067e 100644
--- a/non_openjdk_java_files.mk
+++ b/non_openjdk_java_files.mk
@@ -47,6 +47,7 @@
   dalvik/src/main/java/dalvik/system/DalvikLogging.java \
   dalvik/src/main/java/dalvik/system/DexClassLoader.java \
   dalvik/src/main/java/dalvik/system/DexFile.java \
+  dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java \
   dalvik/src/main/java/dalvik/system/DexPathList.java \
   dalvik/src/main/java/dalvik/system/NativeStart.java \
   dalvik/src/main/java/dalvik/system/PathClassLoader.java \
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index 43384f2..1e0a58b 100644
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -226,6 +226,12 @@
     private transient int objectSize;
 
     /**
+     * Aligned object size for allocation fast path. The value is max int if the object is
+     * uninitialized or finalizable, otherwise the aligned object size.
+     */
+    private transient int objectSizeAllocFastPath;
+
+    /**
      * The lower 16 bits is the primitive type value, or 0 if not a primitive type; set for
      * generated primitive classes.
      */
@@ -292,7 +298,6 @@
      * information about modifiers and type parameters
      *
      * @since 1.8
-     * @hide Hidden pending tests
      */
     public String toGenericString() {
         if (isPrimitive()) {
diff --git a/ojluni/src/main/java/java/lang/reflect/Constructor.java b/ojluni/src/main/java/java/lang/reflect/Constructor.java
index 4ac1ca8..3e26cbb 100644
--- a/ojluni/src/main/java/java/lang/reflect/Constructor.java
+++ b/ojluni/src/main/java/java/lang/reflect/Constructor.java
@@ -348,19 +348,6 @@
         return super.isSynthetic();
     }
 
-    String getSignature() {
-        StringBuilder result = new StringBuilder();
-
-        result.append('(');
-        Class<?>[] parameterTypes = getParameterTypes();
-        for (Class<?> parameterType : parameterTypes) {
-            result.append(Types.getSignature(parameterType));
-        }
-        result.append(")V");
-
-        return result.toString();
-    }
-
     /**
      * {@inheritDoc}
      * @throws NullPointerException  {@inheritDoc}
diff --git a/ojluni/src/main/java/java/lang/reflect/Method.java b/ojluni/src/main/java/java/lang/reflect/Method.java
index ec0cdcf..a9f2eb7 100644
--- a/ojluni/src/main/java/java/lang/reflect/Method.java
+++ b/ojluni/src/main/java/java/lang/reflect/Method.java
@@ -487,27 +487,6 @@
     }
 
     /**
-     * Returns the constructor's signature in non-printable form. This is called
-     * (only) from IO native code and needed for deriving the serialVersionUID
-     * of the class
-     *
-     * @return The constructor's signature.
-     */
-    @SuppressWarnings("unused")
-    String getSignature() {
-        StringBuilder result = new StringBuilder();
-
-        result.append('(');
-        Class<?>[] parameterTypes = getParameterTypes();
-        for (Class<?> parameterType : parameterTypes) {
-            result.append(Types.getSignature(parameterType));
-        }
-        result.append(')');
-        result.append(Types.getSignature(getReturnType()));
-
-        return result.toString();
-    }
-    /**
      * Returns true if this and {@code method} have the same name and the same
      * parameters in the same order. Such methods can share implementation if
      * one method's return types is assignable to the other.
diff --git a/ojluni/src/main/java/java/lang/reflect/Modifier.java b/ojluni/src/main/java/java/lang/reflect/Modifier.java
index 760f1a3..e694505 100644
--- a/ojluni/src/main/java/java/lang/reflect/Modifier.java
+++ b/ojluni/src/main/java/java/lang/reflect/Modifier.java
@@ -502,7 +502,6 @@
      *
      * @jls 8.4.1 Formal Parameters
      * @since 1.8
-     * @hide Hidden pending tests
      */
     public static int parameterModifiers() {
         return PARAMETER_MODIFIERS;
diff --git a/ojluni/src/main/java/java/security/DomainLoadStoreParameter.java b/ojluni/src/main/java/java/security/DomainLoadStoreParameter.java
new file mode 100644
index 0000000..bc96975
--- /dev/null
+++ b/ojluni/src/main/java/java/security/DomainLoadStoreParameter.java
@@ -0,0 +1,171 @@
+/*
+ * 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.security;
+
+import java.net.URI;
+import java.util.*;
+import static java.security.KeyStore.*;
+
+/**
+ * Configuration data that specifies the keystores in a keystore domain.
+ * A keystore domain is a collection of keystores that are presented as a
+ * single logical keystore. The configuration data is used during
+ * {@code KeyStore}
+ * {@link KeyStore#load(KeyStore.LoadStoreParameter) load} and
+ * {@link KeyStore#store(KeyStore.LoadStoreParameter) store} operations.
+ * <p>
+ * The following syntax is supported for configuration data:
+ * <pre>{@code
+ *     domain <domainName> [<property> ...] {
+ *         keystore <keystoreName> [<property> ...] ;
+ *         ...
+ *     };
+ *     ...
+ * }</pre>
+ * where {@code domainName} and {@code keystoreName} are identifiers
+ * and {@code property} is a key/value pairing. The key and value are
+ * separated by an 'equals' symbol and the value is enclosed in double
+ * quotes. A property value may be either a printable string or a binary
+ * string of colon-separated pairs of hexadecimal digits. Multi-valued
+ * properties are represented as a comma-separated list of values,
+ * enclosed in square brackets.
+ * See {@link Arrays#toString(java.lang.Object[])}.
+ * <p>
+ * To ensure that keystore entries are uniquely identified, each
+ * entry's alias is prefixed by its {@code keystoreName} followed
+ * by the entry name separator and each {@code keystoreName} must be
+ * unique within its domain. Entry name prefixes are omitted when
+ * storing a keystore.
+ * <p>
+ * Properties are context-sensitive: properties that apply to
+ * all the keystores in a domain are located in the domain clause,
+ * and properties that apply only to a specific keystore are located
+ * in that keystore's clause.
+ * Unless otherwise specified, a property in a keystore clause overrides
+ * a property of the same name in the domain clause. All property names
+ * are case-insensitive. The following properties are supported:
+ * <dl>
+ * <dt> {@code keystoreType="<type>"} </dt>
+ *     <dd> The keystore type. </dd>
+ * <dt> {@code keystoreURI="<url>"} </dt>
+ *     <dd> The keystore location. </dd>
+ * <dt> {@code keystoreProviderName="<name>"} </dt>
+ *     <dd> The name of the keystore's JCE provider. </dd>
+ * <dt> {@code keystorePasswordEnv="<environment-variable>"} </dt>
+ *     <dd> The environment variable that stores a keystore password.
+ *          Alternatively, passwords may be supplied to the constructor
+ *          method in a {@code Map<String, ProtectionParameter>}. </dd>
+ * <dt> {@code entryNameSeparator="<separator>"} </dt>
+ *     <dd> The separator between a keystore name prefix and an entry name.
+ *          When specified, it applies to all the entries in a domain.
+ *          Its default value is a space. </dd>
+ * </dl>
+ * <p>
+ * For example, configuration data for a simple keystore domain
+ * comprising three keystores is shown below:
+ * <pre>
+ *
+ * domain app1 {
+ *     keystore app1-truststore
+ *         keystoreURI="file:///app1/etc/truststore.jks";
+ *
+ *     keystore system-truststore
+ *         keystoreURI="${java.home}/lib/security/cacerts";
+ *
+ *     keystore app1-keystore
+ *         keystoreType="PKCS12"
+ *         keystoreURI="file:///app1/etc/keystore.p12";
+ * };
+ *
+ * </pre>
+ * @since 1.8
+ */
+public final class DomainLoadStoreParameter implements LoadStoreParameter {
+
+    private final URI configuration;
+    private final Map<String,ProtectionParameter> protectionParams;
+
+    /**
+     * Constructs a DomainLoadStoreParameter for a keystore domain with
+     * the parameters used to protect keystore data.
+     *
+     * @param configuration identifier for the domain configuration data.
+     *     The name of the target domain should be specified in the
+     *     {@code java.net.URI} fragment component when it is necessary
+     *     to distinguish between several domain configurations at the
+     *     same location.
+     *
+     * @param protectionParams the map from keystore name to the parameter
+     *     used to protect keystore data.
+     *     A {@code java.util.Collections.EMPTY_MAP} should be used
+     *     when protection parameters are not required or when they have
+     *     been specified by properties in the domain configuration data.
+     *     It is cloned to prevent subsequent modification.
+     *
+     * @exception NullPointerException if {@code configuration} or
+     *     {@code protectionParams} is {@code null}
+     */
+    public DomainLoadStoreParameter(URI configuration,
+        Map<String,ProtectionParameter> protectionParams) {
+        if (configuration == null || protectionParams == null) {
+            throw new NullPointerException("invalid null input");
+        }
+        this.configuration = configuration;
+        this.protectionParams =
+            Collections.unmodifiableMap(new HashMap<>(protectionParams));
+    }
+
+    /**
+     * Gets the identifier for the domain configuration data.
+     *
+     * @return the identifier for the configuration data
+     */
+    public URI getConfiguration() {
+        return configuration;
+    }
+
+    /**
+     * Gets the keystore protection parameters for keystores in this
+     * domain.
+     *
+     * @return an unmodifiable map of keystore names to protection
+     *     parameters
+     */
+    public Map<String,ProtectionParameter> getProtectionParams() {
+        return protectionParams;
+    }
+
+    /**
+     * Gets the keystore protection parameters for this domain.
+     * Keystore domains do not support a protection parameter.
+     *
+     * @return always returns {@code null}
+     */
+    @Override
+    public KeyStore.ProtectionParameter getProtectionParameter() {
+        return null;
+    }
+}
diff --git a/ojluni/src/main/java/java/security/Principal.java b/ojluni/src/main/java/java/security/Principal.java
index fb29aca..a538e70 100644
--- a/ojluni/src/main/java/java/security/Principal.java
+++ b/ojluni/src/main/java/java/security/Principal.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -25,6 +25,8 @@
 
 package java.security;
 
+import javax.security.auth.Subject;
+
 /**
  * This interface represents the abstract notion of a principal, which
  * can be used to represent any entity, such as an individual, a
@@ -45,7 +47,6 @@
      *
      * @return true if the principal passed in is the same as that
      * encapsulated by this principal, and false otherwise.
-
      */
     public boolean equals(Object another);
 
@@ -69,4 +70,25 @@
      * @return the name of this principal.
      */
     public String getName();
+
+    /**
+     * Returns true if the specified subject is implied by this principal.
+     *
+     * <p>The default implementation of this method returns true if
+     * {@code subject} is non-null and contains at least one principal that
+     * is equal to this principal.
+     *
+     * <p>Subclasses may override this with a different implementation, if
+     * necessary.
+     *
+     * @param subject the {@code Subject}
+     * @return true if {@code subject} is non-null and is
+     *              implied by this principal, or false otherwise.
+     * @since 1.8
+     */
+    public default boolean implies(Subject subject) {
+        if (subject == null)
+            return false;
+        return subject.getPrincipals().contains(this);
+    }
 }
diff --git a/ojluni/src/main/java/java/security/PrivateKey.java b/ojluni/src/main/java/java/security/PrivateKey.java
index d836ea3..7d8a7ea 100644
--- a/ojluni/src/main/java/java/security/PrivateKey.java
+++ b/ojluni/src/main/java/java/security/PrivateKey.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -26,13 +26,23 @@
 package java.security;
 
 /**
- * <p>A private key. This interface contains no methods or constants.
- * It merely serves to group (and provide type safety for) all private key
- * interfaces.
- *
+ * A private key.
+ * The purpose of this interface is to group (and provide type safety
+ * for) all private key interfaces.
+ * <p>
  * Note: The specialized private key interfaces extend this interface.
- * See, for example, the DSAPrivateKey interface in
- * <code>java.security.interfaces</code>.
+ * See, for example, the {@code DSAPrivateKey} interface in
+ * {@link java.security.interfaces}.
+ * <p>
+ * Implementations should override the default {@code destroy} and
+ * {@code isDestroyed} methods from the
+ * {@link javax.security.auth.Destroyable} interface to enable
+ * sensitive key information to be destroyed, cleared, or in the case
+ * where such information is immutable, unreferenced.
+ * Finally, since {@code PrivateKey} is {@code Serializable}, implementations
+ * should also override
+ * {@link java.io.ObjectOutputStream#writeObject(java.lang.Object)}
+ * to prevent keys that have been destroyed from being serialized.
  *
  * @see Key
  * @see PublicKey
@@ -46,7 +56,8 @@
  * @author Josh Bloch
  */
 
-public interface PrivateKey extends Key {
+public interface PrivateKey extends Key, javax.security.auth.Destroyable {
+
     // Declare serialVersionUID to be compatible with JDK1.1
     /**
      * The class fingerprint that is set to indicate serialization
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index 784cbf1..81ae9f3 100644
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -464,6 +464,22 @@
         putAll(copy);
     }
 
+    private boolean checkLegacy(Object key) {
+        if (registered) {
+            Security.increaseVersion();
+        }
+        String keyString = (String)key;
+        if (keyString.startsWith("Provider.")) {
+            return false;
+        }
+
+        legacyChanged = true;
+        if (legacyStrings == null) {
+            legacyStrings = new LinkedHashMap<String,String>();
+        }
+        return true;
+    }
+
     /**
      * Copies all of the mappings from the specified Map to this provider.
      * Internal method to be called AFTER the security check has been
@@ -479,37 +495,21 @@
     }
 
     private Object implRemove(Object key) {
-        if (registered) {
-            Security.increaseVersion();
-        }
         if (key instanceof String) {
-            String keyString = (String)key;
-            if (keyString.startsWith("Provider.")) {
+            if (!checkLegacy(key)) {
                 return null;
             }
-            legacyChanged = true;
-            if (legacyStrings == null) {
-                legacyStrings = new LinkedHashMap<String,String>();
-            }
-            legacyStrings.remove(keyString);
+            legacyStrings.remove((String)key);
         }
         return super.remove(key);
     }
 
     private Object implPut(Object key, Object value) {
         if ((key instanceof String) && (value instanceof String)) {
-            String keyString = (String)key;
-            if (keyString.startsWith("Provider.")) {
+            if (!checkLegacy(key)) {
                 return null;
             }
-            if (registered) {
-                Security.increaseVersion();
-            }
-            legacyChanged = true;
-            if (legacyStrings == null) {
-                legacyStrings = new LinkedHashMap<String,String>();
-            }
-            legacyStrings.put(keyString, (String)value);
+            legacyStrings.put((String)key, (String)value);
         }
         return super.put(key, value);
     }
diff --git a/ojluni/src/main/java/java/security/SecureRandom.java b/ojluni/src/main/java/java/security/SecureRandom.java
index 6bf43f1..43bc3a3 100644
--- a/ojluni/src/main/java/java/security/SecureRandom.java
+++ b/ojluni/src/main/java/java/security/SecureRandom.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -26,6 +26,7 @@
 package java.security;
 
 import java.util.*;
+import java.util.regex.*;
 
 import java.security.Provider.Service;
 import java.util.function.Function;
@@ -33,6 +34,9 @@
 import dalvik.system.VMRuntime;
 import sun.security.jca.*;
 import sun.security.jca.GetInstance.Instance;
+/** BEGIN ANDROID-REMOVED: this debugging mechanism is not supported in Android.
+import sun.security.util.Debug;
+*/
 
 /**
  * This class provides a cryptographically strong random number
@@ -51,7 +55,7 @@
  * <i>RFC 1750: Randomness Recommendations for Security</i></a>.
  *
  * <p>A caller obtains a SecureRandom instance via the
- * no-argument constructor or one of the <code>getInstance</code> methods:
+ * no-argument constructor or one of the {@code getInstance} methods:
  *
  * <pre>
  *      SecureRandom random = new SecureRandom();
@@ -72,16 +76,16 @@
  *      random.nextBytes(bytes);
  * </pre>
  *
- * <p> Callers may also invoke the <code>generateSeed</code> method
+ * <p> Callers may also invoke the {@code generateSeed} method
  * to generate a given number of seed bytes (to seed other random number
  * generators, for example):
  * <pre>
  *      byte seed[] = random.generateSeed(20);
  * </pre>
  *
- * Note: Depending on the implementation, the <code>generateSeed</code> and
- * <code>nextBytes</code> methods may block as entropy is being gathered,
- * for example, if they need to read from /dev/random on various unix-like
+ * Note: Depending on the implementation, the {@code generateSeed} and
+ * {@code nextBytes} methods may block as entropy is being gathered,
+ * for example, if they need to read from /dev/random on various Unix-like
  * operating systems.
  *
  * The SHA1PRNG algorithm from the Crypto provider has been deprecated as it was insecure, and also
@@ -98,6 +102,13 @@
 
 public class SecureRandom extends java.util.Random {
 
+    /** BEGIN ANDROID-REMOVED: this debugging mechanism is not supported in Android.
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("securerandom");
+    END ANDROID-REMOVED */
+
     /**
      * The provider.
      *
@@ -146,16 +157,16 @@
      * for information about standard RNG algorithm names.
      *
      * <p> The returned SecureRandom object has not been seeded.  To seed the
-     * returned object, call the <code>setSeed</code> method.
-     * If <code>setSeed</code> is not called, the first call to
-     * <code>nextBytes</code> will force the SecureRandom object to seed itself.
-     * This self-seeding will not occur if <code>setSeed</code> was
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
      * previously called.
      */
     public SecureRandom() {
         /*
          * This call to our superclass constructor will result in a call
-         * to our own <code>setSeed</code> method, which will return
+         * to our own {@code setSeed} method, which will return
          * immediately when it is passed zero.
          */
         super(0);
@@ -235,6 +246,13 @@
         this.secureRandomSpi = secureRandomSpi;
         this.provider = provider;
         this.algorithm = algorithm;
+
+        /** BEGIN ANDROID-REMOVED: this debugging mechanism is not supported in Android.
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("SecureRandom." + algorithm +
+                " algorithm from: " + this.provider.getName());
+        }
+        END ANDROID-REMOVED */
     }
 
     /**
@@ -251,10 +269,10 @@
      * the {@link Security#getProviders() Security.getProviders()} method.
      *
      * <p> The returned SecureRandom object has not been seeded.  To seed the
-     * returned object, call the <code>setSeed</code> method.
-     * If <code>setSeed</code> is not called, the first call to
-     * <code>nextBytes</code> will force the SecureRandom object to seed itself.
-     * This self-seeding will not occur if <code>setSeed</code> was
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
      * previously called.
      *
      * @param algorithm the name of the RNG algorithm.
@@ -327,10 +345,10 @@
      * the {@link Security#getProviders() Security.getProviders()} method.
      *
      * <p> The returned SecureRandom object has not been seeded.  To seed the
-     * returned object, call the <code>setSeed</code> method.
-     * If <code>setSeed</code> is not called, the first call to
-     * <code>nextBytes</code> will force the SecureRandom object to seed itself.
-     * This self-seeding will not occur if <code>setSeed</code> was
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
      * previously called.
      *
      * @param algorithm the name of the RNG algorithm.
@@ -416,10 +434,10 @@
      * does not have to be registered in the provider list.
      *
      * <p> The returned SecureRandom object has not been seeded.  To seed the
-     * returned object, call the <code>setSeed</code> method.
-     * If <code>setSeed</code> is not called, the first call to
-     * <code>nextBytes</code> will force the SecureRandom object to seed itself.
-     * This self-seeding will not occur if <code>setSeed</code> was
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
      * previously called.
      *
      * @param algorithm the name of the RNG algorithm.
@@ -470,7 +488,7 @@
      * Returns the name of the algorithm implemented by this SecureRandom
      * object.
      *
-     * @return the name of the algorithm or <code>unknown</code>
+     * @return the name of the algorithm or {@code unknown}
      *          if the algorithm name cannot be determined.
      * @since 1.5
      */
@@ -493,17 +511,18 @@
 
     /**
      * Reseeds this random object, using the eight bytes contained
-     * in the given <code>long seed</code>. The given seed supplements,
+     * in the given {@code long seed}. The given seed supplements,
      * rather than replaces, the existing seed. Thus, repeated calls
      * are guaranteed never to reduce randomness.
      *
      * <p>This method is defined for compatibility with
-     * <code>java.util.Random</code>.
+     * {@code java.util.Random}.
      *
      * @param seed the seed.
      *
      * @see #getSeed
      */
+    @Override
     public void setSeed(long seed) {
         /*
          * Ignore call from super constructor (as well as any other calls
@@ -519,14 +538,14 @@
     /**
      * Generates a user-specified number of random bytes.
      *
-     * <p> If a call to <code>setSeed</code> had not occurred previously,
+     * <p> If a call to {@code setSeed} had not occurred previously,
      * the first call to this method forces this SecureRandom object
      * to seed itself.  This self-seeding will not occur if
-     * <code>setSeed</code> was previously called.
+     * {@code setSeed} was previously called.
      *
      * @param bytes the array to be filled in with random bytes.
      */
-
+    @Override
     synchronized public void nextBytes(byte[] bytes) {
         secureRandomSpi.engineNextBytes(bytes);
     }
@@ -534,25 +553,27 @@
     /**
      * Generates an integer containing the user-specified number of
      * pseudo-random bits (right justified, with leading zeros).  This
-     * method overrides a <code>java.util.Random</code> method, and serves
+     * method overrides a {@code java.util.Random} method, and serves
      * to provide a source of random bits to all of the methods inherited
-     * from that class (for example, <code>nextInt</code>,
-     * <code>nextLong</code>, and <code>nextFloat</code>).
+     * from that class (for example, {@code nextInt},
+     * {@code nextLong}, and {@code nextFloat}).
      *
      * @param numBits number of pseudo-random bits to be generated, where
-     * 0 <= <code>numBits</code> <= 32.
+     * {@code 0 <= numBits <= 32}.
      *
-     * @return an <code>int</code> containing the user-specified number
+     * @return an {@code int} containing the user-specified number
      * of pseudo-random bits (right justified, with leading zeros).
      */
+    @Override
     final protected int next(int numBits) {
         int numBytes = (numBits+7)/8;
         byte b[] = new byte[numBytes];
         int next = 0;
 
         nextBytes(b);
-        for (int i = 0; i < numBytes; i++)
+        for (int i = 0; i < numBytes; i++) {
             next = (next << 8) + (b[i] & 0xFF);
+        }
 
         return next >>> (numBytes*8 - numBits);
     }
@@ -564,8 +585,8 @@
      *
      * <p>This method is only included for backwards compatibility.
      * The caller is encouraged to use one of the alternative
-     * <code>getInstance</code> methods to obtain a SecureRandom object, and
-     * then call the <code>generateSeed</code> method to obtain seed bytes
+     * {@code getInstance} methods to obtain a SecureRandom object, and
+     * then call the {@code generateSeed} method to obtain seed bytes
      * from that object.
      *
      * @param numBytes the number of seed bytes to generate.
@@ -575,8 +596,9 @@
      * @see #setSeed
      */
     public static byte[] getSeed(int numBytes) {
-        if (seedGenerator == null)
+        if (seedGenerator == null) {
             seedGenerator = new SecureRandom();
+        }
         return seedGenerator.generateSeed(numBytes);
     }
 
@@ -625,6 +647,95 @@
         return null;
     }
 
+    /*
+     * Lazily initialize since Pattern.compile() is heavy.
+     * Effective Java (2nd Edition), Item 71.
+     */
+    private static final class StrongPatternHolder {
+        /*
+         * Entries are alg:prov separated by ,
+         * Allow for prepended/appended whitespace between entries.
+         *
+         * Capture groups:
+         *     1 - alg
+         *     2 - :prov (optional)
+         *     3 - prov (optional)
+         *     4 - ,nextEntry (optional)
+         *     5 - nextEntry (optional)
+         */
+        private static Pattern pattern =
+            Pattern.compile(
+                "\\s*([\\S&&[^:,]]*)(\\:([\\S&&[^,]]*))?\\s*(\\,(.*))?");
+    }
+
+    /**
+     * Returns a {@code SecureRandom} object.
+     *
+     * In Android this is equivalent to get a SHA1PRNG from OpenSSLProvider.
+     *
+     * Some situations require strong random values, such as when
+     * creating high-value/long-lived secrets like RSA public/private
+     * keys.  To help guide applications in selecting a suitable strong
+     * {@code SecureRandom} implementation, Java distributions
+     * include a list of known strong {@code SecureRandom}
+     * implementations in the {@code securerandom.strongAlgorithms}
+     * Security property.
+     * <p>
+     * Every implementation of the Java platform is required to
+     * support at least one strong {@code SecureRandom} implementation.
+     *
+     * @return a strong {@code SecureRandom} implementation
+     *
+     * @throws NoSuchAlgorithmException if no algorithm is available
+     *
+     * @see Security#getProperty(String)
+     *
+     * @since 1.8
+     */
+    public static SecureRandom getInstanceStrong()
+            throws NoSuchAlgorithmException {
+        String property = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    return Security.getProperty(
+                        "securerandom.strongAlgorithms");
+                }
+            });
+
+        if ((property == null) || (property.length() == 0)) {
+            throw new NoSuchAlgorithmException(
+                "Null/empty securerandom.strongAlgorithms Security Property");
+        }
+
+        String remainder = property;
+        while (remainder != null) {
+            Matcher m;
+            if ((m = StrongPatternHolder.pattern.matcher(
+                    remainder)).matches()) {
+
+                String alg = m.group(1);
+                String prov = m.group(3);
+
+                try {
+                    if (prov == null) {
+                        return SecureRandom.getInstance(alg);
+                    } else {
+                        return SecureRandom.getInstance(alg, prov);
+                    }
+                } catch (NoSuchAlgorithmException |
+                        NoSuchProviderException e) {
+                }
+                remainder = m.group(5);
+            } else {
+                remainder = null;
+            }
+        }
+
+        throw new NoSuchAlgorithmException(
+            "No strong SecureRandom impls available: " + property);
+    }
+
     // Declare serialVersionUID to be compatible with JDK1.1
     static final long serialVersionUID = 4940670005562187L;
 
diff --git a/ojluni/src/main/java/java/util/WeakHashMap.java b/ojluni/src/main/java/java/util/WeakHashMap.java
index 3e82610..e40a1dc 100644
--- a/ojluni/src/main/java/java/util/WeakHashMap.java
+++ b/ojluni/src/main/java/java/util/WeakHashMap.java
@@ -25,6 +25,7 @@
  */
 
 package java.util;
+
 import java.lang.ref.WeakReference;
 import java.lang.ref.ReferenceQueue;
 import java.util.function.BiConsumer;
@@ -191,7 +192,7 @@
 
     @SuppressWarnings("unchecked")
     private Entry<K,V>[] newTable(int n) {
-        return (Entry<K,V>[]) new Entry[n];
+        return (Entry<K,V>[]) new Entry<?,?>[n];
     }
 
     /**
@@ -287,6 +288,23 @@
     }
 
     /**
+     * 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) {
@@ -375,7 +393,7 @@
      */
     public V get(Object key) {
         Object k = maskNull(key);
-        int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
+        int h = hash(k);
         Entry<K,V>[] tab = getTable();
         int index = indexFor(h, tab.length);
         Entry<K,V> e = tab[index];
@@ -405,7 +423,7 @@
      */
     Entry<K,V> getEntry(Object key) {
         Object k = maskNull(key);
-        int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
+        int h = hash(k);
         Entry<K,V>[] tab = getTable();
         int index = indexFor(h, tab.length);
         Entry<K,V> e = tab[index];
@@ -428,7 +446,7 @@
      */
     public V put(K key, V value) {
         Object k = maskNull(key);
-        int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
+        int h = hash(k);
         Entry<K,V>[] tab = getTable();
         int i = indexFor(h, tab.length);
 
@@ -570,7 +588,7 @@
      */
     public V remove(Object key) {
         Object k = maskNull(key);
-        int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
+        int h = hash(k);
         Entry<K,V>[] tab = getTable();
         int i = indexFor(h, tab.length);
         Entry<K,V> prev = tab[i];
@@ -601,7 +619,7 @@
         Entry<K,V>[] tab = getTable();
         Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
         Object k = maskNull(entry.getKey());
-        int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
+        int h = hash(k);
         int i = indexFor(h, tab.length);
         Entry<K,V> prev = tab[i];
         Entry<K,V> e = prev;
@@ -683,7 +701,7 @@
      */
     private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
         V value;
-        int hash;
+        final int hash;
         Entry<K,V> next;
 
         /**
@@ -731,8 +749,7 @@
         public int hashCode() {
             K k = getKey();
             V v = getValue();
-            return ((k==null ? 0 : k.hashCode()) ^
-                    (v==null ? 0 : v.hashCode()));
+            return Objects.hashCode(k) ^ Objects.hashCode(v);
         }
 
         public String toString() {
@@ -742,21 +759,21 @@
 
     private abstract class HashIterator<T> implements Iterator<T> {
         private int index;
-        private Entry<K,V> entry = null;
-        private Entry<K,V> lastReturned = null;
+        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 = null;
+        private Object nextKey;
 
         /**
          * Strong reference needed to avoid disappearance of key
          * between nextEntry() and any use of the entry
          */
-        private Object currentKey = null;
+        private Object currentKey;
 
         HashIterator() {
             index = isEmpty() ? 0 : table.length;
@@ -831,7 +848,7 @@
 
     // Views
 
-    private transient Set<Map.Entry<K,V>> entrySet = null;
+    private transient Set<Map.Entry<K,V>> entrySet;
 
     /**
      * Returns a {@link Set} view of the keys contained in this map.
@@ -1014,7 +1031,7 @@
         Objects.requireNonNull(function);
         int expectedModCount = modCount;
 
-        Entry<K, V>[] tab = getTable();
+        Entry<K, V>[] tab = getTable();;
         for (Entry<K, V> entry : tab) {
             while (entry != null) {
                 Object key = entry.get();
@@ -1030,7 +1047,6 @@
         }
     }
 
-
     /**
      * Similar form as other hash Spliterators, but skips dead
      * elements.
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 89ae10f..b0d574e 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -572,6 +572,7 @@
     ojluni/src/main/java/java/security/DigestInputStream.java \
     ojluni/src/main/java/java/security/DigestOutputStream.java \
     ojluni/src/main/java/java/security/DomainCombiner.java \
+    ojluni/src/main/java/java/security/DomainLoadStoreParameter.java \
     ojluni/src/main/java/java/security/GeneralSecurityException.java \
     ojluni/src/main/java/java/security/GuardedObject.java \
     ojluni/src/main/java/java/security/Guard.java \