Merge "Revert "Enable String compression.""
diff --git a/dex/src/main/java/com/android/dex/DexFormat.java b/dex/src/main/java/com/android/dex/DexFormat.java
index c598eee..1367f65 100644
--- a/dex/src/main/java/com/android/dex/DexFormat.java
+++ b/dex/src/main/java/com/android/dex/DexFormat.java
@@ -51,7 +51,12 @@
      * completed and is not considered a valid dex file format.
      * </p>
      */
-    public static final String VERSION_CURRENT = "037";
+    public static final String VERSION_CURRENT = "038";
+
+    /**
+     * Versions currently supported.
+     */
+    static final String [] VERSIONS_SUPPORTED = { "035", "037", "038" };
 
     /** dex file version number for API level 13 and earlier */
     public static final String VERSION_FOR_API_13 = "035";
@@ -91,9 +96,13 @@
 
         String version = "" + ((char) magic[4]) + ((char) magic[5]) +((char) magic[6]);
 
-        if (version.equals(VERSION_CURRENT)) {
-            return API_CURRENT;
-        } else if (version.equals(VERSION_FOR_API_13)) {
+        for (String supported : VERSIONS_SUPPORTED) {
+            if (version.equals(supported)) {
+                return API_CURRENT;
+            }
+        }
+
+        if (version.equals(VERSION_FOR_API_13)) {
             return API_NO_EXTENDED_OPCODES;
         }
 
diff --git a/dex/src/main/java/com/android/dex/TableOfContents.java b/dex/src/main/java/com/android/dex/TableOfContents.java
index 583f195..b33a749 100644
--- a/dex/src/main/java/com/android/dex/TableOfContents.java
+++ b/dex/src/main/java/com/android/dex/TableOfContents.java
@@ -36,6 +36,8 @@
     public final Section fieldIds = new Section(0x0004);
     public final Section methodIds = new Section(0x0005);
     public final Section classDefs = new Section(0x0006);
+    public final Section callSiteIds = new Section(0x0007);
+    public final Section methodHandles = new Section(0x0008);
     public final Section mapList = new Section(0x1000);
     public final Section typeLists = new Section(0x1001);
     public final Section annotationSetRefLists = new Section(0x1002);
@@ -48,9 +50,9 @@
     public final Section encodedArrays = new Section(0x2005);
     public final Section annotationsDirectories = new Section(0x2006);
     public final Section[] sections = {
-            header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList,
-            typeLists, annotationSetRefLists, annotationSets, classDatas, codes, stringDatas,
-            debugInfos, annotations, encodedArrays, annotationsDirectories
+        header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList, callSiteIds,
+        methodHandles, typeLists, annotationSetRefLists, annotationSets, classDatas, codes,
+        stringDatas, debugInfos, annotations, encodedArrays, annotationsDirectories
     };
 
     public int apiLevel;
@@ -76,7 +78,12 @@
         byte[] magic = headerIn.readByteArray(8);
 
         if (!DexFormat.isSupportedDexMagic(magic)) {
-            throw new DexException("Unexpected magic: " + Arrays.toString(magic));
+            String msg =
+                    String.format("Unexpected magic: [0x%02x, 0x%02x, 0x%02x, 0x%02x, "
+                                  + "0x%02x, 0x%02x, 0x%02x, 0x%02x]",
+                                  magic[0], magic[1], magic[2], magic[3],
+                                  magic[4], magic[5], magic[6], magic[7]);
+            throw new DexException(msg);
         }
 
         apiLevel = DexFormat.magicToApi(magic);
diff --git a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
index 13e9317..5a84c8e 100644
--- a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
+++ b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
@@ -106,6 +106,9 @@
 
         // Hardcode default value for AVA. b/28174137
         { "com.sun.security.preserveOldDCEncoding", null },
+
+        // Hardcode default value for LogManager. b/28174137
+        { "java.util.logging.manager", null },
     };
 }
 
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index 8465a24..fb55475 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -48,12 +48,24 @@
     private long dexFile;
 
     /**
+     * References to CallSite (C array pointer) as they become resolved following
+     * interpreter semantics.
+     */
+    private long resolvedCallSites;
+
+    /**
      * References to fields (C array pointer) as they become resolved following
      * interpreter semantics. May refer to fields defined in other dex files.
      */
     private long resolvedFields;
 
     /**
+     * References to MethodType (C array pointer) as they become resolved following
+     * interpreter semantics.
+     */
+    private long resolvedMethodTypes;
+
+    /**
      * References to methods (C array pointer) as they become resolved following
      * interpreter semantics. May refer to methods defined in other dex files.
      */
@@ -72,10 +84,9 @@
     private long strings;
 
     /**
-     * References to MethodType (C array pointer) as they become resolved following
-     * interpreter semantics.
+     * The number of elements in the native call sites array.
      */
-    private long resolvedMethodTypes;
+    private int numResolvedCallSites;
 
     /**
      * The number of elements in the native resolvedFields array.
@@ -83,6 +94,11 @@
     private int numResolvedFields;
 
     /**
+     * The number of elements in the native method types array.
+     */
+    private int numResolvedMethodTypes;
+
+    /**
      * The number of elements in the native resolvedMethods array.
      */
     private int numResolvedMethods;
@@ -97,11 +113,6 @@
      */
     private int numStrings;
 
-    /**
-     * The number of elements in the native method types array.
-     */
-    private int numResolvedMethodTypes;
-
     // Only created by the VM.
     private DexCache() {}
 
diff --git a/luni/src/test/java/libcore/java/lang/OldSystemTest.java b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
index dc5741f..ad7151d 100644
--- a/luni/src/test/java/libcore/java/lang/OldSystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
@@ -257,13 +257,9 @@
 
     public void test_gc() {
         Runtime rt =  Runtime.getRuntime();
-        Vector<StringBuffer> vec = new Vector<StringBuffer>();
-        long beforeTest = rt.totalMemory() - rt.freeMemory();
-        while (rt.totalMemory() - rt.freeMemory() < beforeTest * 2) {
-             vec.add(new StringBuffer(1000));
-        }
+        byte[] data = new byte[2 * 1024 * 1024];
         long beforeGC = rt.totalMemory() - rt.freeMemory();
-        vec = null;
+        data = null;
         System.gc();
         System.runFinalization();
         long afterGC = rt.totalMemory() - rt.freeMemory();
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
index 4c65161..8e75f71 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
@@ -16,6 +16,7 @@
 
 package libcore.java.lang.invoke;
 
+import java.lang.Thread;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -26,6 +27,8 @@
 
 public class MethodHandleCombinersTest extends TestCase {
 
+    static final int TEST_THREAD_ITERATIONS = 1000;
+
     public static void testThrowException() throws Throwable {
         MethodHandle handle = MethodHandles.throwException(String.class,
                 IllegalArgumentException.class);
@@ -1633,4 +1636,260 @@
         } catch (IllegalArgumentException expected) {
         }
     }
+
+    // An exception thrown on worker threads and re-thrown on the main thread.
+    static Throwable workerException = null;
+
+    private static void invokeMultiThreaded(final MethodHandle mh) throws Throwable {
+        // Create enough worker threads to be oversubscribed in bid to force some parallelism.
+        final int threadCount = Runtime.getRuntime().availableProcessors() + 1;
+        final Thread threads [] = new Thread [threadCount];
+
+        // Launch worker threads and iterate invoking method handle.
+        for (int i = 0; i < threadCount; ++i) {
+            threads[i] = new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            for (int j = 0; j < TEST_THREAD_ITERATIONS; ++j) {
+                                mh.invoke();
+                            }
+                        } catch (Throwable t) {
+                            workerException = t;
+                            fail("Unexpected exception " + workerException);
+                        }
+                    }});
+            threads[i].start();
+        }
+
+        // Wait for completion
+        for (int i = 0; i < threadCount; ++i) {
+            threads[i].join();
+        }
+
+        // Fail on main thread to avoid test appearing to complete successfully.
+        Throwable t = workerException;
+        workerException = null;
+        if (t != null) {
+            throw t;
+        }
+    }
+
+    public static void testDropInsertArgumentsMultithreaded() throws Throwable {
+        MethodHandle delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                "dropArguments_delegate",
+                MethodType.methodType(void.class, new Class<?>[]{String.class, long.class}));
+        MethodHandle mh = MethodHandles.dropArguments(delegate, 0, int.class, Object.class);
+        mh = MethodHandles.insertArguments(mh, 0, 3333, "bogon", "foo", 42);
+        invokeMultiThreaded(mh);
+    }
+
+    private static void exceptionHandler_delegate(NumberFormatException e, int x, int y, long z)
+            throws Throwable {
+        assertEquals(e.getClass(), NumberFormatException.class);
+        assertEquals(e.getMessage(), "fake");
+        assertEquals(x, 66);
+        assertEquals(y, 51);
+        assertEquals(z, 20000000000l);
+    }
+
+    public static void testThrowCatchExceptionMultiThreaded() throws Throwable {
+        MethodHandle thrower = MethodHandles.throwException(void.class,
+                                                            NumberFormatException.class);
+        thrower = MethodHandles.dropArguments(thrower, 0, int.class, int.class, long.class);
+        MethodHandle handler = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "exceptionHandler_delegate",
+            MethodType.methodType(void.class, NumberFormatException.class,
+                                  int.class, int.class, long.class));
+        MethodHandle catcher =
+            MethodHandles.catchException(thrower, NumberFormatException.class, handler);
+        MethodHandle caller = MethodHandles.insertArguments(catcher, 0, 66, 51, 20000000000l,
+                                                            new NumberFormatException("fake"));
+        invokeMultiThreaded(caller);
+    }
+
+    private static void testTargetAndFallback_delegate(MethodHandle mh) throws Throwable {
+        String actual = (String) mh.invoke("target", 42, 56);
+        assertEquals("target", actual);
+        actual = (String) mh.invoke("blah", 41, 56);
+        assertEquals("fallback", actual);
+    }
+
+    public static void testGuardWithTestMultiThreaded() throws Throwable {
+        MethodHandle test =
+                MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                                                  "testGuardWithTest_test",
+                                                  MethodType.methodType(boolean.class,
+                                                                        new Class<?>[]{String.class,
+                                                                                    long.class}));
+        final MethodType type = MethodType.methodType(String.class,
+                new Class<?>[]{String.class, long.class, int.class});
+        final MethodHandle target =
+                MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                                                  "testGuardWithTest_target", type);
+        final MethodHandle fallback =
+                MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+                                                  "testGuardWithTest_fallback", type);
+        MethodHandle adapter = MethodHandles.guardWithTest(test, target, fallback);
+        MethodHandle tester = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class,
+            "testTargetAndFallback_delegate",
+            MethodType.methodType(void.class, MethodHandle.class));
+        invokeMultiThreaded(MethodHandles.insertArguments(tester, 0, adapter));
+    }
+
+    private static void arrayElementSetterGetter_delegate(MethodHandle getter,
+                                                          MethodHandle setter,
+                                                          int [] values)
+            throws Throwable{
+        for (int i = 0; i < values.length; ++i) {
+            int value = i * 13;
+            setter.invoke(values, i, value);
+            assertEquals(values[i], value);
+            assertEquals(getter.invoke(values, i), values[i]);
+        }
+    }
+
+    public static void testReferenceArrayGetterMultiThreaded() throws Throwable {
+        MethodHandle getter = MethodHandles.arrayElementGetter(int[].class);
+        MethodHandle setter = MethodHandles.arrayElementSetter(int[].class);
+        MethodHandle mh = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class,
+            "arrayElementSetterGetter_delegate",
+            MethodType.methodType(void.class, MethodHandle.class, MethodHandle.class, int[].class));
+        mh = MethodHandles.insertArguments(mh, 0, getter, setter,
+                                           new int[] { 1, 2, 3, 5, 7, 11, 13, 17, 19, 23 });
+        invokeMultiThreaded(mh);
+    }
+
+    private static void checkConstant_delegate(MethodHandle mh, double value) throws Throwable {
+        assertEquals(mh.invoke(), value);
+    }
+
+    public static void testConstantMultithreaded() throws Throwable {
+        final double value = 7.77e77;
+        MethodHandle constant = MethodHandles.constant(double.class, value);
+        MethodHandle mh = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkConstant_delegate",
+            MethodType.methodType(void.class, MethodHandle.class, double.class));
+        mh = MethodHandles.insertArguments(mh, 0, constant, value);
+        invokeMultiThreaded(mh);
+    }
+
+    private static void checkIdentity_delegate(MethodHandle mh, char value) throws Throwable {
+        assertEquals(mh.invoke(value), value);
+    }
+
+    public static void testIdentityMultiThreaded() throws Throwable {
+        final char value = 'z';
+        MethodHandle identity = MethodHandles.identity(char.class);
+        MethodHandle mh = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkIdentity_delegate",
+            MethodType.methodType(void.class, MethodHandle.class, char.class));
+        mh = MethodHandles.insertArguments(mh, 0, identity, value);
+        invokeMultiThreaded(mh);
+    }
+
+    private static int multiplyByTwo(int x) { return x * 2; }
+    private static int divideByTwo(int x) { return x / 2; }
+    private static void assertMethodHandleInvokeEquals(MethodHandle mh, int value) throws Throwable{
+        assertEquals(mh.invoke(value), value);
+    }
+
+    public static void testFilterReturnValueMultiThreaded() throws Throwable {
+        MethodHandle target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "multiplyByTwo",
+            MethodType.methodType(int.class, int.class));
+        MethodHandle filter = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "divideByTwo",
+            MethodType.methodType(int.class, int.class));
+        MethodHandle filtered = MethodHandles.filterReturnValue(target, filter);
+        assertEquals(filtered.invoke(33), 33);
+        MethodHandle mh = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "assertMethodHandleInvokeEquals",
+            MethodType.methodType(void.class, MethodHandle.class, int.class));
+        invokeMultiThreaded(MethodHandles.insertArguments(mh, 0, filtered, 77));
+    }
+
+    public static void compareStringAndFloat(String s, float f) {
+        assertEquals(s, Float.toString(f));
+    }
+
+    public static void testPermuteArgumentsMultiThreaded() throws Throwable {
+        MethodHandle mh = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "compareStringAndFloat",
+            MethodType.methodType(void.class, String.class, float.class));
+        mh = MethodHandles.permuteArguments(
+            mh, MethodType.methodType(void.class, float.class, String.class), 1, 0);
+        invokeMultiThreaded(MethodHandles.insertArguments(mh, 0, 2.22f, "2.22"));
+    }
+
+    public static void testSpreadInvokerMultiThreaded() throws Throwable {
+        MethodType methodType = MethodType.methodType(
+            int.class, new Class<?>[]{String.class, String.class, String.class});
+        MethodHandle delegate = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "spreadReferences", methodType);
+        MethodHandle mh = delegate.asSpreader(String[].class, 3);
+        mh = MethodHandles.insertArguments(mh, 0, new Object[] { new String [] { "a", "b", "c" }});
+        invokeMultiThreaded(mh);
+    }
+
+    public static void testCollectorMultiThreaded() throws Throwable {
+        MethodHandle trailingRef = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "collectCharSequence",
+                MethodType.methodType(int.class, String.class, CharSequence[].class));
+        MethodHandle mh = trailingRef.asCollector(String[].class, 2);
+        mh = MethodHandles.insertArguments(mh, 0, "a", "b", "c");
+        invokeMultiThreaded(mh);
+    }
+
+    public static void testFilterArgumentsMultiThreaded() throws Throwable {
+        MethodHandle filter1 = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "filter1",
+            MethodType.methodType(String.class, char.class));
+        MethodHandle filter2 = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "filter2",
+            MethodType.methodType(char.class, String.class));
+        MethodHandle target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "filterTarget",
+            MethodType.methodType(int.class, String.class, char.class, String.class, char.class));
+        MethodHandle adapter = MethodHandles.filterArguments(target, 2, filter1, filter2);
+        invokeMultiThreaded(MethodHandles.insertArguments(adapter, 0, "a", 'b', 'c', "dXXXXX"));
+    }
+
+    private static void checkStringResult_delegate(MethodHandle mh,
+                                                   String expected) throws Throwable {
+        assertEquals(mh.invoke(), expected);
+    }
+
+    public static void testCollectArgumentsMultiThreaded() throws Throwable {
+        MethodHandle filter = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "filter",
+            MethodType.methodType(String.class, char.class, char.class));
+        MethodHandle target = MethodHandles.lookup().findStatic(
+                MethodHandleCombinersTest.class, "target",
+                MethodType.methodType(String.class, String.class, String.class, String.class));
+        MethodHandle collect = MethodHandles.collectArguments(target, 2, filter);
+        collect = MethodHandles.insertArguments(collect, 0, "a", "b", 'c', 'd');
+        MethodHandle mh = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkStringResult_delegate",
+            MethodType.methodType(void.class, MethodHandle.class, String.class));
+        invokeMultiThreaded(MethodHandles.insertArguments(mh, 0, collect, "a: a, b: b, c: c+d"));
+    }
+
+    public static void testFoldArgumentsMultiThreaded() throws Throwable {
+        MethodHandle target = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "foldTarget",
+            MethodType.methodType(String.class, String.class,
+                                  char.class, char.class, String.class));
+        MethodHandle filter = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "foldFilter",
+            MethodType.methodType(String.class, char.class, char.class));
+        MethodHandle adapter = MethodHandles.foldArguments(target, filter);
+        adapter = MethodHandles.insertArguments(adapter, 0, 'c', 'd', "e");
+        MethodHandle mh = MethodHandles.lookup().findStatic(
+            MethodHandleCombinersTest.class, "checkStringResult_delegate",
+            MethodType.methodType(void.class, MethodHandle.class, String.class));
+        invokeMultiThreaded(MethodHandles.insertArguments(mh, 0, adapter, "a: c+d ,b:c ,c:d ,d:e"));
+    }
 }
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
index 8381cbd..774f102 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
@@ -965,7 +965,7 @@
         assertEquals(testPattern, s);
     }
 
