Merge "Correct docs based on recent behavior change"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 9f6d827..fb0b207 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -116,16 +116,6 @@
 LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
 include $(BUILD_JAVA_LIBRARY)
 
-# Path to the ICU4C data files in the Android device file system:
-icu4c_data := /system/usr/icu
-# TODO: It's quite hideous that this double-slash between icu4j and main is required.
-# It's because we provide a variable substition of the make-rule generated jar command
-# to substitute a processed ICUProperties.config file in place of the original.
-#
-# We can avoid this by filtering out ICUConfig.properties from our list of resources.
-icu4j_config_root := $(LOCAL_PATH)/../external/icu/icu4j//main/classes/core/src
-include external/icu/icu4j/adjust_icudt_path.mk
-
 ifeq ($(LIBCORE_SKIP_TESTS),)
 # Make the core-tests library.
 include $(CLEAR_VARS)
diff --git a/benchmarks/src/benchmarks/regression/ProviderBenchmark.java b/benchmarks/src/benchmarks/regression/ProviderBenchmark.java
new file mode 100644
index 0000000..649aa01
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/ProviderBenchmark.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import java.security.Provider;
+import java.security.Security;
+import javax.crypto.Cipher;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import javax.net.ssl.SSLSocketFactory;
+
+public class ProviderBenchmark extends SimpleBenchmark {
+    public void timeStableProviders(int reps) throws Exception {
+        for (int i = 0; i < reps; ++i) {
+            Cipher c = Cipher.getInstance("RSA");
+        }
+    }
+
+    public void timeWithNewProvider(int reps) throws Exception {
+        for (int i = 0; i < reps; ++i) {
+            Security.addProvider(new MockProvider());
+            try {
+                Cipher c = Cipher.getInstance("RSA");
+            } finally {
+                Security.removeProvider("Mock");
+            }
+        }
+    }
+
+    private static class MockProvider extends Provider {
+        public MockProvider() {
+            super("Mock", 1.0, "Mock me!");
+        }
+    }
+}
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 6470e36..6aac9eb 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1509,5 +1509,13 @@
     "libcore.java.util.zip.Zip64FileTest#testZip64Support_totalLargerThan4G",
     "libcore.java.util.zip.Zip64FileTest#testZip64Support_hugeEntry"
   ]
+},
+{
+  description: "OsTest.test_PacketSocketAddress needs CAP_NET_RAW",
+  bug: 19764047,
+  result: EXEC_FAILED,
+  names: [
+    "libcore.io.OsTest#test_PacketSocketAddress"
+  ]
 }
 ]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
index 277abce..8b4844c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ArraysTest.java
@@ -2217,7 +2217,7 @@
                 long[] b = new long[a.length];
 
                 for (int i = 0; i < a.length; i++) {
-                    b[i] = (int) a[i];
+                    b[i] = (long) a[i];
                 }
                 return b;
             }
diff --git a/libart/src/main/java/java/lang/Class.java b/libart/src/main/java/java/lang/Class.java
index 99c562f..388f34c 100644
--- a/libart/src/main/java/java/lang/Class.java
+++ b/libart/src/main/java/java/lang/Class.java
@@ -39,7 +39,6 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.ArtMethod;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.GenericDeclaration;
@@ -141,9 +140,6 @@
     /** Short-cut to dexCache.strings */
     private transient String[] dexCacheStrings;
 
-    /** static, private, and &lt;init&gt; methods. */
-    private transient ArtMethod[] directMethods;
-
     /**
      * The interface table (iftable_) contains pairs of a interface class and an array of the
      * interface methods. There is one pair per interface supported by this class.  That
@@ -169,20 +165,20 @@
     /** If class verify fails, we must return same error on subsequent tries. */
     private transient Class<?> verifyErrorClass;
 
-    /** Virtual methods defined in this class; invoked through vtable. */
-    private transient ArtMethod[] virtualMethods;
-
     /**
      * Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass
      * is copied in, and virtual methods from our class either replace those from the super or are
      * appended. For abstract classes, methods may be created in the vtable that aren't in
      * virtual_ methods_ for miranda methods.
      */
-    private transient ArtMethod[] vtable;
+    private transient Object vtable;
 
     /** access flags; low 16 bits are defined by VM spec */
     private transient int accessFlags;
 
+    /** static, private, and &lt;init&gt; methods. */
+    private transient long directMethods;
+
     /**
      * Instance fields. These describe the layout of the contents of an Object. Note that only the
      * fields directly declared by this class are listed in iFields; fields declared by a
@@ -196,6 +192,8 @@
     /** Static fields */
     private transient long sFields;
 
+    /** Virtual methods defined in this class; invoked through vtable. */
+    private transient long virtualMethods;
 
     /**
      * Total size of the Class instance; used when allocating storage on GC heap.
@@ -222,6 +220,9 @@
      */
     private transient volatile int dexTypeIndex;
 
+    /** Number of direct methods. */
+    private transient int numDirectMethods;
+
     /** Number of instance fields. */
     private transient int numInstanceFields;
 
@@ -234,6 +235,9 @@
     /** Number of static fields. */
     private transient int numStaticFields;
 
+    /** Number of virtual methods. */
+    private transient int numVirtualMethods;
+
     /**
      * Total object size; used when allocating storage on GC heap. For interfaces and abstract
      * classes this will be zero. See also {@link Class#classSize}.
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index c047018..73e35cd 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -33,7 +33,6 @@
 package java.lang;
 
 import com.android.dex.Dex;
-import java.lang.reflect.ArtMethod;
 
 /**
  * A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
@@ -49,7 +48,7 @@
      * References to methods as they become resolved following interpreter semantics. May refer to
      * methods defined in other dex files.
      */
-    ArtMethod[] resolvedMethods;
+    Object resolvedMethods;
 
     /**
      * References to fields as they become resolved following interpreter semantics. May refer to
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
index 0ac15f9..95d90cc 100644
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
@@ -51,10 +51,11 @@
 
     /**
      * The ArtMethod associated with this Method, requried for dispatching due to entrypoints
+     * Classloader is held live by the declaring class.
      * Hidden to workaround b/16828157.
      * @hide
      */
-    protected ArtMethod artMethod;
+    protected long artMethod;
 
     /** Method's declaring class */
     protected Class<?> declaringClass;
diff --git a/libart/src/main/java/java/lang/reflect/ArtMethod.java b/libart/src/main/java/java/lang/reflect/ArtMethod.java
deleted file mode 100644
index 84e6b48..0000000
--- a/libart/src/main/java/java/lang/reflect/ArtMethod.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.reflect;
-
-import com.android.dex.Dex;
-import java.lang.annotation.Annotation;
-import libcore.reflect.AnnotationAccess;
-import libcore.util.EmptyArray;
-
-/**
- * This class represents methods and constructors.
- * @hide
- */
-public final class ArtMethod {
-    /* A note on the field order here, it reflects the same field order as laid out by ART. */
-
-    /** Method's declaring class */
-    private Class<?> declaringClass;
-
-    /** Short-cut to declaringClass.dexCache.resolvedMethods */
-    private ArtMethod[] dexCacheResolvedMethods;
-
-    /** Short-cut to declaringClass.dexCache.resolvedTypes */
-    /* package */ Class<?>[] dexCacheResolvedTypes;
-
-    /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
-    private int accessFlags;
-
-    /* Dex file fields. The defining dex file is available via declaringClass.dexCache */
-
-    /** The offset of the code item associated with this method within its defining dex file */
-    private int dexCodeItemOffset;
-
-    /** The method index of this method within its defining dex file */
-    private int dexMethodIndex;
-
-    /* End of dex file fields. */
-
-    /**
-     * Entry within a dispatch table for this method. For static/direct methods the index is
-     * into the declaringClass.directMethods, for virtual methods the vtable and for
-     * interface methods the ifTable.
-     */
-    private int methodIndex;
-
-    /** Only created by ART directly. */
-    private ArtMethod() {}
-}
diff --git a/luni/src/main/java/java/nio/ByteOrder.java b/luni/src/main/java/java/nio/ByteOrder.java
index 286c970..508c8ef 100644
--- a/luni/src/main/java/java/nio/ByteOrder.java
+++ b/luni/src/main/java/java/nio/ByteOrder.java
@@ -32,13 +32,10 @@
      */
     public static final ByteOrder LITTLE_ENDIAN;
 