-    private static void testReferenceReturnValueConversions() throws Throwable {
+    public void testReferenceReturnValueConversions() throws Throwable {
         MethodHandle mh = MethodHandles.lookup().findStatic(
                 Float.class, "valueOf", MethodType.methodType(Float.class, String.class));
 
@@ -1023,7 +1023,7 @@
         assertEquals(0, c.compareTo(Float.valueOf(2.125f)));
     }
 
-    private static void testPrimitiveReturnValueConversions() throws Throwable {
+    public void testPrimitiveReturnValueConversions() throws Throwable {
         MethodHandle mh = MethodHandles.lookup().findStatic(
                 Math.class, "min", MethodType.methodType(int.class, int.class, int.class));
 
@@ -1155,11 +1155,6 @@
         }
     }
 
-    public static void testReturnValueConversions() throws Throwable {
-        testReferenceReturnValueConversions();
-        testPrimitiveReturnValueConversions();
-    }
-
     public static class BaseVariableArityTester {
         public String update(Float f0, Float... floats) {
             return "base " + f0 + ", " + Arrays.toString(floats);
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index ac64315..ffba98a 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -35,6 +35,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -45,6 +46,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -85,6 +87,20 @@
             Set<Provider.Service> services = provider.getServices();
             assertNotNull(services);
             assertFalse(services.isEmpty());
+            if (LOG_DEBUG) {
+                Set<Provider.Service> originalServices = services;
+                services = new TreeSet<Provider.Service>(
+                        new Comparator<Provider.Service>() {
+                            public int compare(Provider.Service a, Provider.Service b) {
+                                int typeCompare = a.getType().compareTo(b.getType());
+                                if (typeCompare != 0) {
+                                    return typeCompare;
+                                }
+                                return a.getAlgorithm().compareTo(b.getAlgorithm());
+                            }
+                        });
+                services.addAll(originalServices);
+            }
 
             for (Provider.Service service : services) {
                 String type = service.getType();
diff --git a/luni/src/test/java/libcore/java/util/DateTest.java b/luni/src/test/java/libcore/java/util/DateTest.java
index 6185f12..df86a38 100644
--- a/luni/src/test/java/libcore/java/util/DateTest.java
+++ b/luni/src/test/java/libcore/java/util/DateTest.java
@@ -81,49 +81,63 @@
     }
 
     /**
-     * The minimum long value below which {@link Instant#toEpochMilli()} will
-     * throw is not clearly documented. This test discovers if that minimum
-     * value ever changes, and also checks that it is also the minimum Instant
-     * (at a millisecond boundary) that can be converted to a Date.
+     * Test that conversion between Date and Instant works when the
+     * Instant is based on a millisecond value (and thus can be
+     * represented as a Date).
      */
-    public void test_convertFromInstant_lowerBound() {
-        // smallest millisecond Instant that can be converted to Date
-        long minConvertible = -9223372036854775000L;
+    public void test_convertFromAndToInstant_milliseconds() {
+        check_convertFromAndToInstant_milliseconds(Long.MIN_VALUE);
+        check_convertFromAndToInstant_milliseconds(Long.MAX_VALUE);
 
-        // show that this value is < 1 sec away from Long.MIN_VALUE
-        assertEquals(Long.MIN_VALUE + 808, minConvertible);
-
-        Instant inBound = Instant.ofEpochMilli(minConvertible);
-        assertEquals(new Date(minConvertible), Date.from(inBound));
-        assertEquals(minConvertible, inBound.toEpochMilli());
-
-        Instant outOfBound = Instant.ofEpochMilli(minConvertible - 1);
-        try {
-            Date.from(outOfBound);
-            fail();
-        } catch (IllegalArgumentException expected) {
-            assertEquals(ArithmeticException.class, expected.getCause().getClass());
-        }
-
-        try {
-            outOfBound.toEpochMilli();
-            fail();
-        } catch (ArithmeticException expected) {
-
-        }
+        check_convertFromAndToInstant_milliseconds(-1);
+        check_convertFromAndToInstant_milliseconds(0);
+        check_convertFromAndToInstant_milliseconds(123456789);
     }
 
-    public void test_convertFromInstant_upperBound() {
-        Date.from(Instant.ofEpochMilli(Long.MAX_VALUE));
+    private static void check_convertFromAndToInstant_milliseconds(long millis) {
+        assertEquals(new Date(millis), Date.from(Instant.ofEpochMilli(millis)));
+        assertEquals(new Date(millis).toInstant(), Instant.ofEpochMilli(millis));
+    }
 
-        Date.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 0));
-        Date.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 999999999));
-        Instant outOfBound = Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1, 0);
+    /**
+     * Checks the minimum/maximum Instant values (based on seconds and
+     * nanos) that can be converted to a Date, i.e. that can be converted
+     * to milliseconds without overflowing a long. Note that the rounding
+     * is such that the lower bound is exactly Long.MIN_VALUE msec whereas
+     * the upper bound is 999,999 nanos beyond Long.MAX_VALUE msec. This
+     * makes some sense in that the magnitude of the upper/lower bound
+     * nanos differ only by 1, just like the magnitude of Long.MIN_VALUE /
+     * MAX_VALUE differ only by 1.
+     */
+    public void test_convertFromInstant_secondsAndNanos() {
+        // Documentation for how the below bounds relate to long boundaries for milliseconds
+        assertEquals(-808, Long.MIN_VALUE % 1000);
+        assertEquals(807, Long.MAX_VALUE % 1000);
+
+        // Lower bound
+        long minSecond = Long.MIN_VALUE / 1000;
+        Date.from(Instant.ofEpochSecond(minSecond));
+        // This instant exactly corresponds to Long.MIN_VALUE msec because
+        // Long.MIN_VALUE % 1000 == -808 == (-1000 + 192)
+        Date.from(Instant.ofEpochSecond(minSecond - 1, 192000000));
+        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(minSecond - 1, 0));
+        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(minSecond - 1, 191999999));
+
+        // Upper bound
+        long maxSecond = Long.MAX_VALUE / 1000;
+        Date.from(Instant.ofEpochSecond(maxSecond, 0));
+        // This Instant is 999,999 nanos beyond Long.MAX_VALUE msec because
+        // (Long.MAX_VALUE % 1000) == 807
+        Date.from(Instant.ofEpochSecond(maxSecond, 807999999));
+        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(maxSecond + 1, 0));
+        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(maxSecond, 808000000));
+    }
+
+    private static void assertArithmeticOverflowDateFrom(Instant instant) {
         try {
-            Date.from(outOfBound);
-            fail();
+            Date.from(instant);
+            fail(instant + " should not have been convertible to Date");
         } catch (IllegalArgumentException expected) {
-            assertEquals(ArithmeticException.class, expected.getCause().getClass());
         }
     }
 
diff --git a/luni/src/test/java/libcore/java/util/HashtableTest.java b/luni/src/test/java/libcore/java/util/HashtableTest.java
index 4a61147..b7a3202 100644
--- a/luni/src/test/java/libcore/java/util/HashtableTest.java
+++ b/luni/src/test/java/libcore/java/util/HashtableTest.java
@@ -20,6 +20,11 @@
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Field;
 
 public class HashtableTest extends junit.framework.TestCase {
 
@@ -130,4 +135,30 @@
         } catch (ClassNotFoundException expected) {
         }
     }
+
+    public void test_deserializedArrayLength() throws Exception {
+        final float loadFactor = 0.75f;
+        final int entriesCount = 100;
+        // Create table
+        Hashtable<Integer, Integer> hashtable1 = new Hashtable<>(1, loadFactor);
+        for (int i = 0; i < entriesCount; i++) {
+            hashtable1.put(i, 1);
+        }
+
+        // Serialize and deserialize
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+            oos.writeObject(hashtable1);
+        }
+        Hashtable<Integer, Integer> hashtable2 =
+                (Hashtable<Integer, Integer>) new ObjectInputStream(
+                    new ByteArrayInputStream(bos.toByteArray())).readObject();
+
+        // Check that table size is >= min expected size. Due to a bug in
+        // Hashtable deserialization this wasn't the case.
+        Field tableField = Hashtable.class.getDeclaredField("table");
+        tableField.setAccessible(true);
+        Object[] table2 = (Object[]) tableField.get(hashtable2);
+        assertTrue(table2.length >= (entriesCount / loadFactor));
+    }
 }
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index d0d30f1..2b3347c 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -1428,7 +1428,7 @@
         } catch (IllegalStateException expected) {
         }
 
-        // TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs JCERSAPrivateKey)
+        // TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs BCRSAPrivateKey)
         Key encryptKey = getEncryptKey(algorithm);
 
         final AlgorithmParameterSpec encryptSpec = getEncryptAlgorithmParameterSpec(algorithm);
@@ -4626,14 +4626,14 @@
                 if (s.getType().equals("Cipher")) {
                     if (s.getAlgorithm().startsWith("AES_128/")) {
                         Cipher c = Cipher.getInstance(s.getAlgorithm(), p);
-                        assertTrue(checkAES_keyConstraint(c, 128));
-                        assertFalse(checkAES_keyConstraint(c, 192));
-                        assertFalse(checkAES_keyConstraint(c, 256));
+                        assertTrue(s.getAlgorithm(), checkAES_keyConstraint(c, 128));
+                        assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 192));
+                        assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 256));
                     } else if (s.getAlgorithm().startsWith("AES_256/")) {
                         Cipher c = Cipher.getInstance(s.getAlgorithm(), p);
-                        assertFalse(checkAES_keyConstraint(c, 128));
-                        assertFalse(checkAES_keyConstraint(c, 192));
-                        assertTrue(checkAES_keyConstraint(c, 256));
+                        assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 128));
+                        assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 192));
+                        assertTrue(s.getAlgorithm(), checkAES_keyConstraint(c, 256));
                     }
                 }
             }
diff --git a/ojluni/src/main/java/java/lang/BootstrapMethodError.java b/ojluni/src/main/java/java/lang/BootstrapMethodError.java
new file mode 100644
index 0000000..a1509a0
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/BootstrapMethodError.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that an {@code invokedynamic} instruction has
+ * failed to find its bootstrap method,
+ * or the bootstrap method has failed to provide a
+ * {@linkplain java.lang.invoke.CallSite call site} with a {@linkplain java.lang.invoke.CallSite#getTarget target}
+ * of the correct {@linkplain java.lang.invoke.MethodHandle#type method type}.
+ *
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class BootstrapMethodError extends LinkageError {
+    private static final long serialVersionUID = 292L;
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with no detail message.
+     */
+    public BootstrapMethodError() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public BootstrapMethodError(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with the specified
+     * detail message and cause.
+     *
+     * @param s the detail message.
+     * @param cause the cause, may be {@code null}.
+     */
+    public BootstrapMethodError(String s, Throwable cause) {
+        super(s, cause);
+    }
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with the specified
+     * cause.
+     *
+     * @param cause the cause, may be {@code null}.
+     */
+    public BootstrapMethodError(Throwable cause) {
+        // cf. Throwable(Throwable cause) constructor.
+        super(cause == null ? null : cause.toString());
+        initCause(cause);
+    }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/CallSite.java b/ojluni/src/main/java/java/lang/invoke/CallSite.java
new file mode 100644
index 0000000..f9338e6
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/CallSite.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: Not using Empty
+//import sun.invoke.empty.Empty;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * A {@code CallSite} is a holder for a variable {@link MethodHandle},
+ * which is called its {@code target}.
+ * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
+ * all calls to the site's current target.
+ * A {@code CallSite} may be associated with several {@code invokedynamic}
+ * instructions, or it may be "free floating", associated with none.
+ * In any case, it may be invoked through an associated method handle
+ * called its {@linkplain #dynamicInvoker dynamic invoker}.
+ * <p>
+ * {@code CallSite} is an abstract class which does not allow
+ * direct subclassing by users.  It has three immediate,
+ * concrete subclasses that may be either instantiated or subclassed.
+ * <ul>
+ * <li>If a mutable target is not required, an {@code invokedynamic} instruction
+ * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
+ * <li>If a mutable target is required which has volatile variable semantics,
+ * because updates to the target must be immediately and reliably witnessed by other threads,
+ * a {@linkplain VolatileCallSite volatile call site} may be used.
+ * <li>Otherwise, if a mutable target is required,
+ * a {@linkplain MutableCallSite mutable call site} may be used.
+ * </ul>
+ * <p>
+ * A non-constant call site may be <em>relinked</em> by changing its target.
+ * The new target must have the same {@linkplain MethodHandle#type() type}
+ * as the previous target.
+ * Thus, though a call site can be relinked to a series of
+ * successive targets, it cannot change its type.
+ * <p>
+ * Here is a sample use of call sites and bootstrap methods which links every
+ * dynamic call site to print its arguments:
+<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
+static void test() throws Throwable {
+    // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
+    InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
+}
+private static void printArgs(Object... args) {
+  System.out.println(java.util.Arrays.deepToString(args));
+}
+private static final MethodHandle printArgs;
+static {
+  MethodHandles.Lookup lookup = MethodHandles.lookup();
+  Class thisClass = lookup.lookupClass();  // (who am I?)
+  printArgs = lookup.findStatic(thisClass,
+      "printArgs", MethodType.methodType(void.class, Object[].class));
+}
+private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
+  // ignore caller and name, but match the type:
+  return new ConstantCallSite(printArgs.asType(type));
+}
+</pre></blockquote>
+ * @author John Rose, JSR 292 EG
+ */
+abstract
+public class CallSite {
+    // Android-changed: not used.
+    // static { MethodHandleImpl.initStatics(); }
+
+    // The actual payload of this call site:
+    /*package-private*/
+    MethodHandle target;    // Note: This field is known to the JVM.  Do not change.
+
+    /**
+     * Make a blank call site object with the given method type.
+     * An initial target method is supplied which will throw
+     * an {@link IllegalStateException} if called.
+     * <p>
+     * Before this {@code CallSite} object is returned from a bootstrap method,
+     * it is usually provided with a more useful target method,
+     * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+     * @throws NullPointerException if the proposed type is null
+     */
+
+    /*package-private*/
+    CallSite(MethodType type) {
+        // Android-changed: No cache for these so create uninitializedCallSite target here using
+        // method handle transformations to create a method handle that has the expected method
+        // type but throws an IllegalStateException.
+        // target = type.invokers().uninitializedCallSite();
+        this.target = MethodHandles.throwException(type.returnType(), IllegalStateException.class);
+        this.target = MethodHandles.insertArguments(
+            this.target, 0, new IllegalStateException("uninitialized call site"));
+        if (type.parameterCount() > 0) {
+            this.target = MethodHandles.dropArguments(this.target, 0, type.ptypes());
+        }
+
+        // Android-changed: Using initializer method for GET_TARGET
+        // rather than complex static initializer.
+        initializeGetTarget();
+    }
+
+    /**
+     * Make a call site object equipped with an initial target method handle.
+     * @param target the method handle which will be the initial target of the call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    /*package-private*/
+    CallSite(MethodHandle target) {
+        target.type();  // null check
+        this.target = target;
+
+        // Android-changed: Using initializer method for GET_TARGET
+        // rather than complex static initializer.
+        initializeGetTarget();
+    }
+
+    /**
+     * Make a call site object equipped with an initial target method handle.
+     * @param targetType the desired type of the call site
+     * @param createTargetHook a hook which will bind the call site to the target method handle
+     * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+     *         or if the target returned by the hook is not of the given {@code targetType}
+     * @throws NullPointerException if the hook returns a null value
+     * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+     * @throws Throwable anything else thrown by the the hook function
+     */
+    /*package-private*/
+    CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+        this(targetType);
+        ConstantCallSite selfCCS = (ConstantCallSite) this;
+        MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
+        checkTargetChange(this.target, boundTarget);
+        this.target = boundTarget;
+
+        // Android-changed: Using initializer method for GET_TARGET
+        // rather than complex static initializer.
+        initializeGetTarget();
+    }
+
+    /**
+     * Returns the type of this call site's target.
+     * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
+     * The {@code setTarget} method enforces this invariant by refusing any new target that does
+     * not have the previous target's type.
+     * @return the type of the current target, which is also the type of any future target
+     */
+    public MethodType type() {
+        // warning:  do not call getTarget here, because CCS.getTarget can throw IllegalStateException
+        return target.type();
+    }
+
+    /**
+     * Returns the target method of the call site, according to the
+     * behavior defined by this call site's specific class.
+     * The immediate subclasses of {@code CallSite} document the
+     * class-specific behaviors of this method.
+     *
+     * @return the current linkage state of the call site, its target method handle
+     * @see ConstantCallSite
+     * @see VolatileCallSite
+     * @see #setTarget
+     * @see ConstantCallSite#getTarget
+     * @see MutableCallSite#getTarget
+     * @see VolatileCallSite#getTarget
+     */
+    public abstract MethodHandle getTarget();
+
+    /**
+     * Updates the target method of this call site, according to the
+     * behavior defined by this call site's specific class.
+     * The immediate subclasses of {@code CallSite} document the
+     * class-specific behaviors of this method.
+     * <p>
+     * The type of the new target must be {@linkplain MethodType#equals equal to}
+     * the type of the old target.
+     *
+     * @param newTarget the new target
+     * @throws NullPointerException if the proposed new target is null
+     * @throws WrongMethodTypeException if the proposed new target
+     *         has a method type that differs from the previous target
+     * @see CallSite#getTarget
+     * @see ConstantCallSite#setTarget
+     * @see MutableCallSite#setTarget
+     * @see VolatileCallSite#setTarget
+     */
+    public abstract void setTarget(MethodHandle newTarget);
+
+    void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
+        MethodType oldType = oldTarget.type();
+        MethodType newType = newTarget.type();  // null check!
+        if (!newType.equals(oldType))
+            throw wrongTargetType(newTarget, oldType);
+    }
+
+    private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
+        return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
+    }
+
+    /**
+     * Produces a method handle equivalent to an invokedynamic instruction
+     * which has been linked to this call site.
+     * <p>
+     * This method is equivalent to the following code:
+     * <blockquote><pre>
+     * MethodHandle getTarget, invoker, result;
+     * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
+     * invoker = MethodHandles.exactInvoker(this.type());
+     * result = MethodHandles.foldArguments(invoker, getTarget)
+     * </pre></blockquote>
+     *
+     * @return a method handle which always invokes this call site's current target
+     */
+    public abstract MethodHandle dynamicInvoker();
+
+    /*non-public*/ MethodHandle makeDynamicInvoker() {
+        // Android-changed: Use bindTo() rather than bindReceiver() (not implemented).
+        MethodHandle getTarget = GET_TARGET.bindTo(this);
+        MethodHandle invoker = MethodHandles.exactInvoker(this.type());
+        return MethodHandles.foldArguments(invoker, getTarget);
+    }
+
+    // Android-changed: no longer final. GET_TARGET assigned in initializeGetTarget().
+    private static MethodHandle GET_TARGET = null;
+
+    private void initializeGetTarget() {
+        // Android-changed: moved from static initializer for
+        // GET_TARGET to avoid issues with running early. Called from
+        // constructors. CallSite creation is not performance critical.
+        synchronized (CallSite.class) {
+            if (GET_TARGET == null) {
+                try {
+                    GET_TARGET = IMPL_LOOKUP.
+                            findVirtual(CallSite.class, "getTarget",
+                                        MethodType.methodType(MethodHandle.class));
+                } catch (ReflectiveOperationException e) {
+                    throw new InternalError(e);
+                }
+            }
+        }
+    }
+
+    /* Android-changed: not used. */
+    // /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
+    // /*package-private*/
+    // static Empty uninitializedCallSite() {
+    //     throw new IllegalStateException("uninitialized call site");
+    // }
+
+    // unsafe stuff:
+    private static final long TARGET_OFFSET;
+    static {
+        try {
+            TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
+        } catch (Exception ex) { throw new Error(ex); }
+    }
+
+    /*package-private*/
+    void setTargetNormal(MethodHandle newTarget) {
+        // Android-changed: Set value directly.
+        // MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
+        target = newTarget;
+    }
+    /*package-private*/
+    MethodHandle getTargetVolatile() {
+        return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
+    }
+    /*package-private*/
+    void setTargetVolatile(MethodHandle newTarget) {
+        // Android-changed: Set value directly.
+        // MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
+        UNSAFE.putObjectVolatile(this, TARGET_OFFSET, newTarget);
+    }
+
+    /* Android-changed: not used. */
+    // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
+    // static CallSite makeSite(MethodHandle bootstrapMethod,
+    //                          // Callee information:
+    //                          String name, MethodType type,
+    //                          // Extra arguments for BSM, if any:
+    //                          Object info,
+    //                          // Caller information:
+    //                          Class<?> callerClass) {
+    //     Object caller = IMPL_LOOKUP.in(callerClass);
+    //     CallSite site;
+    //     try {
+    //         Object binding;
+    //         info = maybeReBox(info);
+    //         if (info == null) {
+    //             binding = bootstrapMethod.invoke(caller, name, type);
+    //         } else if (!info.getClass().isArray()) {
+    //             binding = bootstrapMethod.invoke(caller, name, type, info);
+    //         } else {
+    //             Object[] argv = (Object[]) info;
+    //             maybeReBoxElements(argv);
+    //             if (3 + argv.length > 255)
+    //                 throw new BootstrapMethodError("too many bootstrap method arguments");
+    //             MethodType bsmType = bootstrapMethod.type();
+    //             if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
+    //                 binding = bootstrapMethod.invoke(caller, name, type, argv);
+    //             else
+    //                 binding = MethodHandles.spreadInvoker(bsmType, 3)
+    //                     .invoke(bootstrapMethod, caller, name, type, argv);
+    //         }
+    //         //System.out.println("BSM for "+name+type+" => "+binding);
+    //         if (binding instanceof CallSite) {
+    //             site = (CallSite) binding;
+    //         }  else {
+    //             throw new ClassCastException("bootstrap method failed to produce a CallSite");
+    //         }
+    //         if (!site.getTarget().type().equals(type))
+    //             throw new WrongMethodTypeException("wrong type: "+site.getTarget());
+    //     } catch (Throwable ex) {
+    //         BootstrapMethodError bex;
+    //         if (ex instanceof BootstrapMethodError)
+    //             bex = (BootstrapMethodError) ex;
+    //         else
+    //             bex = new BootstrapMethodError("call site initialization exception", ex);
+    //         throw bex;
+    //     }
+    //     return site;
+    // }
+    // private static Object maybeReBox(Object x) {
+    //     if (x instanceof Integer) {
+    //         int xi = (int) x;
+    //         if (xi == (byte) xi)
+    //             x = xi;  // must rebox; see JLS 5.1.7
+    //     }
+    //     return x;
+    // }
+    // private static void maybeReBoxElements(Object[] xa) {
+    //     for (int i = 0; i < xa.length; i++) {
+    //         xa[i] = maybeReBox(xa[i]);
+    //     }
+    // }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java b/ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java
new file mode 100644
index 0000000..2d9fede
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
+ * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
+ * bound to the call site's target.
+ * @author John Rose, JSR 292 EG
+ */
+public class ConstantCallSite extends CallSite {
+    private final boolean isFrozen;
+
+    /**
+     * Creates a call site with a permanent target.
+     * @param target the target to be permanently associated with this call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    public ConstantCallSite(MethodHandle target) {
+        super(target);
+        isFrozen = true;
+    }
+
+    /**
+     * Creates a call site with a permanent target, possibly bound to the call site itself.
+     * <p>
+     * During construction of the call site, the {@code createTargetHook} is invoked to
+     * produce the actual target, as if by a call of the form
+     * {@code (MethodHandle) createTargetHook.invoke(this)}.
+     * <p>
+     * Note that user code cannot perform such an action directly in a subclass constructor,
+     * since the target must be fixed before the {@code ConstantCallSite} constructor returns.
+     * <p>
+     * The hook is said to bind the call site to a target method handle,
+     * and a typical action would be {@code someTarget.bindTo(this)}.
+     * However, the hook is free to take any action whatever,
+     * including ignoring the call site and returning a constant target.
+     * <p>
+     * The result returned by the hook must be a method handle of exactly
+     * the same type as the call site.
+     * <p>
+     * While the hook is being called, the new {@code ConstantCallSite}
+     * object is in a partially constructed state.
+     * In this state,
+     * a call to {@code getTarget}, or any other attempt to use the target,
+     * will result in an {@code IllegalStateException}.
+     * It is legal at all times to obtain the call site's type using the {@code type} method.
+     *
+     * @param targetType the type of the method handle to be permanently associated with this call site
+     * @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
+     * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+     *         or if the target returned by the hook is not of the given {@code targetType}
+     * @throws NullPointerException if the hook returns a null value
+     * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+     * @throws Throwable anything else thrown by the the hook function
+     */
+    protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+        super(targetType, createTargetHook);
+        isFrozen = true;
+    }
+
+    /**
+     * Returns the target method of the call site, which behaves
+     * like a {@code final} field of the {@code ConstantCallSite}.
+     * That is, the the target is always the original value passed
+     * to the constructor call which created this instance.
+     *
+     * @return the immutable linkage state of this call site, a constant method handle
+     * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+     */
+    @Override public final MethodHandle getTarget() {
+        if (!isFrozen)  throw new IllegalStateException();
+        return target;
+    }
+
+    /**
+     * Always throws an {@link UnsupportedOperationException}.
+     * This kind of call site cannot change its target.
+     * @param ignore a new target proposed for the call site, which is ignored
+     * @throws UnsupportedOperationException because this kind of call site cannot change its target
+     */
+    @Override public final void setTarget(MethodHandle ignore) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns this call site's permanent target.
+     * Since that target will never change, this is a correct implementation
+     * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
+     * @return the immutable linkage state of this call site, a constant method handle
+     * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+     */
+    @Override
+    public final MethodHandle dynamicInvoker() {
+        return getTarget();
+    }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
index c41e0c2..9e26196 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -665,6 +665,9 @@
          */
         static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
 
+        /** Package-private version of lookup which is trusted. */
+        static final Lookup IMPL_LOOKUP = new Lookup(Object.class, ALL_MODES);
+
         private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
             String name = lookupClass.getName();
             if (name.startsWith("java.lang.invoke."))
@@ -1656,7 +1659,7 @@
             }
         }
 
-        public void throwMakeAccessException(String message, Object from) throws
+        private void throwMakeAccessException(String message, Object from) throws
                 IllegalAccessException{
             message = message + ": "+ toString();
             if (from != null)  message += ", from " + from;
diff --git a/ojluni/src/main/java/java/lang/invoke/MutableCallSite.java b/ojluni/src/main/java/java/lang/invoke/MutableCallSite.java
new file mode 100644
index 0000000..37ca324
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/MutableCallSite.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: not used.
+// import java.util.concurrent.atomic.AtomicInteger;
+
+// Android-changed: removed references to MutableCallSite.syncAll().
+/**
+ * A {@code MutableCallSite} is a {@link CallSite} whose target variable
+ * behaves like an ordinary field.
+ * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
+ * all calls to the site's current target.
+ * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
+ * also delegates each call to the site's current target.
+ * <p>
+ * Here is an example of a mutable call site which introduces a
+ * state variable into a method handle chain.
+ * <!-- JavaDocExamplesTest.testMutableCallSite -->
+ * <blockquote><pre>
+MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
+MethodHandle MH_name = name.dynamicInvoker();
+MethodType MT_str1 = MethodType.methodType(String.class);
+MethodHandle MH_upcase = MethodHandles.lookup()
+    .findVirtual(String.class, "toUpperCase", MT_str1);
+MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
+name.setTarget(MethodHandles.constant(String.class, "Rocky"));
+assertEquals("ROCKY", (String) worker1.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Fred"));
+assertEquals("FRED", (String) worker1.invokeExact());
+// (mutation can be continued indefinitely)
+ * </pre></blockquote>
+ * <p>
+ * The same call site may be used in several places at once.
+ * <blockquote><pre>
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
+MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
+assertEquals("Fred, dear?", (String) worker2.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Wilma"));
+assertEquals("WILMA", (String) worker1.invokeExact());
+assertEquals("Wilma, dear?", (String) worker2.invokeExact());
+ * </pre></blockquote>
+ * <p>
+ * <em>Non-synchronization of target values:</em>
+ * A write to a mutable call site's target does not force other threads
+ * to become aware of the updated value.  Threads which do not perform
+ * suitable synchronization actions relative to the updated call site
+ * may cache the old target value and delay their use of the new target
+ * value indefinitely.
+ * (This is a normal consequence of the Java Memory Model as applied
+ * to object fields.)
+ * <p>
+ * For target values which will be frequently updated, consider using
+ * a {@linkplain VolatileCallSite volatile call site} instead.
+ * @author John Rose, JSR 292 EG
+ */
+public class MutableCallSite extends CallSite {
+    /**
+     * Creates a blank call site object with the given method type.
+     * The initial target is set to a method handle of the given type
+     * which will throw an {@link IllegalStateException} if called.
+     * <p>
+     * The type of the call site is permanently set to the given type.
+     * <p>
+     * Before this {@code CallSite} object is returned from a bootstrap method,
+     * or invoked in some other manner,
+     * it is usually provided with a more useful target method,
+     * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+     * @param type the method type that this call site will have
+     * @throws NullPointerException if the proposed type is null
+     */
+    public MutableCallSite(MethodType type) {
+        super(type);
+    }
+
+    /**
+     * Creates a call site object with an initial target method handle.
+     * The type of the call site is permanently set to the initial target's type.
+     * @param target the method handle that will be the initial target of the call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    public MutableCallSite(MethodHandle target) {
+        super(target);
+    }
+
+    /**
+     * Returns the target method of the call site, which behaves
+     * like a normal field of the {@code MutableCallSite}.
+     * <p>
+     * The interactions of {@code getTarget} with memory are the same
+     * as of a read from an ordinary variable, such as an array element or a
+     * non-volatile, non-final field.
+     * <p>
+     * In particular, the current thread may choose to reuse the result
+     * of a previous read of the target from memory, and may fail to see
+     * a recent update to the target by another thread.
+     *
+     * @return the linkage state of this call site, a method handle which can change over time
+     * @see #setTarget
+     */
+    @Override public final MethodHandle getTarget() {
+        return target;
+    }
+
+    /**
+     * Updates the target method of this call site, as a normal variable.
+     * The type of the new target must agree with the type of the old target.
+     * <p>
+     * The interactions with memory are the same
+     * as of a write to an ordinary variable, such as an array element or a
+     * non-volatile, non-final field.
+     * <p>
+     * In particular, unrelated threads may fail to see the updated target
+     * until they perform a read from memory.
+     * Stronger guarantees can be created by putting appropriate operations
+     * into the bootstrap method and/or the target methods used
+     * at any given call site.
+     *
+     * @param newTarget the new target
+     * @throws NullPointerException if the proposed new target is null
+     * @throws WrongMethodTypeException if the proposed new target
+     *         has a method type that differs from the previous target
+     * @see #getTarget
+     */
+    @Override public void setTarget(MethodHandle newTarget) {
+        checkTargetChange(this.target, newTarget);
+        setTargetNormal(newTarget);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final MethodHandle dynamicInvoker() {
+        return makeDynamicInvoker();
+    }
+
+    // Android-changed: not exposing incomplete implementation.
+    // /**
+    //  * Performs a synchronization operation on each call site in the given array,
+    //  * forcing all other threads to throw away any cached values previously
+    //  * loaded from the target of any of the call sites.
+    //  * <p>
+    //  * This operation does not reverse any calls that have already started
+    //  * on an old target value.
+    //  * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
+    //  * <p>
+    //  * The overall effect is to force all future readers of each call site's target
+    //  * to accept the most recently stored value.
+    //  * ("Most recently" is reckoned relative to the {@code syncAll} itself.)
+    //  * Conversely, the {@code syncAll} call may block until all readers have
+    //  * (somehow) decached all previous versions of each call site's target.
+    //  * <p>
+    //  * To avoid race conditions, calls to {@code setTarget} and {@code syncAll}
+    //  * should generally be performed under some sort of mutual exclusion.
+    //  * Note that reader threads may observe an updated target as early
+    //  * as the {@code setTarget} call that install the value
+    //  * (and before the {@code syncAll} that confirms the value).
+    //  * On the other hand, reader threads may observe previous versions of
+    //  * the target until the {@code syncAll} call returns
+    //  * (and after the {@code setTarget} that attempts to convey the updated version).
+    //  * <p>
+    //  * This operation is likely to be expensive and should be used sparingly.
+    //  * If possible, it should be buffered for batch processing on sets of call sites.
+    //  * <p>
+    //  * If {@code sites} contains a null element,
+    //  * a {@code NullPointerException} will be raised.
+    //  * In this case, some non-null elements in the array may be
+    //  * processed before the method returns abnormally.
+    //  * Which elements these are (if any) is implementation-dependent.
+    //  *
+    //  * <h3>Java Memory Model details</h3>
+    //  * In terms of the Java Memory Model, this operation performs a synchronization
+    //  * action which is comparable in effect to the writing of a volatile variable
+    //  * by the current thread, and an eventual volatile read by every other thread
+    //  * that may access one of the affected call sites.
+    //  * <p>
+    //  * The following effects are apparent, for each individual call site {@code S}:
+    //  * <ul>
+    //  * <li>A new volatile variable {@code V} is created, and written by the current thread.
+    //  *     As defined by the JMM, this write is a global synchronization event.
+    //  * <li>As is normal with thread-local ordering of write events,
+    //  *     every action already performed by the current thread is
+    //  *     taken to happen before the volatile write to {@code V}.
+    //  *     (In some implementations, this means that the current thread
+    //  *     performs a global release operation.)
+    //  * <li>Specifically, the write to the current target of {@code S} is
+    //  *     taken to happen before the volatile write to {@code V}.
+    //  * <li>The volatile write to {@code V} is placed
+    //  *     (in an implementation specific manner)
+    //  *     in the global synchronization order.
+    //  * <li>Consider an arbitrary thread {@code T} (other than the current thread).
+    //  *     If {@code T} executes a synchronization action {@code A}
+    //  *     after the volatile write to {@code V} (in the global synchronization order),
+    //  *     it is therefore required to see either the current target
+    //  *     of {@code S}, or a later write to that target,
+    //  *     if it executes a read on the target of {@code S}.
+    //  *     (This constraint is called "synchronization-order consistency".)
+    //  * <li>The JMM specifically allows optimizing compilers to elide
+    //  *     reads or writes of variables that are known to be useless.
+    //  *     Such elided reads and writes have no effect on the happens-before
+    //  *     relation.  Regardless of this fact, the volatile {@code V}
+    //  *     will not be elided, even though its written value is
+    //  *     indeterminate and its read value is not used.
+    //  * </ul>
+    //  * Because of the last point, the implementation behaves as if a
+    //  * volatile read of {@code V} were performed by {@code T}
+    //  * immediately after its action {@code A}.  In the local ordering
+    //  * of actions in {@code T}, this read happens before any future
+    //  * read of the target of {@code S}.  It is as if the
+    //  * implementation arbitrarily picked a read of {@code S}'s target
+    //  * by {@code T}, and forced a read of {@code V} to precede it,
+    //  * thereby ensuring communication of the new target value.
+    //  * <p>
+    //  * As long as the constraints of the Java Memory Model are obeyed,
+    //  * implementations may delay the completion of a {@code syncAll}
+    //  * operation while other threads ({@code T} above) continue to
+    //  * use previous values of {@code S}'s target.
+    //  * However, implementations are (as always) encouraged to avoid
+    //  * livelock, and to eventually require all threads to take account
+    //  * of the updated target.
+    //  *
+    //  * <p style="font-size:smaller;">
+    //  * <em>Discussion:</em>
+    //  * For performance reasons, {@code syncAll} is not a virtual method
+    //  * on a single call site, but rather applies to a set of call sites.
+    //  * Some implementations may incur a large fixed overhead cost
+    //  * for processing one or more synchronization operations,
+    //  * but a small incremental cost for each additional call site.
+    //  * In any case, this operation is likely to be costly, since
+    //  * other threads may have to be somehow interrupted
+    //  * in order to make them notice the updated target value.
+    //  * However, it may be observed that a single call to synchronize
+    //  * several sites has the same formal effect as many calls,
+    //  * each on just one of the sites.
+    //  *
+    //  * <p style="font-size:smaller;">
+    //  * <em>Implementation Note:</em>
+    //  * Simple implementations of {@code MutableCallSite} may use
+    //  * a volatile variable for the target of a mutable call site.
+    //  * In such an implementation, the {@code syncAll} method can be a no-op,
+    //  * and yet it will conform to the JMM behavior documented above.
+    //  *
+    //  * @param sites an array of call sites to be synchronized
+    //  * @throws NullPointerException if the {@code sites} array reference is null
+    //  *                              or the array contains a null
+    //  */
+    // public static void syncAll(MutableCallSite[] sites) {
+    //     if (sites.length == 0)  return;
+    //     STORE_BARRIER.lazySet(0);
+    //     for (int i = 0; i < sites.length; i++) {
+    //         sites[i].getClass();  // trigger NPE on first null
+    //     }
+    //     // FIXME: NYI
+    // }
+    // private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/Transformers.java b/ojluni/src/main/java/java/lang/invoke/Transformers.java
index 10ce855..82cc797 100644
--- a/ojluni/src/main/java/java/lang/invoke/Transformers.java
+++ b/ojluni/src/main/java/java/lang/invoke/Transformers.java
@@ -237,27 +237,25 @@
      */
     public static class ReferenceArrayElementGetter extends Transformer {
         private final Class<?> arrayClass;
-        private final StackFrameReader reader;
-        private final StackFrameWriter writer;
 
         public ReferenceArrayElementGetter(Class<?> arrayClass) {
             super(MethodType.methodType(arrayClass.getComponentType(),
                     new Class<?>[]{arrayClass, int.class}));
             this.arrayClass = arrayClass;
-            reader = new StackFrameReader();
-            writer = new StackFrameWriter();
         }
 
         @Override
         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
             reader.attach(emulatedStackFrame);
-            writer.attach(emulatedStackFrame);
 
             // Read the array object and the index from the stack frame.
             final Object[] array = (Object[]) reader.nextReference(arrayClass);
             final int index = reader.nextInt();
 
             // Write the array element back to the stack frame.
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(emulatedStackFrame);
             writer.makeReturnValueAccessor();
             writer.putNextReference(array[index], arrayClass.getComponentType());
         }
@@ -268,17 +266,16 @@
      */
     public static class ReferenceArrayElementSetter extends Transformer {
         private final Class<?> arrayClass;
-        private final StackFrameReader reader;
 
         public ReferenceArrayElementSetter(Class<?> arrayClass) {
             super(MethodType.methodType(void.class,
                     new Class<?>[] { arrayClass, int.class, arrayClass.getComponentType() }));
             this.arrayClass = arrayClass;
-            reader = new StackFrameReader();
         }
 
         @Override
         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
             reader.attach(emulatedStackFrame);
 
             // Read the array object, index and the value to write from the stack frame.
@@ -295,23 +292,20 @@
      */
     public static class ReferenceIdentity extends Transformer {
         private final Class<?> type;
-        private final StackFrameReader reader;
-        private final StackFrameWriter writer;
 
         public ReferenceIdentity(Class<?> type) {
             super(MethodType.methodType(type, type));
             this.type = type;
-
-            reader = new StackFrameReader();
-            writer = new StackFrameWriter();
         }
 
         @Override
         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
             reader.attach(emulatedStackFrame);
+
+            final StackFrameWriter writer = new StackFrameWriter();
             writer.attach(emulatedStackFrame);
             writer.makeReturnValueAccessor();
-
             writer.putNextReference(reader.nextReference(type), type);
         }
     }
@@ -336,8 +330,6 @@
 
         private char typeChar;
 
-        private final EmulatedStackFrame.StackFrameWriter writer;
-
         public Constant(Class<?> type, Object value) {
             super(MethodType.methodType(type));
             this.type = type;
@@ -372,12 +364,11 @@
             } else {
                 throw new AssertionError("unknown type: " + typeChar);
             }
-
-            writer = new EmulatedStackFrame.StackFrameWriter();
         }
 
         @Override
         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameWriter writer = new StackFrameWriter();
             writer.attach(emulatedStackFrame);
             writer.makeReturnValueAccessor();
 
@@ -491,9 +482,6 @@
         private final MethodHandle target;
         private final MethodHandle filter;
 
-        private final EmulatedStackFrame.StackFrameReader returnValueReader;
-        private final EmulatedStackFrame.StackFrameWriter filterWriter;
-
         private final EmulatedStackFrame.Range allArgs;
 
         public FilterReturnValue(MethodHandle target, MethodHandle filter) {
@@ -502,9 +490,6 @@
             this.target = target;
             this.filter = filter;
 
-            returnValueReader = new EmulatedStackFrame.StackFrameReader();
-            filterWriter = new EmulatedStackFrame.StackFrameWriter();
-
             allArgs = EmulatedStackFrame.Range.all(type());
         }
 
@@ -515,15 +500,16 @@
             // the same parameter shapes.
             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
             emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0);
-
             target.invoke(targetFrame);
 
             // Perform the invoke.
+            final StackFrameReader returnValueReader = new StackFrameReader();
             returnValueReader.attach(targetFrame);
             returnValueReader.makeReturnValueAccessor();
 
             // Create an emulated frame for the filter and copy all its arguments across.
             EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
+            final StackFrameWriter filterWriter = new StackFrameWriter();
             filterWriter.attach(filterFrame);
 
             final Class<?> returnType = target.type().rtype();
@@ -563,30 +549,24 @@
         private final MethodHandle target;
         private final int[] reorder;
 
-        private final EmulatedStackFrame.StackFrameWriter writer;
-        private final EmulatedStackFrame.StackFrameReader reader;
-
         public PermuteArguments(MethodType type, MethodHandle target, int[] reorder) {
             super(type);
 
             this.target = target;
             this.reorder = reorder;
-
-            writer = new EmulatedStackFrame.StackFrameWriter();
-            reader = new EmulatedStackFrame.StackFrameReader();
         }
 
         @Override
         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
             reader.attach(emulatedStackFrame);
-            final Class<?>[] ptypes = type().ptypes();
 
             // In the interests of simplicity, we box / unbox arguments while performing
             // the permutation. We first iterate through the incoming stack frame and box
             // each argument. We then unbox and write out the argument to the target frame
             // according to the specified reordering.
             Object[] arguments = new Object[reorder.length];
-
+            final Class<?>[] ptypes = type().ptypes();
             for (int i = 0; i < ptypes.length; ++i) {
                 final Class<?> ptype = ptypes[i];
                 if (!ptype.isPrimitive()) {
@@ -613,6 +593,7 @@
             }
 
             EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
+            final StackFrameWriter writer = new StackFrameWriter();
             writer.attach(calleeFrame);
 
             for (int i = 0; i < ptypes.length; ++i) {
@@ -1083,7 +1064,6 @@
          * arguments that aren't a part of the trailing array.
          */
         private final Range copyRange;
-        private final StackFrameWriter writer;
 
         Spreader(MethodHandle target, MethodType spreaderType, int numArrayArgs) {
             super(spreaderType);
@@ -1102,7 +1082,6 @@
             this.numArrayArgs = numArrayArgs;
             // Copy all args except for the last argument.
             this.copyRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset);
-            this.writer = new StackFrameWriter();
         }
 
         @Override
@@ -1115,6 +1094,7 @@
 
             // Attach the writer, prepare to spread the trailing array arguments into
             // the callee frame.
+            StackFrameWriter writer = new StackFrameWriter();
             writer.attach(targetFrame,
                     arrayOffset,
                     copyRange.numReferences,
@@ -1350,9 +1330,6 @@
          */
         private final Range copyRange;
 
-        private final StackFrameWriter writer;
-        private final StackFrameReader reader;
-
         Collector(MethodHandle delegate, Class<?> arrayType, int length) {
             super(delegate.type().asCollectorType(arrayType, length));
 
@@ -1365,8 +1342,6 @@
 
             // Copy all args except for the last argument.
             copyRange = EmulatedStackFrame.Range.of(delegate.type(), 0, arrayOffset);
-            writer = new StackFrameWriter();
-            reader = new StackFrameReader();
         }
 
         @Override
@@ -1379,7 +1354,9 @@
 
             // Attach the writer, prepare to spread the trailing array arguments into
             // the callee frame.
+            final StackFrameWriter writer = new StackFrameWriter();
             writer.attach(targetFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
+            final StackFrameReader reader = new StackFrameReader();
             reader.attach(callerFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
 
             switch (arrayTypeChar) {
@@ -1481,12 +1458,6 @@
         /** The list of filters to apply */
         private final MethodHandle[] filters;
 
-        private final StackFrameWriter writer;
-        private final StackFrameReader reader;
-
-        private final StackFrameWriter filterWriter;
-        private final StackFrameReader filterReader;
-
         FilterArguments(MethodHandle target, int pos, MethodHandle[] filters) {
             super(deriveType(target, pos, filters));
 
@@ -1494,11 +1465,6 @@
             this.pos = pos;
             this.filters = filters;
 
-            this.writer = new StackFrameWriter();
-            this.reader = new StackFrameReader();
-
-            this.filterReader = new StackFrameReader();
-            this.filterWriter = new StackFrameWriter();
         }
 
         private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) {
@@ -1512,9 +1478,11 @@
 
         @Override
         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
             reader.attach(stackFrame);
 
             EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type());
+            final StackFrameWriter writer = new StackFrameWriter();
             writer.attach(transformedFrame);
 
             final Class<?>[] ptypes = target.type().ptypes();
@@ -1537,12 +1505,14 @@
                     EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
 
                     //  Copy the next argument from the stack frame to the filter frame.
+                    final StackFrameWriter filterWriter = new StackFrameWriter();
                     filterWriter.attach(filterFrame);
                     copyNext(reader, filterWriter, filter.type().ptypes()[0]);
 
                     filter.invoke(filterFrame);
 
                     // Copy the argument back from the filter frame to the stack frame.
+                    final StackFrameReader filterReader = new StackFrameReader();
                     filterReader.attach(filterFrame);
                     filterReader.makeReturnValueAccessor();
                     copyNext(filterReader, writer, ptype);
@@ -1581,9 +1551,6 @@
          */
         private final Range range2;
 
-        private final StackFrameReader reader;
-        private final StackFrameWriter writer;
-
         private final int referencesOffset;
         private final int stackFrameOffset;
 
@@ -1606,9 +1573,6 @@
                 this.range2 = null;
             }
 
-            reader = new StackFrameReader();
-            writer = new StackFrameWriter();
-
             // Calculate the number of primitive bytes (or references) we copy to the
             // target frame based on the return value of the combiner.
             final Class<?> collectorRType = collector.type().rtype();
@@ -1637,7 +1601,9 @@
 
             // If one of these offsets is not zero, we have a return value to copy.
             if (referencesOffset != 0 || stackFrameOffset != 0) {
+                final StackFrameReader reader = new StackFrameReader();
                 reader.attach(filterFrame).makeReturnValueAccessor();
+                final StackFrameWriter writer = new StackFrameWriter();
                 writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes);
                 copyNext(reader, writer, target.type().ptypes()[0]);
             }
@@ -1663,9 +1629,6 @@
         private final Range combinerArgs;
         private final Range targetArgs;
 
-        private final StackFrameReader reader;
-        private final StackFrameWriter writer;
-
         private final int referencesOffset;
         private final int stackFrameOffset;
 
@@ -1678,9 +1641,6 @@
             combinerArgs = Range.all(combiner.type());
             targetArgs = Range.all(type());
 
-            reader = new StackFrameReader();
-            writer = new StackFrameWriter();
-
             final Class<?> combinerRType = combiner.type().rtype();
             if (combinerRType == void.class) {
                 stackFrameOffset = 0;
@@ -1706,7 +1666,9 @@
 
             // If one of these offsets is not zero, we have a return value to copy.
             if (referencesOffset != 0 || stackFrameOffset != 0) {
+                final StackFrameReader reader = new StackFrameReader();
                 reader.attach(combinerFrame).makeReturnValueAccessor();
+                final StackFrameWriter writer = new StackFrameWriter();
                 writer.attach(targetFrame);
                 copyNext(reader, writer, target.type().ptypes()[0]);
             }
@@ -1736,7 +1698,6 @@
 
         private final Range range1;
         private final Range range2;
-        private final StackFrameWriter writer;
 
         InsertArguments(MethodHandle target, int pos, Object[] values) {
             super(target.type().dropParameterTypes(pos, pos + values.length));
@@ -1747,8 +1708,6 @@
             final MethodType type = type();
             range1 = EmulatedStackFrame.Range.of(type, 0, pos);
             range2 = Range.of(type, pos, type.parameterCount());
-
-            writer = new StackFrameWriter();
         }
 
         @Override
@@ -1760,6 +1719,7 @@
 
             // Attach a stack frame writer so that we can copy the next |values.length|
             // arguments.
+            final StackFrameWriter writer = new StackFrameWriter();
             writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes);
 
             // Copy all the arguments supplied in |values|.
diff --git a/ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java b/ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java
new file mode 100644
index 0000000..6444335
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: removed references to MutableCallSite.syncAll().
+/**
+ * A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
+ * An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
+ * to its call site target immediately, even if the update occurs in another thread.
+ * There may be a performance penalty for such tight coupling between threads.
+ * <p>
+ * In other respects, a {@code VolatileCallSite} is interchangeable
+ * with {@code MutableCallSite}.
+ * @see MutableCallSite
+ * @author John Rose, JSR 292 EG
+ */
+public class VolatileCallSite extends CallSite {
+    /**
+     * Creates a call site with a volatile binding to its target.
+     * The initial target is set to a method handle
+     * of the given type which will throw an {@code IllegalStateException} if called.
+     * @param type the method type that this call site will have
+     * @throws NullPointerException if the proposed type is null
+     */
+    public VolatileCallSite(MethodType type) {
+        super(type);
+    }
+
+    /**
+     * Creates a call site with a volatile binding to its target.
+     * The target is set to the given value.
+     * @param target the method handle that will be the initial target of the call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    public VolatileCallSite(MethodHandle target) {
+        super(target);
+    }
+
+    /**
+     * Returns the target method of the call site, which behaves
+     * like a {@code volatile} field of the {@code VolatileCallSite}.
+     * <p>
+     * The interactions of {@code getTarget} with memory are the same
+     * as of a read from a {@code volatile} field.
+     * <p>
+     * In particular, the current thread is required to issue a fresh
+     * read of the target from memory, and must not fail to see
+     * a recent update to the target by another thread.
+     *
+     * @return the linkage state of this call site, a method handle which can change over time
+     * @see #setTarget
+     */
+    @Override public final MethodHandle getTarget() {
+        return getTargetVolatile();
+    }
+
+    /**
+     * Updates the target method of this call site, as a volatile variable.
+     * The type of the new target must agree with the type of the old target.
+     * <p>
+     * The interactions with memory are the same as of a write to a volatile field.
+     * In particular, any threads is guaranteed to see the updated target
+     * the next time it calls {@code getTarget}.
+     * @param newTarget the new target
+     * @throws NullPointerException if the proposed new target is null
+     * @throws WrongMethodTypeException if the proposed new target
+     *         has a method type that differs from the previous target
+     * @see #getTarget
+     */
+    @Override public void setTarget(MethodHandle newTarget) {
+        checkTargetChange(getTargetVolatile(), newTarget);
+        setTargetVolatile(newTarget);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final MethodHandle dynamicInvoker() {
+        return makeDynamicInvoker();
+    }
+}
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index deb186c..a932893 100644
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -895,15 +895,6 @@
             algorithm = algorithm.toUpperCase(ENGLISH);
             this.algorithm = intern ? algorithm.intern() : algorithm;
         }
-        // BEGIN ANDROID-CHANGED
-        // The above constructor is not amenable to compile-time execution as Locale.ENGLISH
-        // cannot be retrieved. Special-case a constructor for the static field "previousKey".
-        private ServiceKey() {
-            this.type = "";
-            this.originalAlgorithm = "";
-            this.algorithm = "";
-        }
-        // END ANDROID-CHANGED
         public int hashCode() {
             return type.hashCode() + algorithm.hashCode();
         }
@@ -1088,10 +1079,7 @@
     // list and queries each provider with the same values until it finds
     // a matching service
     private static volatile ServiceKey previousKey =
-                                            // BEGIN ANDROID-CHANGED
-                                            //  was: new ServiceKey("", "", false);
-                                            new ServiceKey();
-                                            // END ANDROID-CHANGED
+                                            new ServiceKey("", "", false);
 
     /**
      * Get an unmodifiable Set of all services supported by
diff --git a/ojluni/src/main/java/java/time/Instant.java b/ojluni/src/main/java/java/time/Instant.java
index 91a177c..9b9efa5 100644
--- a/ojluni/src/main/java/java/time/Instant.java
+++ b/ojluni/src/main/java/java/time/Instant.java
@@ -1229,8 +1229,14 @@
      * @throws ArithmeticException if numeric overflow occurs
      */
     public long toEpochMilli() {
-        long millis = Math.multiplyExact(seconds, 1000);
-        return millis + nanos / 1000_000;
+        if (seconds < 0 && nanos > 0) {
+            long millis = Math.multiplyExact(seconds+1, 1000);
+            long adjustment = nanos / 1000_000 - 1000;
+            return Math.addExact(millis, adjustment);
+        } else {
+            long millis = Math.multiplyExact(seconds, 1000);
+            return Math.addExact(millis, nanos / 1000_000);
+        }
     }
 
     //-----------------------------------------------------------------------
diff --git a/ojluni/src/main/java/java/time/chrono/ChronoLocalDate.java b/ojluni/src/main/java/java/time/chrono/ChronoLocalDate.java
index 676421a..5848e94 100644
--- a/ojluni/src/main/java/java/time/chrono/ChronoLocalDate.java
+++ b/ojluni/src/main/java/java/time/chrono/ChronoLocalDate.java
@@ -715,7 +715,7 @@
      * only compares the underlying date and not the chronology.
      * This allows dates in different calendar systems to be compared based
      * on the time-line position.
-     * This is equivalent to using {@code date1.toEpochDay() &gt; date2.toEpochDay()}.
+     * This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}.
      * <p>
      * This default implementation performs the comparison based on the epoch-day.
      *
@@ -733,7 +733,7 @@
      * only compares the underlying date and not the chronology.
      * This allows dates in different calendar systems to be compared based
      * on the time-line position.
-     * This is equivalent to using {@code date1.toEpochDay() &lt; date2.toEpochDay()}.
+     * This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}.
      * <p>
      * This default implementation performs the comparison based on the epoch-day.
      *
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
index 15f7d84..29e503e 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
@@ -132,7 +132,7 @@
     private static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese");
 
     static Calendar createCalendar() {
-        return Calendar.getJapanesImperialInstance(TimeZone.getDefault(), LOCALE);
+        return Calendar.getJapaneseImperialInstance(TimeZone.getDefault(), LOCALE);
     }
 
     /**
diff --git a/ojluni/src/main/java/java/time/format/ZoneName.java b/ojluni/src/main/java/java/time/format/ZoneName.java
index 1d58109..c3eb20a 100644
--- a/ojluni/src/main/java/java/time/format/ZoneName.java
+++ b/ojluni/src/main/java/java/time/format/ZoneName.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,12 +28,8 @@
 import android.icu.text.TimeZoneNames;
 import android.icu.util.TimeZone;
 import android.icu.util.ULocale;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
 /**
  * A helper class to map a zone name to metazone and back to the
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 6f8b9a9..8593403 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -1489,7 +1489,15 @@
                 setWeekDefinition(MONDAY, 4);
                 cal = gcal;
                 break;
-                // Android-changed: removed support for "buddhist" and "japanese".
+// Android-changed BEGIN: removed support for "buddhist" and "japanese".
+//            case "buddhist":
+//                cal = new BuddhistCalendar(zone, locale);
+//                cal.clear();
+//                break;
+//            case "japanese":
+//                cal = new JapaneseImperialCalendar(zone, locale, true);
+//                break;
+// Android-changed END: removed support for "buddhist" and "japanese".
             default:
                 throw new IllegalArgumentException("unknown calendar type: " + type);
             }
@@ -1586,6 +1594,7 @@
      */
     protected Calendar(TimeZone zone, Locale aLocale)
     {
+        // Android-added BEGIN: Allow aLocale == null
         // http://b/16938922.
         //
         // TODO: This is for backwards compatibility only. Seems like a better idea to throw
@@ -1593,6 +1602,7 @@
         if (aLocale == null) {
             aLocale = Locale.getDefault();
         }
+        // Android-added END: Allow aLocale == null
         fields = new int[FIELD_COUNT];
         isSet = new boolean[FIELD_COUNT];
         stamp = new int[FIELD_COUNT];
@@ -1656,18 +1666,22 @@
         return createCalendar(zone, aLocale);
     }
 
+    // Android-added BEGIN: add getJapaneseImperialInstance()
     /**
      * Create a Japanese Imperial Calendar.
      * @hide
      */
-    public static Calendar getJapanesImperialInstance(TimeZone zone, Locale aLocale) {
+    public static Calendar getJapaneseImperialInstance(TimeZone zone, Locale aLocale) {
         return new JapaneseImperialCalendar(zone, aLocale);
     }
+    // Android-added END: add getJapaneseImperialInstance()
 
     private static Calendar createCalendar(TimeZone zone,
                                            Locale aLocale)
     {
+        // Android-changed BEGIN: only support GregorianCalendar here
         return new GregorianCalendar(zone, aLocale);
+        // Android-changed END: only support GregorianCalendar here
     }
 
     /**
@@ -1758,7 +1772,12 @@
     public void setTimeInMillis(long millis) {
         // If we don't need to recalculate the calendar field values,
         // do nothing.
+// Android-changed BEGIN: Removed ZoneInfo support
         if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet) {
+//        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
+//            && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
+// Android-changed END: Removed ZoneInfo support
+
             return;
         }
         time = millis;
@@ -2041,11 +2060,13 @@
      * @since 1.6
      */
     public String getDisplayName(int field, int style, Locale locale) {
-        // Android-changed: Android has traditionally treated ALL_STYLES as SHORT, even though
+        // Android-changed BEGIN: Treat ALL_STYLES as SHORT
+        // Android has traditionally treated ALL_STYLES as SHORT, even though
         // it's not documented to be a valid value for style.
         if (style == ALL_STYLES) {
             style = SHORT;
         }
+        // Android-changed END: Treat ALL_STYLES as SHORT
         if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
                             ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
             return null;
@@ -2139,6 +2160,7 @@
                                     ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
             return null;
         }
+        // Android-added: Add complete() here to fix leniency, see http://b/35382060
         complete();
 
         String calendarType = getCalendarType();
@@ -2186,10 +2208,12 @@
             baseStyle < minStyle || baseStyle > maxStyle) {
             throw new IllegalArgumentException();
         }
-        // Android-changed: 3 is not a valid base style (1, 2 and 4 are, though), throw if used.
+        // Android-added BEGIN: Check for invalid baseStyle == 3
+        // 3 is not a valid base style (unlike 1, 2 and 4). Throw if used.
         if (baseStyle == 3) {
             throw new IllegalArgumentException();
         }
+        // Android-added END: Check for invalid baseStyle == 3
         if (locale == null) {
             throw new NullPointerException();
         }
diff --git a/ojluni/src/main/java/java/util/Formatter.java b/ojluni/src/main/java/java/util/Formatter.java
index ca1b990..43d5043 100644
--- a/ojluni/src/main/java/java/util/Formatter.java
+++ b/ojluni/src/main/java/java/util/Formatter.java
@@ -2710,6 +2710,7 @@
             if (s != null) {
                 try {
                     // Android-changed: FormatSpecifierParser passes in correct String.
+                    // index = Integer.parseInt(s.substring(0, s.length() - 1));
                     index = Integer.parseInt(s);
                 } catch (NumberFormatException x) {
                     assert(false);
@@ -2757,6 +2758,8 @@
             precision = -1;
             if (s != null) {
                 try {
+                    // Android-changed: FormatSpecifierParser passes in correct String.
+                    // precision = Integer.parseInt(s.substring(1));
                     precision = Integer.parseInt(s);
                     if (precision < 0)
                         throw new IllegalFormatPrecisionException(precision);
@@ -2789,7 +2792,7 @@
             return c;
         }
 
-        // Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+        // Android-changed BEGIN: FormatSpecifierParser passes in the values instead of a Matcher.
         FormatSpecifier(String indexStr, String flagsStr, String widthStr,
                         String precisionStr, String tTStr, String convStr) {
             int idx = 1;
@@ -2806,7 +2809,7 @@
             }
 
             conversion(convStr);
-
+        // Android-changed END: FormatSpecifierParser passes in the values instead of a Matcher.
             if (dt)
                 checkDateTime();
             else if (Conversion.isGeneral(c))
@@ -2998,6 +3001,7 @@
                 s = s.substring(0, precision);
             if (f.contains(Flags.UPPERCASE)) {
                 // Android-changed: Use provided locale instead of default, if it is non-null.
+                // s = s.toUpperCase();
                 s = s.toUpperCase(l != null ? l : Locale.getDefault());
             }
             a.append(justify(s));
@@ -3369,12 +3373,13 @@
                     newW = adjustWidth(width - exp.length - 1, f, neg);
                 localizedMagnitude(sb, mant, f, newW, l);
 
-                // Android-changed: Use localized exponent separator for %e.
+                // Android-changed BEGIN: Use localized exponent separator for %e.
                 Locale separatorLocale = (l != null) ? l : Locale.getDefault();
                 LocaleData localeData = LocaleData.get(separatorLocale);
                 sb.append(f.contains(Flags.UPPERCASE) ?
                         localeData.exponentSeparator.toUpperCase(separatorLocale) :
                         localeData.exponentSeparator.toLowerCase(separatorLocale));
+                // Android-changed END: Use localized exponent separator for %e.
 
                 Flags flags = f.dup().remove(Flags.GROUP);
                 char sign = exp[0];
@@ -4455,14 +4460,14 @@
                     grpSep = dfs.getGroupingSeparator();
                     DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
                     grpSize = df.getGroupingSize();
-                    // Android-changed: http://b/33245708 : Some locales have a group separator but
-                    // also patterns without groups. If we do not clear the group separator in these
-                    // cases a divide by zero is thrown when determining where to place the
-                    // separators.
+                    // Android-changed BEGIN: http://b/33245708
+                    // Some locales have a group separator but also patterns without groups.
+                    // If we do not clear the group separator in these cases a divide by zero
+                    // is thrown when determining where to place the separators.
                     if (!df.isGroupingUsed() || df.getGroupingSize() == 0) {
                         grpSep = '\0';
                     }
-                    // Android-changed: end http://b/33245708.
+                    // Android-changed END: http://b/33245708.
                 }
             }
 
diff --git a/ojluni/src/main/java/java/util/GregorianCalendar.java b/ojluni/src/main/java/java/util/GregorianCalendar.java
index 3d8a7c79..15c7652 100644
--- a/ojluni/src/main/java/java/util/GregorianCalendar.java
+++ b/ojluni/src/main/java/java/util/GregorianCalendar.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * 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
@@ -739,10 +739,12 @@
         gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
     }
 
+    // Android-added BEGIN
     GregorianCalendar(long milliseconds) {
         this();
         setTimeInMillis(milliseconds);
     }
+    // Android-added END
 
 /////////////////
 // Public methods
@@ -1078,8 +1080,7 @@
             }
 
             fd += delta; // fd is the expected fixed date after the calculation
-
-            // Android changed: move time zone related calculation to separate method.
+            // Android-changed BEGIN: time zone related calculation via helper methods
             // Calculate the time in the UTC time zone.
             long utcTime = (fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
 
@@ -1092,6 +1093,7 @@
 
             // Update the time and recompute the fields.
             setTimeInMillis(millis);
+            // Android-changed END: time zone related calculation via helper methods
         }
     }
 