-    private static native boolean isLittleEndian();
-
     static {
-        boolean isLittleEndian = isLittleEndian();
-        BIG_ENDIAN = new ByteOrder("BIG_ENDIAN", isLittleEndian);
-        LITTLE_ENDIAN = new ByteOrder("LITTLE_ENDIAN", !isLittleEndian);
-        NATIVE_ORDER = isLittleEndian ? LITTLE_ENDIAN : BIG_ENDIAN;
+        BIG_ENDIAN = new ByteOrder("BIG_ENDIAN", true /* needs swap */);
+        LITTLE_ENDIAN = new ByteOrder("LITTLE_ENDIAN", false /* needs swap */);
+        NATIVE_ORDER = LITTLE_ENDIAN;
     }
 
     private final String name;
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
index 5dfdd9f..38be0c2 100644
--- a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
@@ -202,7 +202,7 @@
 
     private void setPosition(CharBuffer out) {
         if (out.hasArray()) {
-            out.position(out.position() + data[OUTPUT_OFFSET] - out.arrayOffset());
+            out.position(out.position() + data[OUTPUT_OFFSET]);
         } else {
             out.put(output, 0, data[OUTPUT_OFFSET]);
         }
diff --git a/luni/src/main/java/java/security/Provider.java b/luni/src/main/java/java/security/Provider.java
index 1704b58..1a64ecc 100644
--- a/luni/src/main/java/java/security/Provider.java
+++ b/luni/src/main/java/java/security/Provider.java
@@ -368,8 +368,8 @@
     }
 
     /**
-     * Get the service of the specified type
-     *
+     * Get the service of the specified {@code type} (e.g. "SecureRandom",
+     * "Signature").
      */
     synchronized Provider.Service getService(String type) {
         updatePropertyServiceTable();
diff --git a/luni/src/main/java/java/security/Signature.java b/luni/src/main/java/java/security/Signature.java
index 3151058..795ccad 100644
--- a/luni/src/main/java/java/security/Signature.java
+++ b/luni/src/main/java/java/security/Signature.java
@@ -245,11 +245,12 @@
     }
 
     /**
-     * Gets the SPI implementation backing this signature.
+     * Returns the {@code SignatureSpi} backing this {@code Signature} or {@code null} if no
+     * {@code SignatureSpi} is backing this {@code Signature}.
      *
      * @hide
      */
-    public SignatureSpi getSpi() {
+    public SignatureSpi getCurrentSpi() {
         return null;
     }
 
@@ -739,12 +740,16 @@
 
         /**
          * Convenience call when the Key is not available.
-         *
-         * @hide
          */
-        @Override
-        public SignatureSpi getSpi() {
+        private SignatureSpi getSpi() {
             return getSpi(null);
         }
+
+        @Override
+        public SignatureSpi getCurrentSpi() {
+            synchronized (initLock) {
+                return spiImpl;
+            }
+        }
     }
 }
diff --git a/luni/src/main/java/java/text/DecimalFormatSymbols.java b/luni/src/main/java/java/text/DecimalFormatSymbols.java
index 2f1d4f4..006d37b 100644
--- a/luni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/luni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -297,8 +297,14 @@
             return minusSign.charAt(0);
         }
 
-        throw new UnsupportedOperationException(
-                "Minus sign spans multiple characters: " + minusSign);
+        // Return the minus sign from Locale.ROOT instead of crashing. None of libcore the parsers
+        // or formatters actually call this function, they use {@code getMinusSignString()} instead
+        // and that function always returns the correct (possibly multi-char) symbol.
+        //
+        // Callers of this method that format strings and expect them to be parseable by
+        // the "standard" parsers (or vice-versa) are hosed, but there's not much we can do to
+        // save them.
+        return '-';
     }
 
     /** @hide */
@@ -349,7 +355,15 @@
         if (percent.length() == 1) {
             return percent.charAt(0);
         }
-        throw new UnsupportedOperationException("Percent spans multiple characters: " + percent);
+
+        // Return the percent sign from Locale.ROOT instead of crashing. None of the libcore parsers
+        // or formatters actually call this function, they use {@code getPercentString()} instead
+        // and that function always returns the correct (possibly multi-char) symbol.
+        //
+        // Callers of this method that format strings and expect them to be parseable by
+        // the "standard" parsers (or vice-versa) are hosed, but there's not much we can do to
+        // save them.
+        return '%';
     }
 
     /**
@@ -601,6 +615,8 @@
         new ObjectStreamField("serialVersionOnStream", int.class),
         new ObjectStreamField("zeroDigit", char.class),
         new ObjectStreamField("locale", Locale.class),
+        new ObjectStreamField("minusSignStr", String.class),
+        new ObjectStreamField("percentStr", String.class),
     };
 
     private void writeObject(ObjectOutputStream stream) throws IOException {
@@ -613,15 +629,21 @@
         fields.put("groupingSeparator", getGroupingSeparator());
         fields.put("infinity", infinity);
         fields.put("intlCurrencySymbol", intlCurrencySymbol);
-        fields.put("minusSign", getMinusSign());
         fields.put("monetarySeparator", getMonetaryDecimalSeparator());
         fields.put("NaN", NaN);
         fields.put("patternSeparator", getPatternSeparator());
-        fields.put("percent", getPercent());
         fields.put("perMill", getPerMill());
         fields.put("serialVersionOnStream", 3);
         fields.put("zeroDigit", getZeroDigit());
         fields.put("locale", locale);
+
+        // Hardcode values here for backwards compatibility. These values will only be used
+        // if we're de-serializing this object on an earlier version of android.
+        fields.put("minusSign", minusSign.length() == 1 ? minusSign.charAt(0) : '-');
+        fields.put("percent", percent.length() == 1 ? percent.charAt(0) : '%');
+
+        fields.put("minusSignStr", getMinusSignString());
+        fields.put("percentStr", getPercentString());
         stream.writeFields();
     }
 
@@ -634,10 +656,26 @@
         setGroupingSeparator(fields.get("groupingSeparator", ','));
         infinity = (String) fields.get("infinity", "");
         intlCurrencySymbol = (String) fields.get("intlCurrencySymbol", "");
-        setMinusSign(fields.get("minusSign", '-'));
         NaN = (String) fields.get("NaN", "");
         setPatternSeparator(fields.get("patternSeparator", ';'));
-        setPercent(fields.get("percent", '%'));
+
+        // Special handling for minusSign and percent. If we've serialized the string versions of
+        // these fields, use them. If not, fall back to the single character versions. This can
+        // only happen if we're de-serializing an object that was written by an older version of
+        // android (something that's strongly discouraged anyway).
+        final String minusSignStr = (String) fields.get("minusSignStr", null);
+        if (minusSignStr != null) {
+            minusSign = minusSignStr;
+        } else {
+            setMinusSign(fields.get("minusSign", '-'));
+        }
+        final String percentStr = (String) fields.get("percentStr", null);
+        if (percentStr != null) {
+            percent = percentStr;
+        } else {
+            setPercent(fields.get("percent", '%'));
+        }
+
         setPerMill(fields.get("perMill", '\u2030'));
         setZeroDigit(fields.get("zeroDigit", '0'));
         locale = (Locale) fields.get("locale", null);
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java
index 66d03ad..5a66c20 100644
--- a/luni/src/main/java/javax/crypto/Cipher.java
+++ b/luni/src/main/java/javax/crypto/Cipher.java
@@ -366,11 +366,25 @@
 
     /**
      * Convenience call when the Key is not available.
+     */
+    private CipherSpi getSpi() {
+        return getSpi(null);
+    }
+
+    /**
+     * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no
+     * {@code CipherSpi} is backing this {@code Cipher}.
      *
      * @hide
      */