@@ -2344,9 +2346,12 @@
         }
         if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
             if (tz instanceof ZoneInfo) {
-                // Android changed: libcore ZoneInfo uses different method to get offsets.
+                // Android changed BEGIN: use libcore.util.ZoneInfo
+                // The method name to get offsets differs from sun.util.calendar.ZoneInfo
+                // zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
                 ZoneInfo zoneInfo = (ZoneInfo) tz;
                 zoneOffset = zoneInfo.getOffsetsByUtcTime(time, zoneOffsets);
+                // Android-changed END: use libcore.util.ZoneInfo
             } else {
                 zoneOffset = tz.getOffset(time);
                 zoneOffsets[0] = tz.getRawOffset();
@@ -2796,11 +2801,11 @@
         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
         // or DST_OFFSET fields; then we use those fields.
         TimeZone zone = getZone();
-        // Android changed: move time zone related calculation to separate method.
-
+        // Android-changed BEGIN: time zone related calculation via helper methods
         int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
 
         millis = adjustForZoneAndDaylightSavingsTime(tzMask, millis, zone);
+        // Android-changed END: time zone related calculation via helper methods
 
         // Set this calendar's time in milliseconds
         time = millis;
@@ -2823,6 +2828,7 @@
         setFieldsNormalized(mask);
     }
 
+    // Android-added BEGIN: helper methods for time zone related calculation
     /**
      * Calculates the time in milliseconds that this calendar represents using the UTC time,
      * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
@@ -2992,6 +2998,7 @@
         }
         return dstOffset;
     }
+    // Android-added END: helper methods for time zone related calculation
 
     /**
      * Computes the fixed date under either the Gregorian or the
diff --git a/ojluni/src/main/java/java/util/Hashtable.java b/ojluni/src/main/java/java/util/Hashtable.java
index 9997b94..4f5394e 100644
--- a/ojluni/src/main/java/java/util/Hashtable.java
+++ b/ojluni/src/main/java/java/util/Hashtable.java
@@ -973,10 +973,10 @@
         HashtableEntry<Object, Object> entryStack = null;
 
         synchronized (this) {
-            // Write out the length, threshold, loadfactor
+            // Write out the threshold and loadFactor
             s.defaultWriteObject();
 
-            // Write out length, count of elements
+            // Write out the length and count of elements
             s.writeInt(table.length);
             s.writeInt(count);
 
@@ -1006,22 +1006,34 @@
     private void readObject(java.io.ObjectInputStream s)
          throws IOException, ClassNotFoundException
     {
-        // Read in the length, threshold, and loadfactor
+        // Read in the threshold and loadFactor
         s.defaultReadObject();
 
+        // Validate loadFactor (ignore threshold - it will be re-computed)
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new StreamCorruptedException("Illegal Load: " + loadFactor);
+
         // Read the original length of the array and number of elements
         int origlength = s.readInt();
         int elements = s.readInt();
 
-        // Compute new size with a bit of room 5% to grow but
-        // no larger than the original size.  Make the length
+        // Validate # of elements
+        if (elements < 0)
+            throw new StreamCorruptedException("Illegal # of Elements: " + elements);
+
+        // Clamp original length to be more than elements / loadFactor
+        // (this is the invariant enforced with auto-growth)
+        origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
+
+        // Compute new length with a bit of room 5% + 3 to grow but
+        // no larger than the clamped original length.  Make the length
         // odd if it's large enough, this helps distribute the entries.
         // Guard against the length ending up zero, that's not valid.
-        int length = (int)(elements * loadFactor) + (elements / 20) + 3;
+        int length = (int)((elements + elements / 20) / loadFactor) + 3;
+
         if (length > elements && (length & 1) == 0)
             length--;
-        if (origlength > 0 && length > origlength)
-            length = origlength;
+        length = Math.min(length, origlength);
         table = new HashtableEntry<?,?>[length];
         threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
         count = 0;
@@ -1032,7 +1044,7 @@
                 K key = (K)s.readObject();
             @SuppressWarnings("unchecked")
                 V value = (V)s.readObject();
-            // synch could be eliminated for performance
+            // sync is eliminated for performance
             reconstitutionPut(table, key, value);
         }
     }
@@ -1044,9 +1056,9 @@
      *
      * <p>This differs from the regular put method in several ways. No
      * checking for rehashing is necessary since the number of elements
-     * initially in the table is known. The modCount is not incremented
-     * because we are creating a new instance. Also, no return value
-     * is needed.
+     * initially in the table is known. The modCount is not incremented and
+     * there's no synchronization because we are creating a new instance.
+     * Also, no return value is needed.
      */
     private void reconstitutionPut(HashtableEntry<?,?>[] tab, K key, V value)
         throws StreamCorruptedException
diff --git a/ojluni/src/main/java/java/util/Locale.java b/ojluni/src/main/java/java/util/Locale.java
index 9c75a32..45949c6 100644
--- a/ojluni/src/main/java/java/util/Locale.java
+++ b/ojluni/src/main/java/java/util/Locale.java
@@ -886,7 +886,8 @@
      */
     public static Locale getDefault() {
         // do not synchronize this method - see 4071298
-        return defaultLocale;
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        return NoImagePreloadHolder.defaultLocale;
     }
 
     /**
@@ -972,6 +973,8 @@
     }
 
     private static Locale initDefault(Locale.Category category) {
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        final Locale defaultLocale = NoImagePreloadHolder.defaultLocale;
         return getInstance(
             System.getProperty(category.languageKey, defaultLocale.getLanguage()),
             System.getProperty(category.scriptKey, defaultLocale.getScript()),
@@ -1012,7 +1015,8 @@
     public static synchronized void setDefault(Locale newLocale) {
         setDefault(Category.DISPLAY, newLocale);
         setDefault(Category.FORMAT, newLocale);
-        defaultLocale = newLocale;
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        NoImagePreloadHolder.defaultLocale = newLocale;
         // Android-added: Keep ICU state in sync with java.util.
         ICU.setDefaultLocale(newLocale.toLanguageTag());
     }
@@ -2184,7 +2188,10 @@
      */
     private transient volatile int hashCodeValue = 0;
 
-    private volatile static Locale defaultLocale = initDefault();
+    // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+    private static class NoImagePreloadHolder {
+        public volatile static Locale defaultLocale = initDefault();
+    }
     private volatile static Locale defaultDisplayLocale = null;
     private volatile static Locale defaultFormatLocale = null;
 
diff --git a/ojluni/src/main/java/java/util/Spliterator.java b/ojluni/src/main/java/java/util/Spliterator.java
index 18cb082..35322b3 100644
--- a/ojluni/src/main/java/java/util/Spliterator.java
+++ b/ojluni/src/main/java/java/util/Spliterator.java
@@ -125,7 +125,7 @@
  * are encountered.
  *
  * @apiNote
- * <p>Spliterators, like {@code Iterators}s, are for traversing the elements of
+ * <p>Spliterators, like {@code Iterator}s, are for traversing the elements of
  * a source.  The {@code Spliterator} API was designed to support efficient
  * parallel traversal in addition to sequential traversal, by supporting
  * decomposition as well as single-element iteration.  In addition, the
diff --git a/ojluni/src/main/java/java/util/logging/Logger.java b/ojluni/src/main/java/java/util/logging/Logger.java
index c8b76f1..8cf98fe 100644
--- a/ojluni/src/main/java/java/util/logging/Logger.java
+++ b/ojluni/src/main/java/java/util/logging/Logger.java
@@ -805,6 +805,7 @@
      * @param   level   One of the message level identifiers, e.g., SEVERE
      * @param   msgSupplier   A function, which when called, produces the
      *                        desired log message