-    public CipherSpi getSpi() {
-        return getSpi(null);
+    public CipherSpi getCurrentSpi() {
+        if (specifiedSpi != null) {
+            return specifiedSpi;
+        }
+
+        synchronized (initLock) {
+            return spiImpl;
+        }
     }
 
     /**
diff --git a/luni/src/main/java/javax/crypto/KeyAgreement.java b/luni/src/main/java/javax/crypto/KeyAgreement.java
index d27aa2e..1ba660d 100644
--- a/luni/src/main/java/javax/crypto/KeyAgreement.java
+++ b/luni/src/main/java/javax/crypto/KeyAgreement.java
@@ -252,11 +252,21 @@
 
     /**
      * Convenience call when the Key is not available.
+     */
+    private KeyAgreementSpi getSpi() {
+        return getSpi(null);
+    }
+
+    /**
+     * Returns the {@code KeyAgreementSpi} backing this {@code KeyAgreement} or {@code null} if no
+     * {@code KeyAgreementSpi} is backing this {@code KeyAgreement}.
      *
      * @hide
      */
-    public KeyAgreementSpi getSpi() {
-        return getSpi(null);
+    public KeyAgreementSpi getCurrentSpi() {
+        synchronized (initLock) {
+            return spiImpl;
+        }
     }
 
     /**
diff --git a/luni/src/main/java/javax/crypto/Mac.java b/luni/src/main/java/javax/crypto/Mac.java
index 536f0c5..7da84e6 100644
--- a/luni/src/main/java/javax/crypto/Mac.java
+++ b/luni/src/main/java/javax/crypto/Mac.java
@@ -266,11 +266,21 @@
 
     /**
      * Convenience call when the Key is not available.
+     */
+    private MacSpi getSpi() {
+        return getSpi(null);
+    }
+
+    /**
+     * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is
+     * backing this {@code Mac}.
      *
      * @hide
      */
-    public MacSpi getSpi() {
-        return getSpi(null);
+    public MacSpi getCurrentSpi() {
+        synchronized (initLock) {
+            return spiImpl;
+        }
     }
 
     /**
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index fd8570c..d2cb9ab 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -18,17 +18,11 @@
 
 import android.system.ErrnoException;
 import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel.MapMode;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.TimeZone;
 import libcore.io.BufferIterator;
-import libcore.io.IoUtils;
 import libcore.io.MemoryMappedFile;
 
 /**
@@ -253,6 +247,13 @@
     public boolean hasTimeZone(String id) throws IOException {
       return cache.get(id) != null;
     }
+
+    @Override protected void finalize() throws Throwable {
+      if (mappedFile != null) {
+        mappedFile.close();
+      }
+      super.finalize();
+    }
   }
 
   private ZoneInfoDB() {
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
index 855a8c7..1c794e5 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java
@@ -152,7 +152,8 @@
     }
 
     /**
-     * Returns a list of all possible matches for a given algorithm.
+     * Returns a list of all possible matches for a given algorithm. Returns
+     * {@code null} if no matches were found.
      */
     public ArrayList<Provider.Service> getServices(String algorithm) {
         int newCacheVersion = Services.getCacheVersion();
@@ -163,8 +164,7 @@
                 && newCacheVersion == cacheEntry.cacheVersion) {
             return cacheEntry.services;
         }
-        String name = this.serviceName + "." + algoUC;
-        ArrayList<Provider.Service> services = Services.getServices(name);
+        ArrayList<Provider.Service> services = Services.getServices(serviceName, algoUC);
         this.serviceCache = new ServiceCacheEntry(algoUC, newCacheVersion, services);
         return services;
     }
diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
index c81bf6b..5f3dfe0 100644
--- a/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
+++ b/luni/src/main/java/org/apache/harmony/security/fortress/Services.java
@@ -29,16 +29,6 @@
  * implementations for all "serviceName.algName".
  */
 public class Services {
-
-    /**
-     * The HashMap that contains information about preferred implementations for
-     * all serviceName.algName in the registered providers.
-     * Set the initial size to 600 so we don't grow to 1024 by default because
-     * initialization adds a few entries more than the growth threshold.
-     */
-    private static final HashMap<String, ArrayList<Provider.Service>> services
-            = new HashMap<String, ArrayList<Provider.Service>>(600);
-
     /**
      * Save default SecureRandom service as well.
      * Avoids similar provider/services iteration in SecureRandom constructor.
@@ -71,7 +61,6 @@
             Provider p = (Provider) providerClass.newInstance();
             providers.add(p);
             providersNames.put(p.getName(), p);
-            initServiceInfo(p);
             return true;
         } catch (ClassNotFoundException ignored) {
         } catch (IllegalAccessException ignored) {
@@ -104,7 +93,7 @@
     }
 
     /**
-     * Returns a copy of the registered providers as an array.
+     * Returns the actual registered providers.
      */
     public static synchronized ArrayList<Provider> getProviders() {
         return providers;
@@ -144,54 +133,39 @@
     }
 
     /**
-     * Adds information about provider services into HashMap.
+     * Looks up the requested service by type and algorithm. The service
+     * {@code type} and should be provided in the same format used when
+     * registering a service with a provider, for example, "KeyFactory.RSA".
+     * Callers can cache the returned service information but such caches should
+     * be validated against the result of Service.getCacheVersion() before use.
+     * Returns {@code null} if there are no services found.
      */
-    public static synchronized void initServiceInfo(Provider p) {
-        for (Provider.Service service : p.getServices()) {
-            String type = service.getType();
-            if (cachedSecureRandomService == null && type.equals("SecureRandom")) {
-                cachedSecureRandomService = service;
-            }
-            String key = type + "." + service.getAlgorithm().toUpperCase(Locale.US);
-            appendServiceLocked(key, service);
-            for (String alias : Engine.door.getAliases(service)) {
-                key = type + "." + alias.toUpperCase(Locale.US);
-                appendServiceLocked(key, service);
+    public static synchronized ArrayList<Provider.Service> getServices(String type,
+            String algorithm) {
+        ArrayList<Provider.Service> services = null;
+        for (Provider p : providers) {
+            Provider.Service s = p.getService(type, algorithm);
+            if (s != null) {
+                if (services == null) {
+                    services = new ArrayList<>(providers.size());
+                }
+                services.add(s);
             }
         }
+        return services;
     }
 
     /**
-     * Add or append the service to the key.
+     * Finds the first service offered of {@code type} and returns it.
      */
-    private static void appendServiceLocked(String key, Provider.Service service) {
-        ArrayList<Provider.Service> serviceList = services.get(key);
-        if (serviceList == null) {
-            serviceList = new ArrayList<Provider.Service>(1);
-            services.put(key, serviceList);
+    private static synchronized Provider.Service getFirstServiceOfType(String type) {
+        for (Provider p : providers) {
+            Provider.Service s = Engine.door.getService(p, type);
+            if (s != null) {
+                return s;
+            }
         }
-        serviceList.add(service);
-    }
-
-    /**
-     * Returns true if services does not contain any provider information.
-     */
-    public static synchronized boolean isEmpty() {
-        return services.isEmpty();
-    }
-
-    /**
-     * Looks up the requested service by type and algorithm. The
-     * service key should be provided in the same format used when
-     * registering a service with a provider, for example,
-     * "KeyFactory.RSA".
-     *
-     * Callers can cache the returned service information but such
-     * caches should be validated against the result of
-     * Service.getCacheVersion() before use.
-     */
-    public static synchronized ArrayList<Provider.Service> getServices(String key) {
-        return services.get(key);
+        return null;
     }
 
     /**
@@ -219,13 +193,7 @@
     public static synchronized int getCacheVersion() {
         if (needRefresh) {
             cacheVersion++;
-            synchronized (services) {
-                services.clear();
-            }
-            cachedSecureRandomService = null;
-            for (Provider p : providers) {
-                initServiceInfo(p);
-            }
+            cachedSecureRandomService = getFirstServiceOfType("SecureRandom");
             needRefresh = false;
         }
         return cacheVersion;
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index acc1e4f..787a149 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -47,7 +47,6 @@
     REGISTER(register_java_lang_StringToReal);
     REGISTER(register_java_lang_System);
     REGISTER(register_java_math_NativeBN);
-    REGISTER(register_java_nio_ByteOrder);
     REGISTER(register_java_text_Bidi);
     REGISTER(register_java_util_jar_StrictJarFile);
     REGISTER(register_java_util_regex_Matcher);
diff --git a/luni/src/main/native/java_nio_ByteOrder.cpp b/luni/src/main/native/java_nio_ByteOrder.cpp
deleted file mode 100644
index 3269bc2..0000000
--- a/luni/src/main/native/java_nio_ByteOrder.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ByteOrder"
-
-#include "JNIHelp.h"
-#include "JniConstants.h"
-
-static jboolean ByteOrder_isLittleEndian(JNIEnv*, jclass) {
-    int i = 1;
-    return *reinterpret_cast<jbyte*>(&i) == 1;
-}
-
-static JNINativeMethod gMethods[] = {
-    NATIVE_METHOD(ByteOrder, isLittleEndian, "!()Z"),
-};
-void register_java_nio_ByteOrder(JNIEnv* env) {
-    jniRegisterNativeMethods(env, "java/nio/ByteOrder", gMethods, NELEM(gMethods));
-}
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index 73ed7cb..78ec37a 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -27,7 +27,6 @@
     java_lang_StringToReal.cpp \
     java_lang_System.cpp \
     java_math_NativeBN.cpp \
-    java_nio_ByteOrder.cpp \
     java_text_Bidi.cpp \
     java_util_jar_StrictJarFile.cpp \
     java_util_regex_Matcher.cpp \
diff --git a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
index 1078cd0..c57db71 100644
--- a/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
+++ b/luni/src/test/java/dalvik/system/DexClassLoaderTest.java
@@ -16,6 +16,7 @@
 
 package dalvik.system;
 
+import java.io.FilenameFilter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.io.File;
@@ -29,93 +30,41 @@
  * Tests for the class {@link DexClassLoader}.
  */
 public class DexClassLoaderTest extends TestCase {
-    // Use /data not /sdcard because optimized cannot be noexec mounted
-    private static final File WORKING_DIR;
-    static {
-      // First try to use the test runner directory for cts, fall back to
-      // shell-writable directory for vogar
-      File runner_dir = new File("/data/data/android.core.tests.runner");
-      if (runner_dir.exists()) {
-        WORKING_DIR = runner_dir;
-      } else {
-        WORKING_DIR = new File("/data/local/tmp");
-      }
-    }
-    private static final File TMP_DIR = new File(WORKING_DIR, "loading-test");
     private static final String PACKAGE_PATH = "dalvik/system/";
-    private static final String JAR_NAME = "loading-test.jar";
-    private static final String DEX_NAME = "loading-test.dex";
-    private static final String JAR2_NAME = "loading-test2.jar";
-    private static final String DEX2_NAME = "loading-test2.dex";
-    private static final File JAR_FILE = new File(TMP_DIR, JAR_NAME);
-    private static final File DEX_FILE = new File(TMP_DIR, DEX_NAME);
-    private static final File JAR2_FILE = new File(TMP_DIR, JAR2_NAME);
-    private static final File DEX2_FILE = new File(TMP_DIR, DEX2_NAME);
-    private static final File DEFAULT_OPTIMIZED_DIR = new File(TMP_DIR, "optimized");
-    // Init tests need to use different optimized directories because the tests are executed in the
-    // same runtime. This means we can't reliably count the number of generated file since they
-    // might be cached by the runtime.
-    private static final File INIT1_OPTIMIZED_DIR = new File(TMP_DIR, "optimized_init1");
-    private static final File INIT2_OPTIMIZED_DIR = new File(TMP_DIR, "optimized_init2");
 
-    private static enum Configuration {
-        /** just one classpath element, a raw dex file */
-        ONE_DEX(1, DEX_FILE),
-        ONE_DEX_INIT(INIT1_OPTIMIZED_DIR, 1, DEX_FILE),
-
-        /** just one classpath element, a jar file */
-        ONE_JAR(1, JAR_FILE),
-        ONE_JAR_INIT(INIT1_OPTIMIZED_DIR, 1, JAR_FILE),
-
-        /** two classpath elements, both raw dex files */
-        TWO_DEX(2, DEX_FILE, DEX2_FILE),
-        TWO_DEX_INIT(INIT2_OPTIMIZED_DIR, 2, DEX_FILE, DEX2_FILE),
-
-        /** two classpath elements, both jar files */
-        TWO_JAR(2, JAR_FILE, JAR2_FILE),
-        TWO_JAR_INIT(INIT2_OPTIMIZED_DIR, 2, JAR_FILE, JAR2_FILE);
-
-        public final int expectedFiles;
-        public final File optimizedDir;
-        public final String path;
-
-        Configuration(int expectedFiles, File... files) {
-            this(DEFAULT_OPTIMIZED_DIR, expectedFiles, files);
-        }
-
-        Configuration(File optimizedDir, int expectedFiles, File... files) {
-            assertTrue(files != null && files.length > 0);
-
-            this.expectedFiles = expectedFiles;
-            this.optimizedDir = optimizedDir;
-            String path = files[0].getAbsolutePath();
-            for (int i = 1; i < files.length; i++) {
-                path += File.pathSeparator + files[i].getAbsolutePath();
-            }
-            this.path = path;
-        }
-    }
+    private File srcDir;
+    private File dex1;
+    private File dex2;
+    private File jar1;
+    private File jar2;
+    private File optimizedDir;
 
     protected void setUp() throws Exception {
-        assertTrue(TMP_DIR.exists() || TMP_DIR.mkdirs());
-        assertTrue(DEFAULT_OPTIMIZED_DIR.exists() || DEFAULT_OPTIMIZED_DIR.mkdirs());
-        assertTrue(INIT1_OPTIMIZED_DIR.exists() || INIT1_OPTIMIZED_DIR.mkdirs());
-        assertTrue(INIT2_OPTIMIZED_DIR.exists() || INIT2_OPTIMIZED_DIR.mkdirs());
+        srcDir = File.createTempFile("src", "");
+        assertTrue(srcDir.delete());
+        assertTrue(srcDir.mkdirs());
 
-        ClassLoader cl = DexClassLoaderTest.class.getClassLoader();
-        copyResource(cl, JAR_NAME, JAR_FILE);
-        copyResource(cl, DEX_NAME, DEX_FILE);
-        copyResource(cl, JAR2_NAME, JAR2_FILE);
-        copyResource(cl, DEX2_NAME, DEX2_FILE);
+        dex1 = new File(srcDir, "loading-test.dex");
+        dex2 = new File(srcDir, "loading-test2.dex");
+        jar1 = new File(srcDir, "loading-test.jar");
+        jar2 = new File(srcDir, "loading-test2.jar");
+
+        copyResource("loading-test.dex", dex1);
+        copyResource("loading-test2.dex", dex2);
+        copyResource("loading-test.jar", jar1);
+        copyResource("loading-test2.jar", jar2);
+
+        optimizedDir = File.createTempFile("optimized", "");
+        assertTrue(optimizedDir.delete());
+        assertTrue(optimizedDir.mkdirs());
     }
 
     protected void tearDown() {
-        cleanUpDir(DEFAULT_OPTIMIZED_DIR);
-        cleanUpDir(INIT1_OPTIMIZED_DIR);
-        cleanUpDir(INIT2_OPTIMIZED_DIR);
+        cleanUpDir(srcDir);
+        cleanUpDir(optimizedDir);
     }
 
-    private void cleanUpDir(File dir) {
+    private static void cleanUpDir(File dir) {
         if (!dir.isDirectory()) {
             return;
         }
@@ -127,54 +76,85 @@
 
     /**
      * Copy a resource in the package directory to the indicated
-     * target file, but only if the target file doesn't exist.
+     * target file.
      */
-    private static void copyResource(ClassLoader loader, String resourceName,
+    private static void copyResource(String resourceName,
             File destination) throws IOException {
-        if (destination.exists()) {
-            return;
+        ClassLoader loader = DexClassLoaderTest.class.getClassLoader();
+        assertFalse(destination.exists());
+        InputStream in = loader.getResourceAsStream(PACKAGE_PATH + resourceName);
+        if (in == null) {
+            throw new IllegalStateException("Resource not found: " + PACKAGE_PATH + resourceName);
         }
 
-        InputStream in =
-            loader.getResourceAsStream(PACKAGE_PATH + resourceName);
-        FileOutputStream out = new FileOutputStream(destination);
-        Streams.copy(in, out);
-        in.close();
-        out.close();
+        try (FileOutputStream out = new FileOutputStream(destination)) {
+            Streams.copy(in, out);
+        } finally {
+            in.close();
+        }
     }
 
+    static final FilenameFilter DEX_FILE_NAME_FILTER = new FilenameFilter() {
+        @Override
+        public boolean accept(File file, String s) {
+            return s.endsWith(".dex");
+        }
+    };
+
     /**
-     * Helper to construct an instance to test.
+     * Helper to construct a DexClassLoader instance to test.
      *
-     * @param config how to configure the classpath
+     * @param files The .dex or .jar files to use for the class path.
      */
-    private static DexClassLoader createInstance(Configuration config) {
-        return new DexClassLoader(
-            config.path, config.optimizedDir.getAbsolutePath(), null,
+    private ClassLoader createLoader(File... files) {
+        assertNotNull(files);
+        assertTrue(files.length > 0);
+        String path = files[0].getAbsolutePath();
+        for (int i = 1; i < files.length; i++) {
+            path += File.pathSeparator + files[i].getAbsolutePath();
+        }
+        return new DexClassLoader(path, optimizedDir.getAbsolutePath(), null,
             ClassLoader.getSystemClassLoader());
     }
 
     /**
-     * Helper to construct an instance to test, using the jar file as
-     * the source, and call a named no-argument static method on a
-     * named class.
+     * Helper to construct a new DexClassLoader instance to test, using the
+     * given files as the class path, and call a named no-argument static
+     * method on a named class.
      *
-     * @param config how to configure the classpath
+     * @param className The name of the class of the method to call.
+     * @param methodName The name of the method to call.
+     * @param files The .dex or .jar files to use for the class path.
      */
-    public static Object createInstanceAndCallStaticMethod(
-            Configuration config, String className, String methodName)
-            throws ClassNotFoundException, NoSuchMethodException,
-            IllegalAccessException, InvocationTargetException {
-        DexClassLoader dcl = createInstance(config);
-        Class c = dcl.loadClass(className);
+    public Object createLoaderAndCallMethod(
+            String className, String methodName, File... files)
+            throws ReflectiveOperationException {
+        ClassLoader cl = createLoader(files);
+        Class c = cl.loadClass(className);
         Method m = c.getMethod(methodName, (Class[]) null);
         return m.invoke(null, (Object[]) null);
     }
 
-    /*
-     * Tests that are parametric with respect to whether to use a jar
-     * file or a dex file as the source of the code
+    /**
+     * Helper to construct a new DexClassLoader instance to test, using the
+     * given files as the class path, and read the contents of the named
+     * resource as a String.
+     *
+     * @param resourceName The name of the resource to get.
+     * @param files The .dex or .jar files to use for the class path.
      */
+    private String createLoaderAndGetResource(String resourceName, File... files) throws Exception {
+        ClassLoader cl = createLoader(files);
+        InputStream in = cl.getResourceAsStream(resourceName);
+        if (in == null) {
+            throw new IllegalStateException("Resource not found: " + resourceName);
+        }
+
+        byte[] contents = Streams.readFully(in);
+        return new String(contents, "UTF-8");
+    }
+
+    // ONE_JAR
 
     /**
      * Just a trivial test of construction. This one merely makes
@@ -182,23 +162,19 @@
      * to verify anything about the constructed instance, other than
      * checking for the existence of optimized dex files.
      */
-    private static void test_init(Configuration config) {
-        createInstance(config);
-
-        int expectedFiles = config.expectedFiles;
-        int actualFiles = config.optimizedDir.listFiles().length;
-
-        assertEquals(expectedFiles, actualFiles);
+    public void test_oneJar_init() throws Exception {
+        ClassLoader cl = createLoader(jar1);
+        File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+        assertNotNull(files);
+        assertEquals(1, files.length);
     }
 
     /**
      * Check that a class in the jar/dex file may be used successfully. In this
      * case, a trivial static method is called.
      */
-    private static void test_simpleUse(Configuration config) throws Exception {
-        String result = (String)
-            createInstanceAndCallStaticMethod(config, "test.Test1", "test");
-
+    public void test_oneJar_simpleUse() throws Exception {
+        String result = (String) createLoaderAndCallMethod("test.Test1", "test", jar1);
         assertSame("blort", result);
     }
 
@@ -207,312 +183,214 @@
      * that lives inside the loading-test dex/jar file.
      */
 
-    private static void test_constructor(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_constructor");
-    }
-
-    private static void test_callStaticMethod(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_callStaticMethod");
-    }
-
-    private static void test_getStaticVariable(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_getStaticVariable");
-    }
-
-    private static void test_callInstanceMethod(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_callInstanceMethod");
-    }
-
-    private static void test_getInstanceVariable(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_getInstanceVariable");
-    }
-
-    private static void test_diff_constructor(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_diff_constructor");
-    }
-
-    private static void test_diff_callStaticMethod(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_diff_callStaticMethod");
-    }
-
-    private static void test_diff_getStaticVariable(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_diff_getStaticVariable");
-    }
-
-    private static void test_diff_callInstanceMethod(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_diff_callInstanceMethod");
-    }
-
-    private static void test_diff_getInstanceVariable(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_diff_getInstanceVariable");
-    }
-
-    /*
-     * These methods are all essentially just calls to the
-     * parametrically-defined tests above.
-     */
-
-    // ONE_JAR
-
-    public void test_oneJar_init() throws Exception {
-        test_init(Configuration.ONE_JAR_INIT);
-    }
-
-    public void test_oneJar_simpleUse() throws Exception {
-        test_simpleUse(Configuration.ONE_JAR);
-    }
-
     public void test_oneJar_constructor() throws Exception {
-        test_constructor(Configuration.ONE_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_constructor", jar1);
     }
 
     public void test_oneJar_callStaticMethod() throws Exception {
-        test_callStaticMethod(Configuration.ONE_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", jar1);
     }
 
     public void test_oneJar_getStaticVariable() throws Exception {
-        test_getStaticVariable(Configuration.ONE_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", jar1);
     }
 
     public void test_oneJar_callInstanceMethod() throws Exception {
-        test_callInstanceMethod(Configuration.ONE_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", jar1);
     }
 
     public void test_oneJar_getInstanceVariable() throws Exception {
-        test_getInstanceVariable(Configuration.ONE_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", jar1);
     }
 
     // ONE_DEX
 
     public void test_oneDex_init() throws Exception {
-        test_init(Configuration.ONE_DEX_INIT);
+        ClassLoader cl = createLoader(dex1);
+        File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+        assertNotNull(files);
+        assertEquals(1, files.length);
     }
 
     public void test_oneDex_simpleUse() throws Exception {
-        test_simpleUse(Configuration.ONE_DEX);
+        String result = (String) createLoaderAndCallMethod("test.Test1", "test", dex1);
+        assertSame("blort", result);
     }
 
     public void test_oneDex_constructor() throws Exception {
-        test_constructor(Configuration.ONE_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_constructor", dex1);
     }
 
     public void test_oneDex_callStaticMethod() throws Exception {
-        test_callStaticMethod(Configuration.ONE_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1);
     }
 
     public void test_oneDex_getStaticVariable() throws Exception {
-        test_getStaticVariable(Configuration.ONE_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1);
     }
 
     public void test_oneDex_callInstanceMethod() throws Exception {
-        test_callInstanceMethod(Configuration.ONE_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1);
     }
 
     public void test_oneDex_getInstanceVariable() throws Exception {
-        test_getInstanceVariable(Configuration.ONE_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1);
     }
 
     // TWO_JAR
 
     public void test_twoJar_init() throws Exception {
-        test_init(Configuration.TWO_JAR_INIT);
+        ClassLoader cl = createLoader(jar1, jar2);
+        File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+        assertNotNull(files);
+        assertEquals(2, files.length);
     }
 
     public void test_twoJar_simpleUse() throws Exception {
-        test_simpleUse(Configuration.TWO_JAR);
+        String result = (String) createLoaderAndCallMethod("test.Test1", "test", jar1, jar2);
+        assertSame("blort", result);
     }
 
     public void test_twoJar_constructor() throws Exception {
-        test_constructor(Configuration.TWO_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_constructor", jar1, jar2);
     }
 
     public void test_twoJar_callStaticMethod() throws Exception {
-        test_callStaticMethod(Configuration.TWO_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", jar1, jar2);
     }
 
     public void test_twoJar_getStaticVariable() throws Exception {
-        test_getStaticVariable(Configuration.TWO_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", jar1, jar2);
     }
 
     public void test_twoJar_callInstanceMethod() throws Exception {
-        test_callInstanceMethod(Configuration.TWO_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", jar1, jar2);
     }
 
     public void test_twoJar_getInstanceVariable() throws Exception {
-        test_getInstanceVariable(Configuration.TWO_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", jar1, jar2);
     }
 
-    public static void test_twoJar_diff_constructor() throws Exception {
-        test_diff_constructor(Configuration.TWO_JAR);
+    public void test_twoJar_diff_constructor() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_constructor", jar1, jar2);
     }
 
-    public static void test_twoJar_diff_callStaticMethod() throws Exception {
-        test_diff_callStaticMethod(Configuration.TWO_JAR);
+    public void test_twoJar_diff_callStaticMethod() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_callStaticMethod", jar1, jar2);
     }
 
-    public static void test_twoJar_diff_getStaticVariable() throws Exception {
-        test_diff_getStaticVariable(Configuration.TWO_JAR);
+    public void test_twoJar_diff_getStaticVariable() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_getStaticVariable", jar1, jar2);
     }
 
-    public static void test_twoJar_diff_callInstanceMethod()
-            throws Exception {
-        test_diff_callInstanceMethod(Configuration.TWO_JAR);
+    public void test_twoJar_diff_callInstanceMethod() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_callInstanceMethod", jar1, jar2);
     }
 
-    public static void test_twoJar_diff_getInstanceVariable()
-            throws Exception {
-        test_diff_getInstanceVariable(Configuration.TWO_JAR);
+    public void test_twoJar_diff_getInstanceVariable() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_getInstanceVariable", jar1, jar2);
     }
 
     // TWO_DEX
 
     public void test_twoDex_init() throws Exception {
-        test_init(Configuration.TWO_DEX_INIT);
+        ClassLoader cl = createLoader(dex1, dex2);
+        File[] files = optimizedDir.listFiles(DEX_FILE_NAME_FILTER);
+        assertNotNull(files);
+        assertEquals(2, files.length);
     }
 
     public void test_twoDex_simpleUse() throws Exception {
-        test_simpleUse(Configuration.TWO_DEX);
+        String result = (String) createLoaderAndCallMethod("test.Test1", "test", dex1, dex2);
+        assertSame("blort", result);
     }
 
     public void test_twoDex_constructor() throws Exception {
-        test_constructor(Configuration.TWO_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_constructor", dex1, dex2);
     }
 
     public void test_twoDex_callStaticMethod() throws Exception {
-        test_callStaticMethod(Configuration.TWO_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_callStaticMethod", dex1, dex2);
     }
 
     public void test_twoDex_getStaticVariable() throws Exception {
-        test_getStaticVariable(Configuration.TWO_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_getStaticVariable", dex1, dex2);
     }
 
     public void test_twoDex_callInstanceMethod() throws Exception {
-        test_callInstanceMethod(Configuration.TWO_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_callInstanceMethod", dex1, dex2);
     }
 
     public void test_twoDex_getInstanceVariable() throws Exception {
-        test_getInstanceVariable(Configuration.TWO_DEX);
+        createLoaderAndCallMethod("test.TestMethods", "test_getInstanceVariable", dex1, dex2);
     }
 
-    public static void test_twoDex_diff_constructor() throws Exception {
-        test_diff_constructor(Configuration.TWO_DEX);
+    public void test_twoDex_diff_constructor() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_constructor", dex1, dex2);
     }
 
-    public static void test_twoDex_diff_callStaticMethod() throws Exception {
-        test_diff_callStaticMethod(Configuration.TWO_DEX);
+    public void test_twoDex_diff_callStaticMethod() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_callStaticMethod", dex1, dex2);
     }
 
-    public static void test_twoDex_diff_getStaticVariable() throws Exception {
-        test_diff_getStaticVariable(Configuration.TWO_DEX);
+    public void test_twoDex_diff_getStaticVariable() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_getStaticVariable", dex1, dex2);
     }
 
-    public static void test_twoDex_diff_callInstanceMethod()
-            throws Exception {
-        test_diff_callInstanceMethod(Configuration.TWO_DEX);
+    public void test_twoDex_diff_callInstanceMethod() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_callInstanceMethod", dex1, dex2);
     }
 
-    public static void test_twoDex_diff_getInstanceVariable()
-            throws Exception {
-        test_diff_getInstanceVariable(Configuration.TWO_DEX);
+    public void test_twoDex_diff_getInstanceVariable() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_getInstanceVariable", dex1, dex2);
     }
 
     /*
      * Tests specifically for resource-related functionality.  Since
      * raw dex files don't contain resources, these test only work
-     * with jar files. The first couple methods here are helpers,
-     * and they are followed by the tests per se.
+     * with jar files.
      */
 
     /**
-     * Check that a given resource (by name) is retrievable and contains
-     * the given expected contents.
-     */
-    private static void test_directGetResourceAsStream(Configuration config,
-            String resourceName, String expectedContents)
-            throws Exception {
-        DexClassLoader dcl = createInstance(config);
-        InputStream in = dcl.getResourceAsStream(resourceName);
-        byte[] contents = Streams.readFully(in);
-        String s = new String(contents, "UTF-8");
-
-        assertEquals(expectedContents, s);
-    }
-
-    /**
      * Check that a resource in the jar file is retrievable and contains
      * the expected contents.
      */
-    private static void test_directGetResourceAsStream(Configuration config)
-            throws Exception {
-        test_directGetResourceAsStream(
-            config, "test/Resource1.txt", "Muffins are tasty!\n");
+    public void test_oneJar_directGetResourceAsStream() throws Exception {
+        String result = createLoaderAndGetResource("test/Resource1.txt", jar1);
+        assertEquals("Muffins are tasty!\n", result);
     }
 
     /**
      * Check that a resource in the jar file can be retrieved from
      * a class within that jar file.
      */
-    private static void test_getResourceAsStream(Configuration config)
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            config, "test.TestMethods", "test_getResourceAsStream");
-    }
-
-    public void test_oneJar_directGetResourceAsStream() throws Exception {
-        test_directGetResourceAsStream(Configuration.ONE_JAR);
-    }
-
     public void test_oneJar_getResourceAsStream() throws Exception {
-        test_getResourceAsStream(Configuration.ONE_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_getResourceAsStream", jar1);
     }
 
     public void test_twoJar_directGetResourceAsStream() throws Exception {
-        test_directGetResourceAsStream(Configuration.TWO_JAR);
+        String result = createLoaderAndGetResource("test/Resource1.txt", jar1, jar2);
+        assertEquals("Muffins are tasty!\n", result);
     }
 
     public void test_twoJar_getResourceAsStream() throws Exception {
-        test_getResourceAsStream(Configuration.TWO_JAR);
+        createLoaderAndCallMethod("test.TestMethods", "test_getResourceAsStream", jar1, jar2);
     }
 
     /**
      * Check that a resource in the second jar file is retrievable and
      * contains the expected contents.
      */
-    public void test_twoJar_diff_directGetResourceAsStream()
-            throws Exception {
-        test_directGetResourceAsStream(
-            Configuration.TWO_JAR, "test2/Resource2.txt",
-            "Who doesn't like a good biscuit?\n");
+    public void test_twoJar_diff_directGetResourceAsStream() throws Exception {
+        String result = createLoaderAndGetResource("test2/Resource2.txt", jar1, jar2);
+        assertEquals("Who doesn't like a good biscuit?\n", result);
     }
 
     /**
      * Check that a resource in a jar file can be retrieved from
      * a class within the other jar file.
      */
-    public void test_twoJar_diff_getResourceAsStream()
-            throws Exception {
-        createInstanceAndCallStaticMethod(
-            Configuration.TWO_JAR, "test.TestMethods",
-            "test_diff_getResourceAsStream");
+    public void test_twoJar_diff_getResourceAsStream() throws Exception {
+        createLoaderAndCallMethod("test.TestMethods", "test_diff_getResourceAsStream", jar1, jar2);
     }
 }
diff --git a/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
index 9e6d8d7..31e8fc7 100644
--- a/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/PathClassLoaderTest.java
@@ -17,9 +17,12 @@
 package libcore.dalvik.system;
 
 import dalvik.system.PathClassLoader;
+import java.lang.reflect.Method;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import libcore.io.Streams;
 import junit.framework.TestCase;
 
 public final class PathClassLoaderTest extends TestCase {
@@ -52,6 +55,26 @@
         return result;
     }
 
+    public void testAppUseOfPathClassLoader() throws Exception {
+        // Extract loading-test.jar from the resource.
+        ClassLoader pcl = PathClassLoaderTest.class.getClassLoader();
+        File jar = File.createTempFile("loading-test", ".jar");
+        try (InputStream in = pcl.getResourceAsStream("dalvik/system/loading-test.jar");
+             FileOutputStream out = new FileOutputStream(jar)) {
+          Streams.copy(in, out);
+        }
+
+        // Execute code from the jar file using a PathClassLoader.
+        PathClassLoader cl = new PathClassLoader(jar.getPath(), pcl);
+        Class c = cl.loadClass("test.Test1");
+        Method m = c.getMethod("test", (Class[]) null);
+        String result = (String) m.invoke(null, (Object[]) null);
+        assertSame("blort", result);
+
+        // Clean up the extracted jar file.
+        assertTrue(jar.delete());
+    }
+
     @Override protected void setUp() throws Exception {
         super.setUp();
     }
diff --git a/luni/src/test/java/libcore/java/lang/OldSystemTest.java b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
index dee5bdd..93b06c8 100644
--- a/luni/src/test/java/libcore/java/lang/OldSystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
@@ -260,12 +260,14 @@
         while(rt.freeMemory() < beforeTest * 2/3) {
              vec.add(new StringBuffer(1000));
         }
-        long beforeGC = rt.freeMemory();
+        long beforeGC = rt.totalMemory() - rt.freeMemory();
+        vec = null;
         System.gc();
-        long afterGC = rt.freeMemory();
+        System.runFinalization();
+        long afterGC = rt.totalMemory() - rt.freeMemory();
         assertTrue("memory was not released after calling System.gc()." +
                 "before gc: " + beforeGC + "; after gc: " + afterGC,
-                beforeGC < afterGC);
+                beforeGC > afterGC);
     }
 
     public void test_getenv() {
diff --git a/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java b/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
index e874a1b..4fa6e0c 100644
--- a/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
+++ b/luni/src/test/java/libcore/java/nio/charset/CharsetDecoderTest.java
@@ -105,4 +105,15 @@
         assertEquals(1, cb.position());
         assertEquals('\u2603', cb.get(0));
     }
+
+    public void testBufferWithNonZeroOffset() {
+        CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
+        CharBuffer cb = CharBuffer.allocate(128);
+        cb.position(42);
+        CharBuffer out = cb.slice();
+        CoderResult cr = decoder.decode(
+                ByteBuffer.wrap(new byte[] { 'h', 'e', 'l', 'l', 'o'}), out, false);
+        assertTrue(cr.isUnderflow());
+        assertEquals(5, out.position());
+    }
 }
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index 0be558e..9cb780a 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -547,6 +547,15 @@
         }
     }
 
+    public void testProvider_removeProvider_Success() throws Exception {
+        MockProvider provider = new MockProvider("MockProvider");
+        assertNull(Security.getProvider(provider.getName()));
+        Security.addProvider(provider);
+        assertNotNull(Security.getProvider(provider.getName()));
+        Security.removeProvider(provider.getName());
+        assertNull(Security.getProvider(provider.getName()));
+    }
+
     public static class MyCertStoreSpi extends CertStoreSpi {
         public MyCertStoreSpi(CertStoreParameters params) throws InvalidAlgorithmParameterException {
             super(params);
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index f28446c..6129e1e 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -393,9 +393,14 @@
         return data;
     }
 
-    // http://code.google.com/p/android/issues/detail?id=18566
-    // http://b/5038554
-    public void test18566() throws Exception {
+    /**
+     * This should actually fail because the ASN.1 encoding is incorrect. It is
+     * missing the NULL in the AlgorithmIdentifier field.
+     * <p>
+     * http://code.google.com/p/android/issues/detail?id=18566 <br/>
+     * http://b/5038554
+     */
+    public void test18566_AlgorithmOid_MissingNull_Failure() throws Exception {
         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(PK_BYTES);
         KeyFactory keyFactory = KeyFactory.getInstance("RSA");
         PublicKey pk = keyFactory.generatePublic(keySpec);
@@ -403,7 +408,7 @@
         Signature sig = Signature.getInstance("SHA256withRSA");
         sig.initVerify(pk);
         sig.update(CONTENT);
-        assertTrue(sig.verify(SIGNATURE));
+        assertFalse(sig.verify(SIGNATURE));
     }
 
     /*
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
index 3e0aeba..b1d37f3 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatSymbolsTest.java
@@ -86,4 +86,34 @@
         assertEquals("$", dfs.getCurrencySymbol());
         assertEquals(null, dfs.getInternationalCurrencySymbol());
     }
+
+    // https://code.google.com/p/android/issues/detail?id=170718
+    public void testSerializationOfMultiCharNegativeAndPercentage() throws Exception {
+        DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.forLanguageTag("ar-AR"));
+        assertTrue(dfs.getMinusSignString().length() > 1);
+        assertTrue(dfs.getPercentString().length() > 1);
+
+        // Serialize...
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        new ObjectOutputStream(out).writeObject(dfs);
+        byte[] bytes = out.toByteArray();
+
+        // Deserialize...
+        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
+        DecimalFormatSymbols deserializedDfs = (DecimalFormatSymbols) in.readObject();
+        assertEquals(-1, in.read());
+
+        assertEquals(dfs.getMinusSignString(), deserializedDfs.getMinusSignString());
+        assertEquals(dfs.getPercentString(), deserializedDfs.getPercentString());
+    }
+
+    // http://b/18785260
+    public void testMultiCharMinusSignAndPercentage() {
+        DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.forLanguageTag("ar-AR"));
+        assertTrue(dfs.getMinusSignString().length() > 1);
+        assertTrue(dfs.getPercentString().length() > 1);
+
+        assertEquals('%', dfs.getPercent());
+        assertEquals('-', dfs.getMinusSign());
+    }
 }
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
index ad084e1..22e6795 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
@@ -478,17 +478,10 @@
         } catch (IllegalArgumentException expected) {
         }
 
-        if (StandardNames.IS_RI) {
-            try {
-                sig.verify(signature, signature.length, 0);
-                fail();
-            } catch (SignatureException expected) {
-            }
-        } else {
-            // Calling Signature.verify a second time should not throw
-            // http://code.google.com/p/android/issues/detail?id=34933
-            boolean verified = sig.verify(signature, signature.length, 0);
-            assertFalse(verified);
+        try {
+            sig.verify(signature, signature.length, 0);
+            fail();
+        } catch (SignatureException expected) {
         }
 
         try {
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index 9aab942..793c409 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -180,7 +180,6 @@
         provide("Cipher", "DES");
         provide("Cipher", "DESede");
         provide("Cipher", "DESedeWrap");
-        provide("Cipher", "GCM");
         provide("Cipher", "PBEWithMD5AndDES");
         provide("Cipher", "PBEWithMD5AndTripleDES");
         provide("Cipher", "PBEWithSHA1AndDESede");
@@ -312,25 +311,29 @@
         // Only available with the SunPKCS11-NSS provider,
         // which seems to be enabled in OpenJDK 6 but not Oracle Java 6
         if (Security.getProvider("SunPKCS11-NSS") != null) {
-            provide("AlgorithmParameters", "EC");
             provide("Cipher", "AES/CBC/NOPADDING");
             provide("Cipher", "DES/CBC/NOPADDING");
             provide("Cipher", "DESEDE/CBC/NOPADDING");
             provide("Cipher", "RSA/ECB/PKCS1PADDING");
             provide("KeyAgreement", "DH");
-            provide("KeyAgreement", "ECDH");
             provide("KeyFactory", "DH");
-            provide("KeyFactory", "EC");
             provide("KeyPairGenerator", "DH");
-            provide("KeyPairGenerator", "EC");
             provide("KeyStore", "PKCS11");
             provide("MessageDigest", "SHA1");
             provide("SecretKeyFactory", "AES");
             provide("SecretKeyFactory", "ARCFOUR");
             provide("SecureRandom", "PKCS11");
             provide("Signature", "DSA");
-            provide("Signature", "NONEWITHECDSA");
             provide("Signature", "RAWDSA");
+        }
+
+        if (Security.getProvider("SunPKCS11-NSS") != null ||
+                Security.getProvider("SunEC") != null) {
+            provide("AlgorithmParameters", "EC");
+            provide("KeyAgreement", "ECDH");
+            provide("KeyFactory", "EC");
+            provide("KeyPairGenerator", "EC");
+            provide("Signature", "NONEWITHECDSA");
             provide("Signature", "SHA1WITHECDSA");
             provide("Signature", "SHA224WITHECDSA");
             provide("Signature", "SHA256WITHECDSA");
@@ -479,6 +482,7 @@
             provide("Cipher", "AES/ECB/NOPADDING");
             provide("Cipher", "AES/ECB/PKCS5PADDING");
             provide("Cipher", "AES/ECB/PKCS7PADDING");
+            provide("Cipher", "AES/GCM/NOPADDING");
             provide("Cipher", "AES/OFB/NOPADDING");
             provide("Cipher", "AES/OFB/PKCS5PADDING");
             provide("Cipher", "AES/OFB/PKCS7PADDING");