+     * @since 1.8
      */
     public void log(Level level, Supplier<String> msgSupplier) {
         if (!isLoggable(level)) {
diff --git a/ojluni/src/test/java/nio/file/TestUtil.java b/ojluni/src/test/java/nio/file/TestUtil.java
new file mode 100644
index 0000000..2d102fd
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/TestUtil.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Android-changed: Adapted from jdk/test/java/nio/file/TestUtil.java
+// Android-changed: Added package & made methods public
+package test.java.nio.file;
+
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Random;
+import java.io.IOException;
+
+public class TestUtil {
+    private TestUtil() {
+    }
+
+    static public Path createTemporaryDirectory(String where) throws IOException {
+        Path dir = FileSystems.getDefault().getPath(where);
+        return Files.createTempDirectory(dir, "name");
+    }
+
+    static public Path createTemporaryDirectory() throws IOException {
+        return Files.createTempDirectory("name");
+    }
+
+    static public void removeAll(Path dir) throws IOException {
+        Files.walkFileTree(dir, new FileVisitor<Path>() {
+            @Override
+            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+                try {
+                    Files.delete(file);
+                } catch (IOException x) {
+                    System.err.format("Unable to delete %s: %s\n", file, x);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+                try {
+                    Files.delete(dir);
+                } catch (IOException x) {
+                    System.err.format("Unable to delete %s: %s\n", dir, x);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult visitFileFailed(Path file, IOException exc) {
+                System.err.format("Unable to visit %s: %s\n", file, exc);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    static public void deleteUnchecked(Path file) {
+        try {
+            Files.delete(file);
+        } catch (IOException exc) {
+            System.err.format("Unable to delete %s: %s\n", file, exc);
+        }
+    }
+
+    /**
+     * Creates a directory tree in the given directory so that the total
+     * size of the path is more than 2k in size. This is used for long
+     * path tests on Windows.
+     */
+    static public Path createDirectoryWithLongPath(Path dir)
+        throws IOException
+    {
+        StringBuilder sb = new StringBuilder();
+        for (int i=0; i<240; i++) {
+            sb.append('A');
+        }
+        String name = sb.toString();
+        do {
+            dir = dir.resolve(name).resolve(".");
+            Files.createDirectory(dir);
+        } while (dir.toString().length() < 2048);
+        return dir;
+    }
+
+    /**
+     * Returns true if symbolic links are supported
+     */
+    static public boolean supportsLinks(Path dir) {
+        Path link = dir.resolve("testlink");
+        Path target = dir.resolve("testtarget");
+        try {
+            Files.createSymbolicLink(link, target);
+            Files.delete(link);
+            return true;
+        } catch (UnsupportedOperationException x) {
+            return false;
+        } catch (IOException x) {
+            return false;
+        }
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/AclEntryEmptySetTest.java b/ojluni/src/test/java/nio/file/attribute/AclEntryEmptySetTest.java
new file mode 100644
index 0000000..7f0c17b
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/AclEntryEmptySetTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 7076310
+ * @summary Test AclEntry.Builder setFlags and setPermissions with empty sets
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/AclEntry/EmptySet.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+
+import java.nio.file.attribute.*;
+import java.util.*;
+
+/*
+ * Test for bug 7076310 "(file) AclEntry.Builder setFlags throws
+ * IllegalArgumentException if set argument is empty"
+ * The bug is only applies when the given Set is NOT an instance of EnumSet.
+ *
+ * The setPermissions method also has the same problem.
+ */
+// Android-changed: Renamed from "EmptySet"
+public class AclEntryEmptySetTest {
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() {
+        Set<AclEntryFlag> flags = new HashSet<>();
+        AclEntry.newBuilder().setFlags(flags);
+
+        Set<AclEntryPermission> perms = new HashSet<>();
+        AclEntry.newBuilder().setPermissions(perms);
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/AclFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/AclFileAttributeViewTest.java
new file mode 100644
index 0000000..262aa81
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/AclFileAttributeViewTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333 6891404
+ * @summary Unit test for java.nio.file.attribute.AclFileAttribueView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+import static java.nio.file.attribute.AclEntryType.*;
+import static java.nio.file.attribute.AclEntryPermission.*;
+import static java.nio.file.attribute.AclEntryFlag.*;
+
+// Android-changed: Renamed from "Basic"
+public class AclFileAttributeViewTest {
+
+    static void printAcl(List<AclEntry> acl) {
+        for (AclEntry entry: acl) {
+            System.out.format("  %s%n", entry);
+        }
+    }
+
+    // sanity check read and writing ACL
+    static void testReadWrite(Path dir) throws IOException {
+        Path file = dir.resolve("foo");
+        if (Files.notExists(file))
+            Files.createFile(file);
+
+        AclFileAttributeView view =
+            Files.getFileAttributeView(file, AclFileAttributeView.class);
+
+        // print existing ACL
+        List<AclEntry> acl = view.getAcl();
+        System.out.println(" -- current ACL --");
+        printAcl(acl);
+
+        // insert entry to grant owner read access
+        UserPrincipal owner = view.getOwner();
+        AclEntry entry = AclEntry.newBuilder()
+            .setType(ALLOW)
+            .setPrincipal(owner)
+            .setPermissions(READ_DATA, READ_ATTRIBUTES)
+            .build();
+        System.out.println(" -- insert (entry 0) --");
+        System.out.format("  %s%n", entry);
+        acl.add(0, entry);
+        view.setAcl(acl);
+
+        // re-ACL and check entry
+        List<AclEntry> newacl = view.getAcl();
+        System.out.println(" -- current ACL --");
+        printAcl(acl);
+        if (!newacl.get(0).equals(entry)) {
+            throw new RuntimeException("Entry 0 is not expected");
+        }
+
+        // if PosixFileAttributeView then repeat test with OWNER@
+        if (Files.getFileStore(file).supportsFileAttributeView("posix")) {
+            owner = file.getFileSystem().getUserPrincipalLookupService()
+                .lookupPrincipalByName("OWNER@");
+            entry = AclEntry.newBuilder(entry).setPrincipal(owner).build();
+
+            System.out.println(" -- replace (entry 0) --");
+            System.out.format("  %s%n", entry);
+
+            acl.set(0, entry);
+            view.setAcl(acl);
+            newacl = view.getAcl();
+            System.out.println(" -- current ACL --");
+            printAcl(acl);
+            if (!newacl.get(0).equals(entry)) {
+                throw new RuntimeException("Entry 0 is not expected");
+            }
+        }
+    }
+
+    static FileAttribute<List<AclEntry>> asAclAttribute(final List<AclEntry> acl) {
+        return new FileAttribute<List<AclEntry>>() {
+            public String name() { return "acl:acl"; }
+            public List<AclEntry> value() { return acl; }
+        };
+    }
+
+    static void assertEquals(List<AclEntry> actual, List<AclEntry> expected) {
+        if (!actual.equals(expected)) {
+            System.err.format("Actual: %s\n", actual);
+            System.err.format("Expected: %s\n", expected);
+            throw new RuntimeException("ACL not expected");
+        }
+    }
+
+    // sanity check create a file or directory with initial ACL
+    static void testCreateFile(Path dir) throws IOException {
+        UserPrincipal user = Files.getOwner(dir);
+        AclFileAttributeView view;
+
+        // create file with initial ACL
+        System.out.println("-- create file with initial ACL --");
+        Path file = dir.resolve("gus");
+        List<AclEntry> fileAcl = Arrays.asList(
+            AclEntry.newBuilder()
+                .setType(AclEntryType.ALLOW)
+                .setPrincipal(user)
+                .setPermissions(SYNCHRONIZE, READ_DATA, WRITE_DATA,
+                    READ_ATTRIBUTES, READ_ACL, WRITE_ATTRIBUTES, DELETE)
+                .build());
+        Files.createFile(file, asAclAttribute(fileAcl));
+        view = Files.getFileAttributeView(file, AclFileAttributeView.class);
+        assertEquals(view.getAcl(), fileAcl);
+
+        // create directory with initial ACL
+        System.out.println("-- create directory with initial ACL --");
+        Path subdir = dir.resolve("stuff");
+        List<AclEntry> dirAcl = Arrays.asList(
+            AclEntry.newBuilder()
+                .setType(AclEntryType.ALLOW)
+                .setPrincipal(user)
+                .setPermissions(SYNCHRONIZE, ADD_FILE, DELETE)
+                .build(),
+            AclEntry.newBuilder(fileAcl.get(0))
+                .setFlags(FILE_INHERIT)
+                .build());
+        Files.createDirectory(subdir, asAclAttribute(dirAcl));
+        view = Files.getFileAttributeView(subdir, AclFileAttributeView.class);
+        assertEquals(view.getAcl(), dirAcl);
+    }
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws IOException {
+        // use work directory rather than system temporary directory to
+        // improve chances that ACLs are supported
+        Path dir = Paths.get("./work" + new Random().nextInt());
+        Files.createDirectory(dir);
+        try {
+            if (!Files.getFileStore(dir).supportsFileAttributeView("acl")) {
+                System.out.println("ACLs not supported - test skipped!");
+                return;
+            }
+            testReadWrite(dir);
+
+            // only currently feasible on Windows
+            if (System.getProperty("os.name").startsWith("Windows"))
+                testCreateFile(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewCreationTimeTest.java b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewCreationTimeTest.java
new file mode 100644
index 0000000..b393981
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewCreationTimeTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8011536
+ * @summary Basic test for creationTime attribute on platforms/file systems
+ *     that support it.
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.attribute.*;
+import java.time.Instant;
+import java.io.IOException;
+
+// Android-changed: Renamed from "CreationTime"
+public class BasicFileAttributeViewCreationTimeTest {
+
+    private static final java.io.PrintStream err = System.err;
+
+    /**
+     * Reads the creationTime attribute
+     */
+    private static FileTime creationTime(Path file) throws IOException {
+        return Files.readAttributes(file, BasicFileAttributes.class).creationTime();
+    }
+
+    /**
+     * Sets the creationTime attribute
+     */
+    private static void setCreationTime(Path file, FileTime time) throws IOException {
+        BasicFileAttributeView view =
+            Files.getFileAttributeView(file, BasicFileAttributeView.class);
+        view.setTimes(null, null, time);
+    }
+
+    static void test(Path top) throws IOException {
+        Path file = Files.createFile(top.resolve("foo"));
+
+        /**
+         * Check that creationTime reported
+         */
+        FileTime creationTime = creationTime(file);
+        Instant now = Instant.now();
+        if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) {
+            err.println("File creation time reported as: " + creationTime);
+            throw new RuntimeException("Expected to be close to: " + now);
+        }
+
+        /**
+         * Is the creationTime attribute supported here?
+         */
+        boolean supportsCreationTimeRead = false;
+        boolean supportsCreationTimeWrite = false;
+        String os = System.getProperty("os.name");
+        if (os.contains("OS X") && Files.getFileStore(file).type().equals("hfs")) {
+            supportsCreationTimeRead = true;
+        } else if (os.startsWith("Windows")) {
+            String type = Files.getFileStore(file).type();
+            if (type.equals("NTFS") || type.equals("FAT")) {
+                supportsCreationTimeRead = true;
+                supportsCreationTimeWrite = true;
+            }
+        }
+
+        /**
+         * If the creation-time attribute is supported then change the file's
+         * last modified and check that it doesn't change the creation-time.
+         */
+        if (supportsCreationTimeRead) {
+            // change modified time by +1 hour
+            Instant plusHour = Instant.now().plusSeconds(60L * 60L);
+            Files.setLastModifiedTime(file, FileTime.from(plusHour));
+            FileTime current = creationTime(file);
+            if (!current.equals(creationTime))
+                throw new RuntimeException("Creation time should not have changed");
+        }
+
+        /**
+         * If the creation-time attribute is supported and can be changed then
+         * check that the change is effective.
+         */
+        if (supportsCreationTimeWrite) {
+            // change creation time by -1 hour
+            Instant minusHour = Instant.now().minusSeconds(60L * 60L);
+            creationTime = FileTime.from(minusHour);
+            setCreationTime(file, creationTime);
+            FileTime current = creationTime(file);
+            if (Math.abs(creationTime.toMillis()-current.toMillis()) > 1000L)
+                throw new RuntimeException("Creation time not changed");
+        }
+    }
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws IOException {
+        // create temporary directory to run tests
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            test(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewTest.java
new file mode 100644
index 0000000..82f4e0e
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2008, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.BasicFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.io.*;
+
+// Android-changed: Renamed from "Basic"
+public class BasicFileAttributeViewTest {
+
+    static void check(boolean okay, String msg) {
+        if (!okay)
+            throw new RuntimeException(msg);
+    }
+
+    static void checkAttributesOfDirectory(Path dir)
+        throws IOException
+    {
+        BasicFileAttributes attrs = Files.readAttributes(dir, BasicFileAttributes.class);
+        check(attrs.isDirectory(), "is a directory");
+        check(!attrs.isRegularFile(), "is not a regular file");
+        check(!attrs.isSymbolicLink(), "is not a link");
+        check(!attrs.isOther(), "is not other");
+
+        // last-modified-time should match java.io.File in seconds
+        File f = new File(dir.toString());
+        check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS),
+              "last-modified time should be the same");
+    }
+
+    static void checkAttributesOfFile(Path dir, Path file)
+        throws IOException
+    {
+        BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class);
+        check(attrs.isRegularFile(), "is a regular file");
+        check(!attrs.isDirectory(), "is not a directory");
+        check(!attrs.isSymbolicLink(), "is not a link");
+        check(!attrs.isOther(), "is not other");
+
+        // size and last-modified-time should match java.io.File in seconds
+        File f = new File(file.toString());
+        check(f.length() == attrs.size(), "size should be the same");
+        check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS),
+              "last-modified time should be the same");
+
+        // copy last-modified time from directory to file,
+        // re-read attribtues, and check they match
+        BasicFileAttributeView view =
+            Files.getFileAttributeView(file, BasicFileAttributeView.class);
+        BasicFileAttributes dirAttrs = Files.readAttributes(dir, BasicFileAttributes.class);
+        view.setTimes(dirAttrs.lastModifiedTime(), null, null);
+
+        attrs = view.readAttributes();
+        check(attrs.lastModifiedTime().equals(dirAttrs.lastModifiedTime()),
+            "last-modified time should be equal");
+
+        // security tests
+        check (!(attrs instanceof PosixFileAttributes),
+            "should not be able to cast to PosixFileAttributes");
+    }
+
+    static void checkAttributesOfLink(Path link)
+        throws IOException
+    {
+        BasicFileAttributes attrs =
+            Files.readAttributes(link, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
+        check(attrs.isSymbolicLink(), "is a link");
+        check(!attrs.isDirectory(), "is a directory");
+        check(!attrs.isRegularFile(), "is not a regular file");
+        check(!attrs.isOther(), "is not other");
+    }
+
+    static void attributeReadWriteTests(Path dir)
+        throws IOException
+    {
+        // create file
+        Path file = dir.resolve("foo");
+        try (OutputStream out = Files.newOutputStream(file)) {
+            out.write("this is not an empty file".getBytes("UTF-8"));
+        }
+
+        // check attributes of directory and file
+        checkAttributesOfDirectory(dir);
+        checkAttributesOfFile(dir, file);
+
+        // symbolic links may be supported
+        Path link = dir.resolve("link");
+        try {
+            Files.createSymbolicLink(link, file);
+        } catch (UnsupportedOperationException x) {
+            return;
+        } catch (IOException x) {
+            return;
+        }
+        checkAttributesOfLink(link);
+    }
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws IOException {
+        // create temporary directory to run tests
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            attributeReadWriteTests(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/DosFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/DosFileAttributeViewTest.java
new file mode 100644
index 0000000..8386a31
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/DosFileAttributeViewTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.DosFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+
+// Android-changed: Renamed from "Basic"
+public class DosFileAttributeViewTest {
+
+    static void check(boolean okay) {
+        if (!okay)
+            throw new RuntimeException("Test failed");
+    }
+
+    // exercise each setter/getter method, leaving all attributes unset
+    static void testAttributes(DosFileAttributeView view) throws IOException {
+        view.setReadOnly(true);
+        check(view.readAttributes().isReadOnly());
+        view.setReadOnly(false);
+        check(!view.readAttributes().isReadOnly());
+        view.setHidden(true);
+        check(view.readAttributes().isHidden());
+        view.setHidden(false);
+        check(!view.readAttributes().isHidden());
+        view.setArchive(true);
+        check(view.readAttributes().isArchive());
+        view.setArchive(false);
+        check(!view.readAttributes().isArchive());
+        view.setSystem(true);
+        check(view.readAttributes().isSystem());
+        view.setSystem(false);
+        check(!view.readAttributes().isSystem());
+    }
+
+    // set the value of all attributes
+    static void setAll(DosFileAttributeView view, boolean value)
+        throws IOException
+    {
+        view.setReadOnly(value);
+        view.setHidden(value);
+        view.setArchive(value);
+        view.setSystem(value);
+    }
+
+    // read and write FAT attributes
+    static void readWriteTests(Path dir) throws IOException {
+
+        // create "foo" and test that we can read/write each FAT attribute
+        Path file = Files.createFile(dir.resolve("foo"));
+        try {
+            testAttributes(Files.getFileAttributeView(file, DosFileAttributeView.class));
+
+            // Following tests use a symbolic link so skip if not supported
+            if (!TestUtil.supportsLinks(dir))
+                return;
+
+            Path link = dir.resolve("link");
+            Files.createSymbolicLink(link, file);
+
+            // test following links
+            testAttributes(Files.getFileAttributeView(link, DosFileAttributeView.class));
+
+            // test not following links
+            try {
+                try {
+                    testAttributes(Files
+                        .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS));
+                } catch (IOException x) {
+                    // access to link attributes not supported
+                    return;
+                }
+
+                // set all attributes on link
+                // run test on target of link (which leaves them all un-set)
+                // check that attributes of link remain all set
+                setAll(Files
+                    .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS), true);
+                testAttributes(Files
+                    .getFileAttributeView(link, DosFileAttributeView.class));
+                DosFileAttributes attrs =
+                    Files.getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS)
+                         .readAttributes();
+                check(attrs.isReadOnly());
+                check(attrs.isHidden());
+                check(attrs.isArchive());
+                check(attrs.isSystem());
+                setAll(Files
+                    .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS), false);
+
+                // set all attributes on target
+                // run test on link (which leaves them all un-set)
+                // check that attributes of target remain all set
+                setAll(Files.getFileAttributeView(link, DosFileAttributeView.class), true);
+                testAttributes(Files
+                    .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS));
+                attrs = Files.getFileAttributeView(link, DosFileAttributeView.class).readAttributes();
+                check(attrs.isReadOnly());
+                check(attrs.isHidden());
+                check(attrs.isArchive());
+                check(attrs.isSystem());
+                setAll(Files.getFileAttributeView(link, DosFileAttributeView.class), false);
+            } finally {
+                TestUtil.deleteUnchecked(link);
+            }
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+    }
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws IOException {
+        // create temporary directory to run tests
+        Path dir = TestUtil.createTemporaryDirectory();
+
+        try {
+            // skip test if DOS file attributes not supported
+            if (!Files.getFileStore(dir).supportsFileAttributeView("dos")) {
+                System.out.println("DOS file attribute not supported.");
+                return;
+            }
+            readWriteTests(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/FileTimeTest.java b/ojluni/src/test/java/nio/file/attribute/FileTimeTest.java
new file mode 100644
index 0000000..43c5d61
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/FileTimeTest.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 6844313 8011647
+ * @summary Unit test for java.nio.file.FileTime
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/FileTime/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
+import java.util.concurrent.TimeUnit;
+import static java.util.concurrent.TimeUnit.*;
+import java.util.Random;
+import java.util.EnumSet;
+
+// Android-changed: Renamed from "Basic"
+public class FileTimeTest {
+
+    static final Random rand = new Random();
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() {
+        long now = System.currentTimeMillis();
+        long tomorrowInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) + 1;
+        long yesterdayInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) - 1;
+
+        Instant nowInstant = Instant.ofEpochMilli(now);
+
+        // equals
+        eq(now, MILLISECONDS, now, MILLISECONDS);
+        eq(now, MILLISECONDS, now*1000L, MICROSECONDS);
+        neq(now, MILLISECONDS, 0, MILLISECONDS);
+        neq(now, MILLISECONDS, 0, MICROSECONDS);
+
+        eq(nowInstant, now, MILLISECONDS);
+        eq(nowInstant, now*1000L, MICROSECONDS);
+        neq(nowInstant, 0, MILLISECONDS);
+        neq(nowInstant, 0, MICROSECONDS);
+
+        // compareTo
+        cmp(now, MILLISECONDS, now, MILLISECONDS, 0);
+        cmp(now, MILLISECONDS, now*1000L, MICROSECONDS, 0);
+        cmp(now, MILLISECONDS, now-1234, MILLISECONDS, 1);
+        cmp(now, MILLISECONDS, now+1234, MILLISECONDS, -1);
+
+        cmp(tomorrowInDays, DAYS, now, MILLISECONDS, 1);
+        cmp(now, MILLISECONDS, tomorrowInDays, DAYS, -1);
+        cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1);
+        cmp(now, MILLISECONDS, yesterdayInDays, DAYS, 1);
+        cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1);
+
+        cmp(Long.MAX_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, 1);
+        cmp(Long.MAX_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, 1);
+        cmp(Long.MIN_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, -1);
+        cmp(Long.MIN_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, -1);
+
+        cmp(Instant.MIN, Long.MIN_VALUE, DAYS, 1);
+        cmp(Instant.MIN, Long.MIN_VALUE, HOURS, 1);
+        cmp(Instant.MIN, Long.MIN_VALUE, MINUTES, 1);
+        cmp(Instant.MIN, Long.MIN_VALUE, SECONDS, 1);
+        cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 1, SECONDS, 1);
+        cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 100, SECONDS, 1);
+        cmp(Instant.MIN, Instant.MIN.getEpochSecond(), SECONDS, 0);
+
+        cmp(Instant.MAX, Long.MAX_VALUE, DAYS, -1);
+        cmp(Instant.MAX, Long.MAX_VALUE, HOURS, -1);
+        cmp(Instant.MAX, Long.MAX_VALUE, MINUTES, -1);
+        cmp(Instant.MAX, Long.MAX_VALUE, SECONDS, -1);
+        cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 1, SECONDS, -1);
+        cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 100, SECONDS, -1);
+        cmp(Instant.MAX, Instant.MAX.getEpochSecond(), SECONDS, 0);
+
+        cmp(nowInstant, now, MILLISECONDS, 0);
+        cmp(nowInstant, now*1000L, MICROSECONDS, 0);
+        cmp(nowInstant, now-1234, MILLISECONDS, 1);
+        cmp(nowInstant, now+1234, MILLISECONDS, -1);
+        cmp(nowInstant, tomorrowInDays, DAYS, -1);
+        cmp(nowInstant, yesterdayInDays, DAYS, 1);
+
+        // to(TimeUnit)
+        to(MILLISECONDS.convert(1, DAYS) - 1, MILLISECONDS);
+        to(MILLISECONDS.convert(1, DAYS) + 0, MILLISECONDS);
+        to(MILLISECONDS.convert(1, DAYS) + 1, MILLISECONDS);
+        to(1, MILLISECONDS);
+        to(0, MILLISECONDS);
+        to(1, MILLISECONDS);
+        to(MILLISECONDS.convert(-1, DAYS) - 1, MILLISECONDS);
+        to(MILLISECONDS.convert(-1, DAYS) + 0, MILLISECONDS);
+        to(MILLISECONDS.convert(-1, DAYS) + 1, MILLISECONDS);
+        for (TimeUnit unit: TimeUnit.values()) {
+            for (int i=0; i<100; i++) { to(rand.nextLong(), unit); }
+            to(Long.MIN_VALUE, unit);
+            to(Long.MAX_VALUE, unit);
+        }
+
+        // toInstant()
+        int N = 1000;
+        for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) {
+            for (int i = 0; i < N; i++) {
+                long value = rand.nextLong();
+                FileTime ft = FileTime.from(value, unit);
+                Instant instant = ft.toInstant();
+                if (instant != Instant.MIN && instant != Instant.MAX) {
+                    eqTime(value, unit, instant);
+                }
+            }
+        }
+        for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) {
+            long value = Long.MIN_VALUE;
+            FileTime ft = FileTime.from(value, unit);
+            Instant instant = ft.toInstant();
+            if (unit.compareTo(TimeUnit.SECONDS) < 0) {
+                eqTime(value, unit, instant);
+            } else if (!instant.equals(Instant.MIN)) {
+                throw new RuntimeException("should overflow to MIN");
+            }
+            value = Long.MAX_VALUE;
+            ft = FileTime.from(value, unit);
+            instant = ft.toInstant();
+            if (unit.compareTo(TimeUnit.SECONDS) < 0) {
+                eqTime(value, unit, instant);
+            } else if (!instant.equals(Instant.MAX)) {
+                throw new RuntimeException("should overflow to MAX");
+            }
+        }
+
+        // from(Instant)
+        final long MAX_SECOND = 31556889864403199L;
+        for (int i = 0; i < N; i++) {
+            long v = rand.nextLong();
+            long secs = v % MAX_SECOND;
+            Instant instant = Instant.ofEpochSecond(secs, rand.nextInt(1000_000_000));
+            FileTime ft = FileTime.from(instant);
+            if (!ft.toInstant().equals(instant) || ft.to(SECONDS)  != secs) {
+                throw new RuntimeException("from(Instant) failed");
+            }
+            long millis = v;
+            instant = Instant.ofEpochMilli(millis);
+            ft = FileTime.from(instant);
+            if (!ft.toInstant().equals(instant) ||
+                ft.toMillis()  != instant.toEpochMilli()) {
+                throw new RuntimeException("from(Instant) failed");
+            }
+            long nanos = v;
+            ft = FileTime.from(nanos, NANOSECONDS);
+            secs = nanos / 1000_000_000;
+            nanos = nanos % 1000_000_000;
+            instant = Instant.ofEpochSecond(secs, nanos);
+            if (!ft.equals(FileTime.from(instant))) {
+                throw new RuntimeException("from(Instant) failed");
+            }
+        }
+
+        // toString
+        ts(1L, DAYS, "1970-01-02T00:00:00Z");
+        ts(1L, HOURS, "1970-01-01T01:00:00Z");
+        ts(1L, MINUTES, "1970-01-01T00:01:00Z");
+        ts(1L, SECONDS, "1970-01-01T00:00:01Z");
+        ts(1L, MILLISECONDS, "1970-01-01T00:00:00.001Z");
+        ts(1L, MICROSECONDS, "1970-01-01T00:00:00.000001Z");
+        ts(1L, NANOSECONDS, "1970-01-01T00:00:00.000000001Z");
+        ts(999999999L, NANOSECONDS, "1970-01-01T00:00:00.999999999Z");
+        ts(9999999999L, NANOSECONDS, "1970-01-01T00:00:09.999999999Z");
+
+        ts(-1L, DAYS, "1969-12-31T00:00:00Z");
+        ts(-1L, HOURS, "1969-12-31T23:00:00Z");
+        ts(-1L, MINUTES, "1969-12-31T23:59:00Z");
+        ts(-1L, SECONDS, "1969-12-31T23:59:59Z");
+        ts(-1L, MILLISECONDS, "1969-12-31T23:59:59.999Z");
+        ts(-1L, MICROSECONDS, "1969-12-31T23:59:59.999999Z");
+        ts(-1L, NANOSECONDS, "1969-12-31T23:59:59.999999999Z");
+        ts(-999999999L, NANOSECONDS, "1969-12-31T23:59:59.000000001Z");
+        ts(-9999999999L, NANOSECONDS, "1969-12-31T23:59:50.000000001Z");
+
+        ts(-62135596799999L, MILLISECONDS, "0001-01-01T00:00:00.001Z");
+        ts(-62135596800000L, MILLISECONDS, "0001-01-01T00:00:00Z");
+        ts(-62135596800001L, MILLISECONDS, "-0001-12-31T23:59:59.999Z");
+
+        ts(253402300799999L, MILLISECONDS, "9999-12-31T23:59:59.999Z");
+        ts(-377642044800001L, MILLISECONDS, "-9999-12-31T23:59:59.999Z");
+
+        // NTFS epoch in usec.
+        ts(-11644473600000000L, MICROSECONDS, "1601-01-01T00:00:00Z");
+
+        ts(Instant.MIN, "-1000000001-01-01T00:00:00Z");
+        ts(Instant.MAX, "1000000000-12-31T23:59:59.999999999Z");
+
+        try {
+            FileTime.from(0L, null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException npe) { }
+        try {
+            FileTime.from(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException npe) { }
+
+        FileTime time = FileTime.fromMillis(now);
+        if (time.equals(null))
+            throw new RuntimeException("should not be equal to null");
+        try {
+            time.compareTo(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException npe) { }
+
+        // Instant + toMilli() overflow
+        overflow(Long.MAX_VALUE,
+                 FileTime.from(Instant.MAX).toMillis());
+        overflow(Long.MAX_VALUE,
+                 FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1))
+                         .toMillis());
+        overflow(Long.MIN_VALUE,
+                 FileTime.from(Instant.MIN).toMillis());
+        overflow(Long.MIN_VALUE,
+                 FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1))
+                         .toMillis());
+
+        // Instant + to(TimeUnit) overflow
+        overflow(Long.MAX_VALUE,
+                 FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1))
+                         .to(MILLISECONDS));
+        overflow(Long.MAX_VALUE,
+                 FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000,
+                                                     MILLISECONDS.toNanos(1000)))
+                    .to(MILLISECONDS));
+        overflow(Long.MIN_VALUE,
+                 FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1))
+                         .to(MILLISECONDS));
+        overflow(Long.MIN_VALUE,
+                 FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000,
+                                                     -MILLISECONDS.toNanos(1)))
+            .to(MILLISECONDS));
+    }
+
+    static void overflow(long minmax, long v) {
+        if (v != minmax)
+            throw new RuntimeException("saturates to Long.MIN/MAX_VALUE expected");
+    }
+
+    static void cmp(long v1, TimeUnit u1, long v2, TimeUnit u2, int expected) {
+        int result = FileTime.from(v1, u1).compareTo(FileTime.from(v2, u2));
+        if (result != expected)
+            throw new RuntimeException("unexpected order");
+    }
+
+    static void cmp(Instant ins, long v2, TimeUnit u2, int expected) {
+        int result = FileTime.from(ins).compareTo(FileTime.from(v2, u2));
+        if (result != expected)
+            throw new RuntimeException("unexpected order");
+    }
+
+    static void eq(long v1, TimeUnit u1, long v2, TimeUnit u2) {
+        FileTime t1 = FileTime.from(v1, u1);
+        FileTime t2 = FileTime.from(v2, u2);
+        if (!t1.equals(t2))
+            throw new RuntimeException("not equal");
+        if (t1.hashCode() != t2.hashCode())
+            throw new RuntimeException("hashCodes should be equal");
+    }
+
+    static void eq(Instant ins, long v2, TimeUnit u2) {
+        FileTime t1 = FileTime.from(ins);
+        FileTime t2 = FileTime.from(v2, u2);
+        if (!t1.equals(t2))
+            throw new RuntimeException("not equal");
+        if (t1.hashCode() != t2.hashCode())
+            throw new RuntimeException("hashCodes should be equal");
+    }
+
+    static void eqTime(long value, TimeUnit unit, Instant instant) {
+        long secs = SECONDS.convert(value, unit);
+        long nanos = NANOSECONDS.convert(value - unit.convert(secs, SECONDS), unit);
+        if (nanos < 0) {    // normalize nanoOfSecond to positive
+            secs -= 1;
+            nanos += 1000_000_000;
+        }
+        if (secs != instant.getEpochSecond() || (int)nanos != instant.getNano()) {
+            System.err.println(" ins=" + instant);
+            throw new RuntimeException("ft and instant are not the same time point");
+        }
+    }
+
+    static void neq(long v1, TimeUnit u1, long v2, TimeUnit u2) {
+        FileTime t1 = FileTime.from(v1, u1);
+        FileTime t2 = FileTime.from(v2, u2);
+        if (t1.equals(t2))
+            throw new RuntimeException("should not be equal");
+    }
+
+    static void neq(Instant ins, long v2, TimeUnit u2) {
+        FileTime t1 = FileTime.from(ins);
+        FileTime t2 = FileTime.from(v2, u2);
+        if (t1.equals(t2))
+            throw new RuntimeException("should not be equal");
+    }
+
+    static void to(long v, TimeUnit unit) {
+        FileTime t = FileTime.from(v, unit);
+        for (TimeUnit u: TimeUnit.values()) {
+            long result = t.to(u);
+            long expected = u.convert(v, unit);
+            if (result != expected) {
+                throw new RuntimeException("unexpected result");
+            }
+        }
+    }
+
+    static void ts(long v, TimeUnit unit, String expected) {
+        String result = FileTime.from(v, unit).toString();
+        if (!result.equals(expected)) {
+            System.err.format("FileTime.from(%d, %s).toString() failed\n", v, unit);
+            System.err.format("Expected: %s\n", expected);
+            System.err.format("     Got: %s\n", result);
+            throw new RuntimeException();
+        }
+    }
+
+    static void ts(Instant instant, String expected) {
+        String result = FileTime.from(instant).toString();
+        if (!result.equals(expected)) {
+            System.err.format("FileTime.from(%s).toString() failed\n", instant);
+            System.err.format("Expected: %s\n", expected);
+            System.err.format("     Got: %s\n", result);
+            throw new RuntimeException();
+        }
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/PosixFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/PosixFileAttributeViewTest.java
new file mode 100644
index 0000000..7825837
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/PosixFileAttributeViewTest.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.PosixFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Unit test for PosixFileAttributeView, passing silently if this attribute
+ * view is not available.
+ */
+
+// Android-changed: Renamed from "Basic"
+public class PosixFileAttributeViewTest {
+
+    /**
+     * Use view to update permission to the given mode and check that the
+     * permissions have been updated.
+     */
+    static void testPermissions(Path file, String mode) throws IOException {
+        System.out.format("change mode: %s\n", mode);
+        Set<PosixFilePermission> perms = PosixFilePermissions.fromString(mode);
+
+        // change permissions and re-read them.
+        Files.setPosixFilePermissions(file, perms);
+        Set<PosixFilePermission> current = Files.getPosixFilePermissions(file);
+        if (!current.equals(perms)) {
+            throw new RuntimeException("Actual permissions: " +
+                PosixFilePermissions.toString(current) + ", expected: " +
+                PosixFilePermissions.toString(perms));
+        }
+
+        // repeat test using setAttribute/getAttribute
+        Files.setAttribute(file, "posix:permissions", perms);
+        current = (Set<PosixFilePermission>)Files.getAttribute(file, "posix:permissions");
+        if (!current.equals(perms)) {
+            throw new RuntimeException("Actual permissions: " +
+                PosixFilePermissions.toString(current) + ", expected: " +
+                PosixFilePermissions.toString(perms));
+        }
+    }
+
+    /**
+     * Check that the actual permissions of a file match or make it more
+     * secure than requested
+     */
+    static void checkSecure(Set<PosixFilePermission> requested,
+                            Set<PosixFilePermission> actual)
+    {
+        for (PosixFilePermission perm: actual) {
+            if (!requested.contains(perm)) {
+                throw new RuntimeException("Actual permissions: " +
+                    PosixFilePermissions.toString(actual) + ", requested: " +
+                    PosixFilePermissions.toString(requested) +
+                    " - file is less secure than requested");
+            }
+        }
+    }
+
+    /**
+     * Create file with given mode and check that the file is created with a
+     * mode that is not less secure
+     */
+    static void createWithPermissions(Path file,
+                                      String mode)
+        throws IOException
+    {
+        Set<PosixFilePermission> requested = PosixFilePermissions.fromString(mode);
+        FileAttribute<Set<PosixFilePermission>> attr =
+            PosixFilePermissions.asFileAttribute(requested);
+        System.out.format("create file with mode: %s\n", mode);
+        Files.createFile(file, attr);
+        try {
+            checkSecure(requested,
+                Files.getFileAttributeView(file, PosixFileAttributeView.class)
+                     .readAttributes()
+                     .permissions());
+        } finally {
+            Files.delete(file);
+        }
+
+        System.out.format("create directory with mode: %s\n", mode);
+        Files.createDirectory(file, attr);
+        try {
+            checkSecure(requested,
+                Files.getFileAttributeView(file, PosixFileAttributeView.class)
+                     .readAttributes()
+                     .permissions());
+        } finally {
+            Files.delete(file);
+        }
+    }
+
+    /**
+     * Test the setPermissions/permissions methods.
+     */
+    static void permissionTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Permission Tests  --");
+
+        // create file and test updating and reading its permissions
+        Path file = dir.resolve("foo");
+        System.out.format("create %s\n", file);
+        Files.createFile(file);
+        try {
+            // get initial permissions so that we can restore them later
+            PosixFileAttributeView view =
+                Files.getFileAttributeView(file, PosixFileAttributeView.class);
+            Set<PosixFilePermission> save = view.readAttributes()
+                .permissions();
+
+            // test various modes
+            try {
+                testPermissions(file, "---------");
+                testPermissions(file, "r--------");
+                testPermissions(file, "-w-------");
+                testPermissions(file, "--x------");
+                testPermissions(file, "rwx------");
+                testPermissions(file, "---r-----");
+                testPermissions(file, "----w----");
+                testPermissions(file, "-----x---");
+                testPermissions(file, "---rwx---");
+                testPermissions(file, "------r--");
+                testPermissions(file, "-------w-");
+                testPermissions(file, "--------x");
+                testPermissions(file, "------rwx");
+                testPermissions(file, "r--r-----");
+                testPermissions(file, "r--r--r--");
+                testPermissions(file, "rw-rw----");
+                testPermissions(file, "rwxrwx---");
+                testPermissions(file, "rw-rw-r--");
+                testPermissions(file, "r-xr-x---");
+                testPermissions(file, "r-xr-xr-x");
+                testPermissions(file, "rwxrwxrwx");
+            } finally {
+                view.setPermissions(save);
+            }
+        } finally {
+            Files.delete(file);
+        }
+
+        // create link (to file that doesn't exist) and test reading of
+        // permissions
+        if (TestUtil.supportsLinks(dir)) {
+            Path link = dir.resolve("link");
+            System.out.format("create link %s\n", link);
+            Files.createSymbolicLink(link, file);
+            try {
+                PosixFileAttributes attrs =
+                    Files.getFileAttributeView(link,
+                                               PosixFileAttributeView.class,
+                                               NOFOLLOW_LINKS)
+                         .readAttributes();
+                if (!attrs.isSymbolicLink()) {
+                    throw new RuntimeException("not a link");
+                }
+            } finally {
+                Files.delete(link);
+            }
+        }
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test creating a file and directory with initial permissios
+     */
+    static void createTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Create Tests  --");
+
+        Path file = dir.resolve("foo");
+
+        createWithPermissions(file, "---------");
+        createWithPermissions(file, "r--------");
+        createWithPermissions(file, "-w-------");
+        createWithPermissions(file, "--x------");
+        createWithPermissions(file, "rwx------");
+        createWithPermissions(file, "---r-----");
+        createWithPermissions(file, "----w----");
+        createWithPermissions(file, "-----x---");
+        createWithPermissions(file, "---rwx---");
+        createWithPermissions(file, "------r--");
+        createWithPermissions(file, "-------w-");
+        createWithPermissions(file, "--------x");
+        createWithPermissions(file, "------rwx");
+        createWithPermissions(file, "r--r-----");
+        createWithPermissions(file, "r--r--r--");
+        createWithPermissions(file, "rw-rw----");
+        createWithPermissions(file, "rwxrwx---");
+        createWithPermissions(file, "rw-rw-r--");
+        createWithPermissions(file, "r-xr-x---");
+        createWithPermissions(file, "r-xr-xr-x");
+        createWithPermissions(file, "rwxrwxrwx");
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test setOwner/setGroup methods - this test simply exercises the
+     * methods to avoid configuration.
+     */
+    static void ownerTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Owner Tests  --");
+
+        Path file = dir.resolve("gus");
+        System.out.format("create %s\n", file);
+
+        Files.createFile(file);
+        try {
+
+            // read attributes of directory to get owner/group
+            PosixFileAttributeView view =
+                Files.getFileAttributeView(file, PosixFileAttributeView.class);
+            PosixFileAttributes attrs = view.readAttributes();
+
+            // set to existing owner/group
+            view.setOwner(attrs.owner());
+            view.setGroup(attrs.group());
+
+            // repeat test using set/getAttribute
+            UserPrincipal owner = (UserPrincipal)Files.getAttribute(file, "posix:owner");
+            Files.setAttribute(file, "posix:owner", owner);
+            UserPrincipal group = (UserPrincipal)Files.getAttribute(file, "posix:group");
+            Files.setAttribute(file, "posix:group", group);
+
+        } finally {
+            Files.delete(file);
+        }
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test the lookupPrincipalByName/lookupPrincipalByGroupName methods
+     */
+    static void lookupPrincipalTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Lookup UserPrincipal Tests --");
+
+        UserPrincipalLookupService lookupService = dir.getFileSystem()
+            .getUserPrincipalLookupService();
+
+        // read attributes of directory to get owner/group
+        PosixFileAttributes attrs = Files.readAttributes(dir, PosixFileAttributes.class);
+
+        // lookup owner and check it matches file's owner
+        System.out.format("lookup: %s\n", attrs.owner().getName());
+        try {
+            UserPrincipal owner = lookupService.lookupPrincipalByName(attrs.owner().getName());
+            if (owner instanceof GroupPrincipal)
+                throw new RuntimeException("owner is a group?");
+            if (!owner.equals(attrs.owner()))
+                throw new RuntimeException("owner different from file owner");
+        } catch (UserPrincipalNotFoundException x) {
+            System.out.println("user not found - test skipped");
+        }
+
+        // lookup group and check it matches file's group-owner
+        System.out.format("lookup group: %s\n", attrs.group().getName());
+        try {
+            GroupPrincipal group = lookupService.lookupPrincipalByGroupName(attrs.group().getName());
+            if (!group.equals(attrs.group()))
+                throw new RuntimeException("group different from file group-owner");
+        } catch (UserPrincipalNotFoundException x) {
+            System.out.println("group not found - test skipped");
+        }
+
+        // test that UserPrincipalNotFoundException is thrown
+        String invalidPrincipal = "scumbag99";
+        try {
+            System.out.format("lookup: %s\n", invalidPrincipal);
+            lookupService.lookupPrincipalByName(invalidPrincipal);
+            throw new RuntimeException("'" + invalidPrincipal + "' is a valid user?");
+        } catch (UserPrincipalNotFoundException x) {
+        }
+        try {
+            System.out.format("lookup group: %s\n", invalidPrincipal);
+            lookupService.lookupPrincipalByGroupName("idonotexist");
+            throw new RuntimeException("'" + invalidPrincipal + "' is a valid group?");
+        } catch (UserPrincipalNotFoundException x) {
+        }
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test various exceptions are thrown as expected
+     */
+    @SuppressWarnings("unchecked")
+    static void exceptionsTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Exceptions --");
+
+        PosixFileAttributeView view =
+            Files.getFileAttributeView(dir,PosixFileAttributeView.class);
+
+        // NullPointerException
+        try {
+            view.setOwner(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            view.setGroup(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+
+        UserPrincipalLookupService lookupService = dir.getFileSystem()
+            .getUserPrincipalLookupService();
+        try {
+            lookupService.lookupPrincipalByName(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            lookupService.lookupPrincipalByGroupName(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            view.setPermissions(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            Set<PosixFilePermission> perms = new HashSet<>();
+            perms.add(null);
+            view.setPermissions(perms);
+            throw new RuntimeException("NullPointerException not thrown");
+        }  catch (NullPointerException x) {
+        }
+
+        // ClassCastException
+        try {
+            Set perms = new HashSet();  // raw type
+            perms.add(new Object());
+            view.setPermissions(perms);
+            throw new RuntimeException("ClassCastException not thrown");
+        }  catch (ClassCastException x) {
+        }
+
+        System.out.println("OKAY");
+    }
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            if (!Files.getFileStore(dir).supportsFileAttributeView("posix")) {
+                System.out.println("PosixFileAttributeView not supported");
+                return;
+            }
+
+            permissionTests(dir);
+            createTests(dir);
+            ownerTests(dir);
+            lookupPrincipalTests(dir);
+            exceptionsTests(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/UserDefinedFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/UserDefinedFileAttributeViewTest.java
new file mode 100644
index 0000000..6fb3c78
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/UserDefinedFileAttributeViewTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.UserDefinedFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Random;
+import java.io.IOException;
+
+// Android-changed: Renamed from "Basic"
+public class UserDefinedFileAttributeViewTest {
+
+    private static Random rand = new Random();
+
+    private static final String ATTR_NAME = "mime_type";
+    private static final String ATTR_VALUE = "text/plain";
+    private static final String ATTR_VALUE2 = "text/html";
+
+    static interface Task {
+        void run() throws Exception;
+    }
+
+    static void tryCatch(Class<? extends Throwable> ex, Task task) {
+        boolean caught = false;
+        try {
+            task.run();
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass())) {
+                caught = true;
+            } else {
+                throw new RuntimeException(x);
+            }
+        }
+        if (!caught)
+            throw new RuntimeException(ex.getName() + " expected");
+    }
+
+    static void expectNullPointerException(Task task) {
+        tryCatch(NullPointerException.class, task);
+    }
+
+    static boolean hasAttribute(UserDefinedFileAttributeView view, String attr)
+        throws IOException
+    {
+        for (String name: view.list()) {
+            if (name.equals(ATTR_NAME))
+                return true;
+        }
+        return false;
+    }
+
+    static void test(Path file, LinkOption... options) throws IOException {
+        final UserDefinedFileAttributeView view =
+            Files.getFileAttributeView(file, UserDefinedFileAttributeView.class, options);
+        ByteBuffer buf = rand.nextBoolean() ?
+            ByteBuffer.allocate(100) : ByteBuffer.allocateDirect(100);
+
+        // Test: write
+        buf.put(ATTR_VALUE.getBytes()).flip();
+        int size = buf.remaining();
+        int nwrote = view.write(ATTR_NAME, buf);
+        if (nwrote != size)
+            throw new RuntimeException("Unexpected number of bytes written");
+
+        // Test: size
+        if (view.size(ATTR_NAME) != size)
+            throw new RuntimeException("Unexpected size");
+
+        // Test: read
+        buf.clear();
+        int nread = view.read(ATTR_NAME, buf);
+        if (nread != size)
+            throw new RuntimeException("Unexpected number of bytes read");
+        buf.flip();
+        String value = Charset.defaultCharset().decode(buf).toString();
+        if (!value.equals(ATTR_VALUE))
+            throw new RuntimeException("Unexpected attribute value");
+
+        // Test: read with insufficient space
+        tryCatch(IOException.class, new Task() {
+            public void run() throws IOException {
+                view.read(ATTR_NAME, ByteBuffer.allocateDirect(1));
+            }});
+
+        // Test: replace value
+        buf.clear();
+        buf.put(ATTR_VALUE2.getBytes()).flip();
+        size = buf.remaining();
+        view.write(ATTR_NAME, buf);
+        if (view.size(ATTR_NAME) != size)
+            throw new RuntimeException("Unexpected size");
+
+        // Test: list
+        if (!hasAttribute(view, ATTR_NAME))
+            throw new RuntimeException("Attribute name not in list");
+
+        // Test: delete
+        view.delete(ATTR_NAME);
+        if (hasAttribute(view, ATTR_NAME))
+            throw new RuntimeException("Attribute name in list");
+
+        // Test: dynamic access
+        String name = "user:" + ATTR_NAME;
+        byte[] valueAsBytes = ATTR_VALUE.getBytes();
+        Files.setAttribute(file, name, valueAsBytes);
+        byte[] actualAsBytes = (byte[])Files.getAttribute(file, name);
+        if (!Arrays.equals(valueAsBytes, actualAsBytes))
+            throw new RuntimeException("Unexpected attribute value");
+        Map<String,?> map = Files.readAttributes(file, name);
+        if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+            throw new RuntimeException("Unexpected attribute value");
+        map = Files.readAttributes(file, "user:*");
+        if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+            throw new RuntimeException("Unexpected attribute value");
+    }
+
+    static void miscTests(final Path file) throws IOException {
+        final UserDefinedFileAttributeView view =
+            Files.getFileAttributeView(file, UserDefinedFileAttributeView.class);
+        view.write(ATTR_NAME, ByteBuffer.wrap(ATTR_VALUE.getBytes()));
+
+        // NullPointerException
+        final ByteBuffer buf = ByteBuffer.allocate(100);
+
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.read(null, buf);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.read(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.write(null, buf);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+               view.write(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.size(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.delete(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                Files.getAttribute(file, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                Files.getAttribute(file, "user:" + ATTR_NAME, (LinkOption[])null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                Files.setAttribute(file, "user:" + ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                Files.setAttribute(file, null, new byte[0]);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                Files.setAttribute(file, "user: " + ATTR_NAME, new byte[0], (LinkOption[])null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                Files.readAttributes(file, (String)null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                Files.readAttributes(file, "*", (LinkOption[])null);
+            }});
+
+        // Read-only buffer
+        tryCatch(IllegalArgumentException.class, new Task() {
+            public void run() throws IOException {
+                ByteBuffer buf = ByteBuffer.wrap(ATTR_VALUE.getBytes()).asReadOnlyBuffer();
+                view.write(ATTR_NAME, buf);
+                buf.flip();
+                view.read(ATTR_NAME, buf);
+            }});
+
+        // Zero bytes remaining
+        tryCatch(IOException.class, new Task() {
+            public void run() throws IOException {
+                ByteBuffer buf = buf = ByteBuffer.allocateDirect(100);
+                buf.position(buf.capacity());
+                view.read(ATTR_NAME, buf);
+            }});
+    }
+
+    // Android-changed: Removed args & added @Test
+    @Test
+    public static void main() throws IOException {
+        // create temporary directory to run tests
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            if (!Files.getFileStore(dir).supportsFileAttributeView("user")) {
+                System.out.println("UserDefinedFileAttributeView not supported - skip test");
+                return;
+            }
+
+            // test access to user defined attributes of regular file
+            Path file = dir.resolve("foo.html");
+            Files.createFile(file);
+            try {
+                test(file);
+            } finally {
+                Files.delete(file);
+            }
+
+            // test access to user defined attributes of directory
+            Path subdir = dir.resolve("foo");
+            Files.createDirectory(subdir);
+            try {
+                test(subdir);
+            } finally {
+                Files.delete(subdir);
+            }
+
+            // test access to user defined attributes of sym link
+            if (TestUtil.supportsLinks(dir)) {
+                Path target = dir.resolve("doesnotexist");
+                Path link = dir.resolve("link");
+                Files.createSymbolicLink(link, target);
+                try {
+                    test(link, NOFOLLOW_LINKS);
+                } catch (IOException x) {
+                    // access to attributes of sym link may not be supported
+                } finally {
+                    Files.delete(link);
+                }
+            }
+
+            // misc. tests
+            try {
+                file = dir.resolve("foo.txt");
+                Files.createFile(file);
+                miscTests(dir);
+            } finally {
+                Files.delete(file);
+            }
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+ }
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
index 3d89db5..1b8fea7 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
@@ -1931,6 +1931,16 @@
         Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1).toEpochMilli();
     }
 
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_toEpochMillis_overflow() {
+        Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 809_000_000).toEpochMilli();
+    }
+
+    @Test(expectedExceptions=ArithmeticException.class)
+    public void test_toEpochMillis_overflow2() {
+        Instant.ofEpochSecond(-9223372036854776L, 1).toEpochMilli();
+    }
+
     //-----------------------------------------------------------------------
     // compareTo()
     //-----------------------------------------------------------------------
diff --git a/ojluni/src/test/java/time/test/java/time/TestInstant.java b/ojluni/src/test/java/time/test/java/time/TestInstant.java
index cf135a1..203bb57 100644
--- a/ojluni/src/test/java/time/test/java/time/TestInstant.java
+++ b/ojluni/src/test/java/time/test/java/time/TestInstant.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,6 +62,8 @@
 import java.time.Instant;
 
 import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
 
 /**
  * Test Instant.
@@ -74,4 +76,24 @@
         assertImmutable(Instant.class);
     }
 
+    @DataProvider(name="sampleEpochMillis")
+    private Object[][] provider_sampleEpochMillis() {
+        return new Object[][] {
+            {"Long.MAX_VALUE", Long.MAX_VALUE},
+            {"Long.MAX_VALUE-1", Long.MAX_VALUE - 1},
+            {"1", 1L},
+            {"0", 0L},
+            {"-1", -1L},
+            {"Long.MIN_VALUE+1", Long.MIN_VALUE + 1},
+            {"Long.MIN_VALUE", Long.MIN_VALUE}
+        };
+    }
+
+    @Test(dataProvider="sampleEpochMillis")
+    public void test_epochMillis(String name, long millis) {
+        Instant t1 = Instant.ofEpochMilli(millis);
+        long m = t1.toEpochMilli();
+        assertEquals(millis, m, name);
+    }
+
 }
diff --git a/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java b/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java
index 1ef3a5b..23ef184 100644
--- a/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java
+++ b/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java
@@ -99,7 +99,7 @@
         assertEquals(locale.toString(), "ja_JP_#u-ca-japanese", "Unexpected locale");
 
         // Android changed: Android doesn't return the Japanese Imperial Calendar from getInstance.
-        Calendar cal = java.util.Calendar.getJapanesImperialInstance(TimeZone.getDefault(), locale);
+        Calendar cal = Calendar.getJapaneseImperialInstance(TimeZone.getDefault(), locale);
         assertEquals(cal.getCalendarType(), "japanese", "Unexpected calendar type");
 
         JapaneseDate jDate = JapaneseChronology.INSTANCE.date(isoStartDate);
diff --git a/ojluni/src/test/java/time/test/java/util/TestFormatter.java b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
index afd5fc4..05cb2e7 100644
--- a/ojluni/src/test/java/time/test/java/util/TestFormatter.java
+++ b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
@@ -111,7 +111,7 @@
                 TimeZone tz = TimeZone.getTimeZone(zdt.getZone());
                 Calendar cal;
                 if (calLocale.getLanguage().equals("ja")) {
-                    cal = Calendar.getJapanesImperialInstance(tz, calLocale);
+                    cal = Calendar.getJapaneseImperialInstance(tz, calLocale);
                 } else {
                     cal = Calendar.getInstance(tz, calLocale);
                 }
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 50c4b84..4285911 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -114,6 +114,7 @@
     ojluni/src/main/java/java/lang/AssertionError.java \
     ojluni/src/main/java/java/lang/AutoCloseable.java \
     ojluni/src/main/java/java/lang/Boolean.java \
+    ojluni/src/main/java/java/lang/BootstrapMethodError.java \
     ojluni/src/main/java/java/lang/Byte.java \
     ojluni/src/main/java/java/lang/Character.java \
     ojluni/src/main/java/java/lang/CharSequence.java \
@@ -240,6 +241,8 @@
     ojluni/src/main/java/java/lang/VirtualMachineError.java \
     ojluni/src/main/java/java/lang/Void.java \
     ojluni/src/main/java/java/lang/invoke/LambdaConversionException.java \
+    ojluni/src/main/java/java/lang/invoke/CallSite.java \
+    ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java \
     ojluni/src/main/java/java/lang/invoke/MethodHandle.java \
     ojluni/src/main/java/java/lang/invoke/MethodHandles.java \
     ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java \
@@ -247,8 +250,10 @@
     ojluni/src/main/java/java/lang/invoke/MethodHandleStatics.java \
     ojluni/src/main/java/java/lang/invoke/MethodType.java \
     ojluni/src/main/java/java/lang/invoke/MethodTypeForm.java \
+    ojluni/src/main/java/java/lang/invoke/MutableCallSite.java \
     ojluni/src/main/java/java/lang/invoke/Stable.java \
     ojluni/src/main/java/java/lang/invoke/Transformers.java \
+    ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java \
     ojluni/src/main/java/java/lang/invoke/WrongMethodTypeException.java \
     ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java \
     ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java \
@@ -1744,10 +1749,10 @@
 # On older platforms : Both sets of stub files are used and core-oj does not contain
 # any of these classes.
 openjdk_lambda_stub_files := \
-    ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
     ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java \
     ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java
 openjdk_lambda_duplicate_stub_files := \
+    ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
     ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
     ojluni/src/lambda/java/java/lang/invoke/LambdaConversionException.java \
     ojluni/src/lambda/java/java/lang/invoke/MethodHandle.java \
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index 8b5664e..8bc9937 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -16,6 +16,10 @@
 
 package libcore.java.security;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import java.security.Security;
 import java.security.spec.DSAPrivateKeySpec;
 import java.security.spec.DSAPublicKeySpec;
@@ -36,7 +40,6 @@
 import java.util.Set;
 import javax.crypto.spec.DHPrivateKeySpec;
 import javax.crypto.spec.DHPublicKeySpec;
-import junit.framework.Assert;
 
 /**
  * This class defines expected string names for protocols, key types,
@@ -63,7 +66,7 @@
  * Java &trade; PKCS#11 Reference Guide
  * </a>.
  */
-public final class StandardNames extends Assert {
+public final class StandardNames {
 
     public static final boolean IS_RI
             = !"Dalvik Core Library".equals(System.getProperty("java.specification.name"));
@@ -107,7 +110,7 @@
     private static void provide(String type, String algorithm) {
         Set<String> algorithms = PROVIDER_ALGORITHMS.get(type);
         if (algorithms == null) {
-            algorithms = new HashSet();
+            algorithms = new HashSet<String>();
             PROVIDER_ALGORITHMS.put(type, algorithms);
         }
         assertTrue("Duplicate " + type + " " + algorithm,
@@ -490,6 +493,16 @@
             provide("Cipher", "PBEWITHSHAAND40BITRC2-CBC");
             provide("Cipher", "PBEWITHSHAAND40BITRC4");
             provide("Cipher", "PBEWITHSHAANDTWOFISH-CBC");
+            provide("Cipher", "PBEWithHmacSHA1AndAES_128");
+            provide("Cipher", "PBEWithHmacSHA224AndAES_128");
+            provide("Cipher", "PBEWithHmacSHA256AndAES_128");
+            provide("Cipher", "PBEWithHmacSHA384AndAES_128");
+            provide("Cipher", "PBEWithHmacSHA512AndAES_128");
+            provide("Cipher", "PBEWithHmacSHA1AndAES_256");
+            provide("Cipher", "PBEWithHmacSHA224AndAES_256");
+            provide("Cipher", "PBEWithHmacSHA256AndAES_256");
+            provide("Cipher", "PBEWithHmacSHA384AndAES_256");
+            provide("Cipher", "PBEWithHmacSHA512AndAES_256");
             provide("Mac", "PBEWITHHMACSHA");
             provide("Mac", "PBEWITHHMACSHA1");
             provide("SecretKeyFactory", "PBEWITHHMACSHA1");
@@ -590,7 +603,7 @@
             unprovide("AlgorithmParameters", "PBEWithMD5AndDES"); // 1.2.840.113549.1.5.3
 
             // EC support
-            // provide("AlgorithmParameters", "EC");
+            provide("AlgorithmParameters", "EC");
             provide("KeyAgreement", "ECDH");
             provide("KeyFactory", "EC");
             provide("KeyPairGenerator", "EC");
diff --git a/support/src/test/java/libcore/java/security/TestKeyStore.java b/support/src/test/java/libcore/java/security/TestKeyStore.java
index ef62a44..3829dc1 100644
--- a/support/src/test/java/libcore/java/security/TestKeyStore.java
+++ b/support/src/test/java/libcore/java/security/TestKeyStore.java
@@ -16,10 +16,14 @@
 
 package libcore.java.security;
 
+import static org.junit.Assert.assertEquals;
+
 import com.android.org.bouncycastle.asn1.DEROctetString;
+import com.android.org.bouncycastle.asn1.x500.X500Name;
 import com.android.org.bouncycastle.asn1.x509.BasicConstraints;
 import com.android.org.bouncycastle.asn1.x509.CRLReason;
 import com.android.org.bouncycastle.asn1.x509.ExtendedKeyUsage;
+import com.android.org.bouncycastle.asn1.x509.Extension;
 import com.android.org.bouncycastle.asn1.x509.GeneralName;
 import com.android.org.bouncycastle.asn1.x509.GeneralNames;
 import com.android.org.bouncycastle.asn1.x509.GeneralSubtree;
@@ -27,23 +31,20 @@
 import com.android.org.bouncycastle.asn1.x509.KeyUsage;
 import com.android.org.bouncycastle.asn1.x509.NameConstraints;
 import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import com.android.org.bouncycastle.asn1.x509.X509Extensions;
 import com.android.org.bouncycastle.cert.X509CertificateHolder;
+import com.android.org.bouncycastle.cert.X509v3CertificateBuilder;
 import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
 import com.android.org.bouncycastle.cert.ocsp.BasicOCSPResp;
 import com.android.org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
 import com.android.org.bouncycastle.cert.ocsp.CertificateID;
 import com.android.org.bouncycastle.cert.ocsp.CertificateStatus;
-import com.android.org.bouncycastle.cert.ocsp.OCSPException;
 import com.android.org.bouncycastle.cert.ocsp.OCSPResp;
 import com.android.org.bouncycastle.cert.ocsp.OCSPRespBuilder;
 import com.android.org.bouncycastle.cert.ocsp.RevokedStatus;
 import com.android.org.bouncycastle.jce.provider.BouncyCastleProvider;
 import com.android.org.bouncycastle.operator.DigestCalculatorProvider;
-import com.android.org.bouncycastle.operator.OperatorCreationException;
 import com.android.org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
 import com.android.org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -64,7 +65,6 @@
 import java.security.UnrecoverableEntryException;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
@@ -79,7 +79,6 @@
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.security.auth.x500.X500Principal;
-import junit.framework.Assert;
 import libcore.javax.net.ssl.TestKeyManager;
 import libcore.javax.net.ssl.TestTrustManager;
 
@@ -90,7 +89,7 @@
  * Creating a key store is relatively slow, so a singleton instance is
  * accessible via TestKeyStore.get().
  */
-public final class TestKeyStore extends Assert {
+public final class TestKeyStore {
     /** Size of DSA keys to generate for testing. */
     private static final int DSA_KEY_SIZE_BITS = 1024;
 
@@ -156,11 +155,9 @@
         }
     }
 
-    private static final boolean TEST_MANAGERS = true;
     private static final byte[] LOCAL_HOST_ADDRESS = { 127, 0, 0, 1 };
     private static final String LOCAL_HOST_NAME = "localhost";
 
-
     public final KeyStore keyStore;
     public final char[] storePassword;
     public final char[] keyPassword;
@@ -707,43 +704,40 @@
             throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm);
         }
 
-        X509V3CertificateGenerator x509cg = new X509V3CertificateGenerator();
-        x509cg.setSubjectDN(subject);
-        x509cg.setIssuerDN(issuer);
-        x509cg.setNotBefore(start);
-        x509cg.setNotAfter(end);
-        x509cg.setPublicKey(publicKey);
-        x509cg.setSignatureAlgorithm(signatureAlgorithm);
         if (serialNumber == null) {
             byte[] serialBytes = new byte[16];
             new SecureRandom().nextBytes(serialBytes);
             serialNumber = new BigInteger(1, serialBytes);
         }
-        x509cg.setSerialNumber(serialNumber);
+
+        X509v3CertificateBuilder x509cg = new X509v3CertificateBuilder(
+                X500Name.getInstance(issuer.getEncoded()), serialNumber, start, end,
+                X500Name.getInstance(subject.getEncoded()),
+                SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));
         if (keyUsage != 0) {
-            x509cg.addExtension(X509Extensions.KeyUsage,
+            x509cg.addExtension(Extension.keyUsage,
                                 true,
                                 new KeyUsage(keyUsage));
         }
         if (ca) {
-            x509cg.addExtension(X509Extensions.BasicConstraints,
+            x509cg.addExtension(Extension.basicConstraints,
                                 true,
                                 new BasicConstraints(true));
         }
         for (int i = 0; i < extendedKeyUsages.size(); i++) {
             KeyPurposeId keyPurposeId = extendedKeyUsages.get(i);
             boolean critical = criticalExtendedKeyUsages.get(i);
-            x509cg.addExtension(X509Extensions.ExtendedKeyUsage,
+            x509cg.addExtension(Extension.extendedKeyUsage,
                                 critical,
                                 new ExtendedKeyUsage(keyPurposeId));
         }
         for (GeneralName subjectAltName : subjectAltNames) {
-            x509cg.addExtension(X509Extensions.SubjectAlternativeName,
+            x509cg.addExtension(Extension.subjectAlternativeName,
                                 false,
                                 new GeneralNames(subjectAltName).getEncoded());
         }
         if (!permittedNameConstraints.isEmpty() || !excludedNameConstraints.isEmpty()) {
-            x509cg.addExtension(X509Extensions.NameConstraints,
+            x509cg.addExtension(Extension.nameConstraints,
                                 true,
                                 new NameConstraints(permittedNameConstraints.toArray(
                                                         new GeneralSubtree[
@@ -753,7 +747,12 @@
                                                             excludedNameConstraints.size()])));
         }
 
-        X509Certificate x509c = x509cg.generateX509Certificate(privateKey);
+        X509CertificateHolder x509holder = x509cg.build(
+                new JcaContentSignerBuilder(signatureAlgorithm).build(privateKey));
+        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+        X509Certificate x509c = (X509Certificate) certFactory.generateCertificate(
+                new ByteArrayInputStream(x509holder.getEncoded()));
+
         if (StandardNames.IS_RI) {
             /*
              * The RI can't handle the BC EC signature algorithm
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/DistroVersion.java b/tzdata/update2/src/main/libcore/tzdata/update2/DistroVersion.java
index ae4af45..4848db7 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/DistroVersion.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/DistroVersion.java
@@ -30,12 +30,14 @@
      * The major distro format version supported by this device.
      * Increment this for non-backwards compatible changes to the distro format. Reset the minor
      * version to 1 when doing so.
+     * This constant must match the one in system/core/tzdatacheck/tzdatacheck.cpp.
      */
     public static final int CURRENT_FORMAT_MAJOR_VERSION = 1;
 
     /**
      * The minor distro format version supported by this device. Increment this for
      * backwards-compatible changes to the distro format.
+     * This constant must match the one in system/core/tzdatacheck/tzdatacheck.cpp.
      */
     public static final int CURRENT_FORMAT_MINOR_VERSION = 1;
 
@@ -122,10 +124,8 @@
     }
 
     public static boolean isCompatibleWithThisDevice(DistroVersion distroVersion) {
-        return (DistroVersion.CURRENT_FORMAT_MAJOR_VERSION
-                == distroVersion.formatMajorVersion)
-                && (DistroVersion.CURRENT_FORMAT_MINOR_VERSION
-                <= distroVersion.formatMinorVersion);
+        return (CURRENT_FORMAT_MAJOR_VERSION == distroVersion.formatMajorVersion)
+                && (CURRENT_FORMAT_MINOR_VERSION <= distroVersion.formatMinorVersion);
     }
 
     @Override
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistro.java b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistro.java
index c04b4cb..04e3f2a 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistro.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistro.java
@@ -40,6 +40,7 @@
     /**
      * The name of the file inside the distro containing the distro version information.
      * The content is ASCII bytes representing a set of version numbers. See {@link DistroVersion}.
+     * This constant must match the one in system/core/tzdatacheck/tzdatacheck.cpp.
      */
     public static final String DISTRO_VERSION_FILE_NAME = "distro_version";
 
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java
similarity index 98%
rename from tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java
rename to tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java
index d08bb1d..1b56ebf 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java
@@ -26,8 +26,7 @@
  * A distro-validation / extraction class. Separate from the services code that uses it for easier
  * testing. This class is not thread-safe: callers are expected to handle mutual exclusion.
  */
-// TODO(nfuller) Rename to TimeZoneDistroInstaller
-public final class TimeZoneBundleInstaller {
+public final class TimeZoneDistroInstaller {
     /** {@link #installWithErrorCode(byte[])} result code: Success. */
     public final static int INSTALL_SUCCESS = 0;
     /** {@link #installWithErrorCode(byte[])} result code: Distro corrupt. */
@@ -49,7 +48,7 @@
     private final File currentTzDataDir;
     private final File workingDir;
 
-    public TimeZoneBundleInstaller(String logTag, File systemTzDataFile, File installDir) {
+    public TimeZoneDistroInstaller(String logTag, File systemTzDataFile, File installDir) {
         this.logTag = logTag;
         this.systemTzDataFile = systemTzDataFile;
         oldTzDataDir = new File(installDir, OLD_TZ_DATA_DIR_NAME);
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java
similarity index 92%
rename from tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java
rename to tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java
index 088e7cb..6ae0e56 100644
--- a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java
@@ -34,9 +34,9 @@
 import libcore.tzdata.update2.tools.TimeZoneDistroBuilder;
 
 /**
- * Tests for {@link TimeZoneBundleInstaller}.
+ * Tests for {@link TimeZoneDistroInstaller}.
  */
-public class TimeZoneBundleInstallerTest extends TestCase {
+public class TimeZoneDistroInstallerTest extends TestCase {
 
     // OLDER_RULES_VERSION < SYSTEM_RULES_VERSION < NEW_RULES_VERSION < NEWER_RULES_VERSION
     private static final String OLDER_RULES_VERSION = "2030a";
@@ -44,7 +44,7 @@
     private static final String NEW_RULES_VERSION = "2030c";
     private static final String NEWER_RULES_VERSION = "2030d";
 
-    private TimeZoneBundleInstaller installer;
+    private TimeZoneDistroInstaller installer;
     private File tempDir;
     private File testInstallDir;
     private File testSystemTzDataDir;
@@ -61,8 +61,8 @@
         byte[] systemTzDataBytes = createTzData(SYSTEM_RULES_VERSION);
         createFile(testSystemTzDataFile, systemTzDataBytes);
 
-        installer = new TimeZoneBundleInstaller(
-                "TimeZoneBundleInstallerTest", testSystemTzDataFile, testInstallDir);
+        installer = new TimeZoneDistroInstaller(
+                "TimeZoneDistroInstallerTest", testSystemTzDataFile, testInstallDir);
     }
 
     private static File createDirectory(String prefix) throws Exception {
@@ -89,8 +89,8 @@
     /** Tests the an update on a device will fail if the /system tzdata file cannot be found. */
     public void testInstall_badSystemFile() throws Exception {
         File doesNotExist = new File(testSystemTzDataDir, "doesNotExist");
-        TimeZoneBundleInstaller brokenSystemInstaller = new TimeZoneBundleInstaller(
-                "TimeZoneBundleInstallerTest", doesNotExist, testInstallDir);
+        TimeZoneDistroInstaller brokenSystemInstaller = new TimeZoneDistroInstaller(
+                "TimeZoneDistroInstallerTest", doesNotExist, testInstallDir);
         TimeZoneDistro tzData = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
 
         try {
@@ -106,7 +106,7 @@
         TimeZoneDistro distro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
 
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(distro.getBytes()));
         assertDistroInstalled(distro);
     }
@@ -117,7 +117,7 @@
     public void testInstall_successfulFirstUpdate_sameVersionAsSystem() throws Exception {
         TimeZoneDistro distro = createValidTimeZoneDistro(SYSTEM_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(distro.getBytes()));
         assertDistroInstalled(distro);
     }
@@ -128,7 +128,7 @@
     public void testInstall_unsuccessfulFirstUpdate_olderVersionThanSystem() throws Exception {
         TimeZoneDistro distro = createValidTimeZoneDistro(OLDER_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_RULES_TOO_OLD,
+                TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD,
                 installer.installWithErrorCode(distro.getBytes()));
         assertNoContentInstalled();
     }
@@ -139,19 +139,19 @@
     public void testInstall_successfulFollowOnUpdate_newerVersion() throws Exception {
         TimeZoneDistro distro1 = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(distro1.getBytes()));
         assertDistroInstalled(distro1);
 
         TimeZoneDistro distro2 = createValidTimeZoneDistro(NEW_RULES_VERSION, 2);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(distro2.getBytes()));
         assertDistroInstalled(distro2);
 
         TimeZoneDistro distro3 = createValidTimeZoneDistro(NEWER_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(distro3.getBytes()));
         assertDistroInstalled(distro3);
     }
@@ -163,13 +163,13 @@
     public void testInstall_unsuccessfulFollowOnUpdate_olderVersion() throws Exception {
         TimeZoneDistro distro1 = createValidTimeZoneDistro(NEW_RULES_VERSION, 2);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(distro1.getBytes()));
         assertDistroInstalled(distro1);
 
         TimeZoneDistro distro2 = createValidTimeZoneDistro(OLDER_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_RULES_TOO_OLD,
+                TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD,
                 installer.installWithErrorCode(distro2.getBytes()));
         assertDistroInstalled(distro1);
     }
@@ -178,7 +178,7 @@
     public void testInstall_missingTzDataFile() throws Exception {
         TimeZoneDistro installedDistro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(installedDistro.getBytes()));
         assertDistroInstalled(installedDistro);
 
@@ -187,7 +187,7 @@
                         .clearTzDataForTests()
                         .buildUnvalidated();
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+                TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
                 installer.installWithErrorCode(incompleteDistro.getBytes()));
         assertDistroInstalled(installedDistro);
     }
@@ -196,7 +196,7 @@
     public void testInstall_missingIcuFile() throws Exception {
         TimeZoneDistro installedDistro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(installedDistro.getBytes()));
         assertDistroInstalled(installedDistro);
 
@@ -205,7 +205,7 @@
                         .clearIcuDataForTests()
                         .buildUnvalidated();
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+                TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
                 installer.installWithErrorCode(incompleteDistro.getBytes()));
         assertDistroInstalled(installedDistro);
     }
@@ -220,7 +220,7 @@
 
         TimeZoneDistro distro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_SUCCESS,
+                TimeZoneDistroInstaller.INSTALL_SUCCESS,
                 installer.installWithErrorCode(distro.getBytes()));
         assertDistroInstalled(distro);
     }
@@ -234,7 +234,7 @@
                 .clearVersionForTests()
                 .buildUnvalidated();
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+                TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
                 installer.installWithErrorCode(distro.getBytes()));
         assertNoContentInstalled();
     }
@@ -248,7 +248,7 @@
                 .replaceFormatVersionForTests(2, 1)
                 .buildUnvalidated();
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION,
+                TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION,
                 installer.installWithErrorCode(distro.getBytes()));
         assertNoContentInstalled();
     }
@@ -265,7 +265,7 @@
 
         TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidFormatVersionBytes);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+                TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
                 installer.installWithErrorCode(distro.getBytes()));
         assertNoContentInstalled();
     }
@@ -281,7 +281,7 @@
 
         TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidRevisionBytes);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+                TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
                 installer.installWithErrorCode(distro.getBytes()));
         assertNoContentInstalled();
     }
@@ -297,7 +297,7 @@
 
         TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidRulesVersionBytes);
         assertEquals(
-                TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+                TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
                 installer.installWithErrorCode(distro.getBytes()));
         assertNoContentInstalled();
     }