Update ResourceBundle related classes from java.util to OpenJDK8u60

Documented several previously undocumented Android-changed sections
that were missed in the initial draft of this CL.

 - ResourceBundle
   Added test for new method getBaseBundleName().
   Added missing Android-changed comment for:
     - use of UTF-8 for PropertyResourceBundles
     - use of getLoader(VMStack.getCallingClassLoader())
 - spi.ResourceBundleControlProvider
 - PropertyResourceBundle, ListResourceBundle
   Android-changed: Made access to the 'lookup' field thread safe.
 - ServiceLoader
   Do not use legacy security code.
   Added missing Android-changed comments for loadFromSystemProperty()
   and for fail() invocations where Android passes a 'Throwable cause'.

Bug: 29935305

Test: run cts -m CtsLibcoreTestCases

Change-Id: Idc3a7c5513644dd103e7d132789d37a1c40f1471
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
index db2ee7a..5d35e4c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
@@ -39,6 +39,17 @@
         assertEquals("[de_CH, de, ]", c.getCandidateLocales("base", new Locale("de", "CH")).toString());
     }
 
+    public void test_getBaseName() {
+        String name = "tests.support.Support_TestResource";
+        ResourceBundle bundle = ResourceBundle.getBundle(name);
+        assertEquals(name, bundle.getBaseBundleName());
+
+        bundle = ResourceBundle.getBundle(name, Locale.getDefault());
+        assertEquals(name, bundle.getBaseBundleName());
+
+        assertNull(new Mock_ResourceBundle().getBaseBundleName());
+    }
+
     /**
      * java.util.ResourceBundle#getBundle(java.lang.String,
      *        java.util.Locale)
diff --git a/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java b/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java
index b69a2dd..f17eb22 100644
--- a/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java
+++ b/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java
@@ -44,7 +44,7 @@
       ServiceLoader.load(ServiceLoaderTestInterfaceMissingClass.class).iterator().next();
       fail();
     } catch (ServiceConfigurationError expected) {
-      assertTrue(expected.getCause() instanceof ClassNotFoundException);
+      assertTrue(expected.toString(), expected.getCause() instanceof ClassNotFoundException);
     }
   }
 
@@ -55,7 +55,7 @@
       ServiceLoader.load(ServiceLoaderTestInterfaceWrongType.class).iterator().next();
       fail();
     } catch (ServiceConfigurationError expected) {
-      assertTrue(expected.getCause() instanceof ClassCastException);
+      assertTrue(expected.toString(), expected.getCause() instanceof ClassCastException);
     }
   }
 
diff --git a/ojluni/src/main/java/java/util/ListResourceBundle.java b/ojluni/src/main/java/java/util/ListResourceBundle.java
index 736016f..99090ca 100644
--- a/ojluni/src/main/java/java/util/ListResourceBundle.java
+++ b/ojluni/src/main/java/java/util/ListResourceBundle.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2010, 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
@@ -89,7 +89,7 @@
  *
  * public class MyResources_fr extends ListResourceBundle {
  *     protected Object[][] getContents() {
- *         return new Object[][] = {
+ *         return new Object[][] {
  *         // LOCALIZE THIS
  *             {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
  *             {"s2", "1"},                               // location of {0} in pattern
@@ -105,6 +105,12 @@
  * }
  * </pre>
  * </blockquote>
+ *
+ * <p>
+ * The implementation of a {@code ListResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the methods in this class are thread-safe.
+ *
  * @see ResourceBundle
  * @see PropertyResourceBundle
  * @since JDK1.1
@@ -200,5 +206,8 @@
         lookup = temp;
     }
 
-    private Map<String,Object> lookup = null;
+    // Android-changed: Fix unsafe publication http://b/31467561
+    // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+    // was: private Map<String,Object> lookup = null;
+    private volatile Map<String,Object> lookup = null;
 }
diff --git a/ojluni/src/main/java/java/util/PropertyResourceBundle.java b/ojluni/src/main/java/java/util/PropertyResourceBundle.java
index c7fe3b4..23c3ffe 100644
--- a/ojluni/src/main/java/java/util/PropertyResourceBundle.java
+++ b/ojluni/src/main/java/java/util/PropertyResourceBundle.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2006, 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
@@ -100,6 +100,11 @@
  * </blockquote>
  *
  * <p>
+ * The implementation of a {@code PropertyResourceBundle} subclass must be
+ * thread-safe if it's simultaneously used by multiple threads. The default
+ * implementations of the non-abstract methods in this class are thread-safe.
+ *
+ * <p>
  * <strong>Note:</strong> PropertyResourceBundle can be constructed either
  * from an InputStream or a Reader, which represents a property file.
  * Constructing a PropertyResourceBundle instance from an InputStream requires
@@ -124,7 +129,10 @@
      *        to read from.
      * @throws IOException if an I/O error occurs
      * @throws NullPointerException if <code>stream</code> is null
+     * @throws IllegalArgumentException if {@code stream} contains a
+     *     malformed Unicode escape sequence.
      */
+    @SuppressWarnings({"unchecked", "rawtypes"})
     public PropertyResourceBundle (InputStream stream) throws IOException {
         Properties properties = new Properties();
         properties.load(stream);
@@ -141,8 +149,11 @@
      *        read from.
      * @throws IOException if an I/O error occurs
      * @throws NullPointerException if <code>reader</code> is null
+     * @throws IllegalArgumentException if a malformed Unicode escape sequence appears
+     *     from {@code reader}.
      * @since 1.6
      */
+    @SuppressWarnings({"unchecked", "rawtypes"})
     public PropertyResourceBundle (Reader reader) throws IOException {
         Properties properties = new Properties();
         properties.load(reader);
@@ -186,5 +197,8 @@
 
     // ==================privates====================
 
-    private Map<String,Object> lookup;
+    // Android-changed: Fix unsafe publication http://b/31467561
+    // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+    // was: private Map<String,Object> lookup;
+    private final Map<String,Object> lookup;
 }
diff --git a/ojluni/src/main/java/java/util/ResourceBundle.java b/ojluni/src/main/java/java/util/ResourceBundle.java
index f604089..bf73b03 100644
--- a/ojluni/src/main/java/java/util/ResourceBundle.java
+++ b/ojluni/src/main/java/java/util/ResourceBundle.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
@@ -41,7 +41,6 @@
 
 package java.util;
 
-import dalvik.system.VMStack;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -59,7 +58,9 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.jar.JarEntry;
+import java.util.spi.ResourceBundleControlProvider;
 
+import dalvik.system.VMStack;
 import sun.reflect.CallerSensitive;
 import sun.util.locale.BaseLocale;
 import sun.util.locale.LocaleObjectCache;
@@ -76,7 +77,7 @@
  *
  * <p>
  * This allows you to write programs that can:
- * <UL type=SQUARE>
+ * <UL>
  * <LI> be easily localized, or translated, into different languages
  * <LI> handle multiple locales at once
  * <LI> be easily modified later to support even more locales
@@ -186,7 +187,14 @@
  * subclass.  Your subclasses must override two methods: <code>handleGetObject</code>
  * and <code>getKeys()</code>.
  *
- * <h4>ResourceBundle.Control</h4>
+ * <p>
+ * The implementation of a {@code ResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the non-abstract methods in this class, and the methods in the direct
+ * known concrete subclasses {@code ListResourceBundle} and
+ * {@code PropertyResourceBundle} are thread-safe.
+ *
+ * <h3>ResourceBundle.Control</h3>
  *
  * The {@link ResourceBundle.Control} class provides information necessary
  * to perform the bundle loading process by the <code>getBundle</code>
@@ -197,7 +205,18 @@
  * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
  * factory method for details.
  *
- * <h4>Cache Management</h4>
+ * <p><a name="modify_default_behavior">For the {@code getBundle} factory</a>
+ * methods that take no {@link Control} instance, their <a
+ * href="#default_behavior"> default behavior</a> of resource bundle loading
+ * can be modified with <em>installed</em> {@link
+ * ResourceBundleControlProvider} implementations. Any installed providers are
+ * detected at the {@code ResourceBundle} class loading time. If any of the
+ * providers provides a {@link Control} for the given base name, that {@link
+ * Control} will be used instead of the default {@link Control}. If there is
+ * more than one service provider installed for supporting the same base name,
+ * the first one returned from {@link ServiceLoader} will be used.
+ *
+ * <h3>Cache Management</h3>
  *
  * Resource bundle instances created by the <code>getBundle</code> factory
  * methods are cached by default, and the factory methods return the same
@@ -213,7 +232,7 @@
  * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
  * long) ResourceBundle.Control.needsReload} for details.
  *
- * <h4>Example</h4>
+ * <h3>Example</h3>
  *
  * The following is a very simple example of a <code>ResourceBundle</code>
  * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
@@ -299,7 +318,25 @@
     /**
      * Queue for reference objects referring to class loaders or bundles.
      */
-    private static final ReferenceQueue referenceQueue = new ReferenceQueue();
+    private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
+
+    /**
+     * Returns the base name of this bundle, if known, or {@code null} if unknown.
+     *
+     * If not null, then this is the value of the {@code baseName} parameter
+     * that was passed to the {@code ResourceBundle.getBundle(...)} method
+     * when the resource bundle was loaded.
+     *
+     * @return The base name of the resource bundle, as provided to and expected
+     * by the {@code ResourceBundle.getBundle(...)} methods.
+     *
+     * @see #getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader)
+     *
+     * @since 1.8
+     */
+    public String getBaseBundleName() {
+        return name;
+    }
 
     /**
      * The parent bundle of this bundle.
@@ -334,6 +371,21 @@
      */
     private volatile Set<String> keySet;
 
+    private static final List<ResourceBundleControlProvider> providers;
+
+    static {
+        List<ResourceBundleControlProvider> list = null;
+        ServiceLoader<ResourceBundleControlProvider> serviceLoaders
+                = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class);
+        for (ResourceBundleControlProvider provider : serviceLoaders) {
+            if (list == null) {
+                list = new ArrayList<>();
+            }
+            list.add(provider);
+        }
+        providers = list;
+    }
+
     /**
      * Sole constructor.  (For invocation by subclass constructors, typically
      * implicit.)
@@ -394,12 +446,13 @@
             if (parent != null) {
                 obj = parent.getObject(key);
             }
-            if (obj == null)
+            if (obj == null) {
                 throw new MissingResourceException("Can't find resource for bundle "
                                                    +this.getClass().getName()
                                                    +", key "+key,
                                                    this.getClass().getName(),
                                                    key);
+            }
         }
         return obj;
     }
@@ -420,6 +473,10 @@
      * resources on behalf of the client.
      */
     private static ClassLoader getLoader(ClassLoader cl) {
+        // Android-changed: On Android, this method takes a ClassLoader argument:
+        // Callers call {@code getLoader(VMStack.getCallingClassLoader())}
+        // instead of {@code getLoader(Reflection.getCallerClass())}.
+        // ClassLoader cl = caller == null ? null : caller.getClassLoader();
         if (cl == null) {
             // When the caller's loader is the boot class loader, cl is null
             // here. In that case, ClassLoader.getSystemClassLoader() may
@@ -486,7 +543,7 @@
      * null, but the base name and the locale must have a non-null
      * value.
      */
-    private static final class CacheKey implements Cloneable {
+    private static class CacheKey implements Cloneable {
         // These three are the actual keys for lookup in Map.
         private String name;
         private Locale locale;
@@ -581,8 +638,7 @@
                         // treat it as unequal
                         && (loader != null)
                         && (loader == otherEntry.loaderRef.get());
-            } catch (NullPointerException e) {
-            } catch (ClassCastException e) {
+            } catch (    NullPointerException | ClassCastException e) {
             }
             return false;
         }
@@ -612,7 +668,7 @@
                 return clone;
             } catch (CloneNotSupportedException e) {
                 //this should never happen
-                throw new InternalError();
+                throw new InternalError(e);
             }
         }
 
@@ -667,11 +723,11 @@
      * garbage collected when nobody else is using them. The ResourceBundle
      * class has no reason to keep class loaders alive.
      */
-    private static final class LoaderReference extends WeakReference<ClassLoader>
-                                               implements CacheKeyReference {
+    private static class LoaderReference extends WeakReference<ClassLoader>
+                                         implements CacheKeyReference {
         private CacheKey cacheKey;
 
-        LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) {
+        LoaderReference(ClassLoader referent, ReferenceQueue<Object> q, CacheKey key) {
             super(referent, q);
             cacheKey = key;
         }
@@ -685,11 +741,11 @@
      * References to bundles are soft references so that they can be garbage
      * collected when they have no hard references.
      */
-    private static final class BundleReference extends SoftReference<ResourceBundle>
-                                               implements CacheKeyReference {
+    private static class BundleReference extends SoftReference<ResourceBundle>
+                                         implements CacheKeyReference {
         private CacheKey cacheKey;
 
-        BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) {
+        BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
             super(referent, q);
             cacheKey = key;
         }
@@ -721,9 +777,10 @@
     public static final ResourceBundle getBundle(String baseName)
     {
         return getBundleImpl(baseName, Locale.getDefault(),
-                             /* must determine loader here, else we break stack invariant */
+                             // Android-changed: use of VMStack.getCallingClassLoader()
                              getLoader(VMStack.getCallingClassLoader()),
-                             Control.INSTANCE);
+                             // getLoader(Reflection.getCallerClass()),
+                             getDefaultControl(baseName));
     }
 
     /**
@@ -764,8 +821,9 @@
     public static final ResourceBundle getBundle(String baseName,
                                                  Control control) {
         return getBundleImpl(baseName, Locale.getDefault(),
-                             /* must determine loader here, else we break stack invariant */
+                             // Android-changed: use of VMStack.getCallingClassLoader()
                              getLoader(VMStack.getCallingClassLoader()),
+                             // getLoader(Reflection.getCallerClass()),
                              control);
     }
 
@@ -795,9 +853,10 @@
                                                  Locale locale)
     {
         return getBundleImpl(baseName, locale,
-                             /* must determine loader here, else we break stack invariant */
+                             // Android-changed: use of VMStack.getCallingClassLoader()
                              getLoader(VMStack.getCallingClassLoader()),
-                             Control.INSTANCE);
+                             // getLoader(Reflection.getCallerClass()),
+                             getDefaultControl(baseName));
     }
 
     /**
@@ -841,8 +900,9 @@
     public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
                                                  Control control) {
         return getBundleImpl(baseName, targetLocale,
-                             /* must determine loader here, else we break stack invariant */
+                             // Android-changed: use of VMStack.getCallingClassLoader()
                              getLoader(VMStack.getCallingClassLoader()),
+                             // getLoader(Reflection.getCallerClass()),
                              control);
     }
 
@@ -850,9 +910,15 @@
      * Gets a resource bundle using the specified base name, locale, and class
      * loader.
      *
-     * <p><a name="default_behavior"></a>This method behaves the same as calling
+     * <p>This method behaves the same as calling
      * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
-     * default instance of {@link Control}. The following describes this behavior.
+     * default instance of {@link Control} unless another {@link Control} is
+     * provided with the {@link ResourceBundleControlProvider} SPI. Refer to the
+     * description of <a href="#modify_default_behavior">modifying the default
+     * behavior</a>.
+     *
+     * <p><a name="default_behavior">The following describes the default
+     * behavior</a>.
      *
      * <p><code>getBundle</code> uses the base name, the specified locale, and
      * the default locale (obtained from {@link java.util.Locale#getDefault()
@@ -947,8 +1013,8 @@
      * <p>If still no result bundle is found, the base name alone is looked up. If
      * this still fails, a <code>MissingResourceException</code> is thrown.
      *
-     * <p><a name="parent_chain"></a> Once a result resource bundle has been found,
-     * its <em>parent chain</em> is instantiated.  If the result bundle already
+     * <p><a name="parent_chain"> Once a result resource bundle has been found,
+     * its <em>parent chain</em> is instantiated</a>.  If the result bundle already
      * has a parent (perhaps because it was returned from a cache) the chain is
      * complete.
      *
@@ -977,8 +1043,8 @@
      * path name (using "/") instead of a fully qualified class name (using
      * ".").
      *
-     * <p><a name="default_behavior_example"></a>
-     * <strong>Example:</strong>
+     * <p><a name="default_behavior_example">
+     * <strong>Example:</strong></a>
      * <p>
      * The following class and property files are provided:
      * <pre>
@@ -999,7 +1065,7 @@
      * <p>Calling <code>getBundle</code> with the locale arguments below will
      * instantiate resource bundles as follows:
      *
-     * <table>
+     * <table summary="getBundle() locale to resource bundle mapping">
      * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
      * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
      * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
@@ -1027,7 +1093,7 @@
         if (loader == null) {
             throw new NullPointerException();
         }
-        return getBundleImpl(baseName, locale, loader, Control.INSTANCE);
+        return getBundleImpl(baseName, locale, loader, getDefaultControl(baseName));
     }
 
     /**
@@ -1039,7 +1105,6 @@
      * bundles. Conceptually, the bundle loading process with the given
      * <code>control</code> is performed in the following steps.
      *
-     * <p>
      * <ol>
      * <li>This factory method looks up the resource bundle in the cache for
      * the specified <code>baseName</code>, <code>targetLocale</code> and
@@ -1079,45 +1144,45 @@
      * <code>control.newBundle</code>.
      *
      * <table style="width: 50%; text-align: left; margin-left: 40px;"
-     *  border="0" cellpadding="2" cellspacing="2">
-     * <tbody><code>
+     *  border="0" cellpadding="2" cellspacing="2" summary="locale-format combinations for newBundle">
+     * <tbody>
      * <tr>
      * <td
-     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br>
+     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>Locale</code><br>
      * </td>
      * <td
-     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br>
+     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>format</code><br>
      * </td>
      * </tr>
      * <tr>
-     * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code><br>
      * </td>
-     * <td style="vertical-align: top; width: 50%;">java.class<br>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code><br>
      * </td>
      * </tr>
      * <tr>
-     * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td>
-     * <td style="vertical-align: top; width: 50%;">java.properties<br>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code><br>
      * </td>
      * </tr>
      * <tr>
-     * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
-     * <td style="vertical-align: top; width: 50%;">java.class</td>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
      * </tr>
      * <tr>
-     * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
-     * <td style="vertical-align: top; width: 50%;">java.properties</td>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
      * </tr>
      * <tr>
-     * <td style="vertical-align: top; width: 50%;">Locale("")<br>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code><br>
      * </td>
-     * <td style="vertical-align: top; width: 50%;">java.class</td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
      * </tr>
      * <tr>
-     * <td style="vertical-align: top; width: 50%;">Locale("")</td>
-     * <td style="vertical-align: top; width: 50%;">java.properties</td>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
      * </tr>
-     * </code></tbody>
+     * </tbody>
      * </table>
      * </li>
      *
@@ -1210,7 +1275,7 @@
      * <p><code>getBundle</code> finds
      * <code>foo/bar/Messages_fr.properties</code> and creates a
      * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
-     * sets up its parent chain from the list of the candiate locales.  Only
+     * sets up its parent chain from the list of the candidate locales.  Only
      * <code>foo/bar/Messages.properties</code> is found in the list and
      * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
      * that becomes the parent of the instance for
@@ -1248,6 +1313,18 @@
         return getBundleImpl(baseName, targetLocale, loader, control);
     }
 
+    private static Control getDefaultControl(String baseName) {
+        if (providers != null) {
+            for (ResourceBundleControlProvider provider : providers) {
+                Control control = provider.getControl(baseName);
+                if (control != null) {
+                    return control;
+                }
+            }
+        }
+        return Control.INSTANCE;
+    }
+
     private static ResourceBundle getBundleImpl(String baseName, Locale locale,
                                                 ClassLoader loader, Control control) {
         if (locale == null || control == null) {
@@ -1333,8 +1410,8 @@
      * Checks if the given <code>List</code> is not null, not empty,
      * not having null in its elements.
      */
-    private static final boolean checkList(List a) {
-        boolean valid = (a != null && a.size() != 0);
+    private static boolean checkList(List<?> a) {
+        boolean valid = (a != null && !a.isEmpty());
         if (valid) {
             int size = a.size();
             for (int i = 0; valid && i < size; i++) {
@@ -1344,12 +1421,12 @@
         return valid;
     }
 
-    private static final ResourceBundle findBundle(CacheKey cacheKey,
-                                                   List<Locale> candidateLocales,
-                                                   List<String> formats,
-                                                   int index,
-                                                   Control control,
-                                                   ResourceBundle baseBundle) {
+    private static ResourceBundle findBundle(CacheKey cacheKey,
+                                             List<Locale> candidateLocales,
+                                             List<String> formats,
+                                             int index,
+                                             Control control,
+                                             ResourceBundle baseBundle) {
         Locale targetLocale = candidateLocales.get(index);
         ResourceBundle parent = null;
         if (index != candidateLocales.size() - 1) {
@@ -1421,10 +1498,10 @@
         return parent;
     }
 
-    private static final ResourceBundle loadBundle(CacheKey cacheKey,
-                                                   List<String> formats,
-                                                   Control control,
-                                                   boolean reload) {
+    private static ResourceBundle loadBundle(CacheKey cacheKey,
+                                             List<String> formats,
+                                             Control control,
+                                             boolean reload) {
 
         // Here we actually load the bundle in the order of formats
         // specified by the getFormats() value.
@@ -1461,7 +1538,7 @@
         return bundle;
     }
 
-    private static final boolean isValidBundle(ResourceBundle bundle) {
+    private static boolean isValidBundle(ResourceBundle bundle) {
         return bundle != null && bundle != NONEXISTENT_BUNDLE;
     }
 
@@ -1469,7 +1546,7 @@
      * Determines whether any of resource bundles in the parent chain,
      * including the leaf, have expired.
      */
-    private static final boolean hasValidParentChain(ResourceBundle bundle) {
+    private static boolean hasValidParentChain(ResourceBundle bundle) {
         long now = System.currentTimeMillis();
         while (bundle != null) {
             if (bundle.expired) {
@@ -1490,9 +1567,9 @@
     /**
      * Throw a MissingResourceException with proper message
      */
-    private static final void throwMissingResourceException(String baseName,
-                                                            Locale locale,
-                                                            Throwable cause) {
+    private static void throwMissingResourceException(String baseName,
+                                                      Locale locale,
+                                                      Throwable cause) {
         // If the cause is a MissingResourceException, avoid creating
         // a long chain. (6355009)
         if (cause instanceof MissingResourceException) {
@@ -1515,8 +1592,8 @@
      * cache or its parent has expired. <code>bundle.expire</code> is true
      * upon return if the bundle in the cache has expired.
      */
-    private static final ResourceBundle findBundleInCache(CacheKey cacheKey,
-                                                          Control control) {
+    private static ResourceBundle findBundleInCache(CacheKey cacheKey,
+                                                    Control control) {
         BundleReference bundleRef = cacheList.get(cacheKey);
         if (bundleRef == null) {
             return null;
@@ -1622,9 +1699,9 @@
      * the bundle before this call, the one found in the cache is
      * returned.
      */
-    private static final ResourceBundle putBundleInCache(CacheKey cacheKey,
-                                                         ResourceBundle bundle,
-                                                         Control control) {
+    private static ResourceBundle putBundleInCache(CacheKey cacheKey,
+                                                   ResourceBundle bundle,
+                                                   Control control) {
         setExpirationTime(cacheKey, control);
         if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
             CacheKey key = (CacheKey) cacheKey.clone();
@@ -1655,7 +1732,7 @@
         return bundle;
     }
 
-    private static final void setExpirationTime(CacheKey cacheKey, Control control) {
+    private static void setExpirationTime(CacheKey cacheKey, Control control) {
         long ttl = control.getTimeToLive(cacheKey.getName(),
                                          cacheKey.getLocale());
         if (ttl >= 0) {
@@ -1680,7 +1757,9 @@
      */
     @CallerSensitive
     public static final void clearCache() {
+        // Android-changed: use of VMStack.getCallingClassLoader()
         clearCache(getLoader(VMStack.getCallingClassLoader()));
+        // clearCache(getLoader(Reflection.getCallerClass()));
     }
 
     /**
@@ -2160,11 +2239,11 @@
          * one by one as below:
          *
          * <ul>
-         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
-         * <li> [<em>L</em>, <em>C</em>]
-         * <li> [<em>L</em>]
-         * <li> <code>Locale.ROOT</code>
-         * </ul>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>] </li>
+         * <li> [<em>L</em>, <em>C</em>] </li>
+         * <li> [<em>L</em>] </li>
+         * <li> <code>Locale.ROOT</code> </li>
+         * </ul></li>
          *
          * <li>For an input <code>Locale</code> with a non-empty script value,
          * append candidate <code>Locale</code>s by omitting the final component
@@ -2172,33 +2251,33 @@
          * <code>Locale</code> with country and variant restored:
          *
          * <ul>
-         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
-         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
-         * <li> [<em>L</em>, <em>S</em>]
-         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
-         * <li> [<em>L</em>, <em>C</em>]
-         * <li> [<em>L</em>]
-         * <li> <code>Locale.ROOT</code>
-         * </ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
          *
          * <li>For an input <code>Locale</code> with a variant value consisting
          * of multiple subtags separated by underscore, generate candidate
          * <code>Locale</code>s by omitting the variant subtags one by one, then
-         * insert them after every occurence of <code> Locale</code>s with the
+         * insert them after every occurrence of <code> Locale</code>s with the
          * full variant value in the original list.  For example, if the
          * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
          *
          * <ul>
-         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
-         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
-         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
-         * <li> [<em>L</em>, <em>S</em>]
-         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
-         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
-         * <li> [<em>L</em>, <em>C</em>]
-         * <li> [<em>L</em>]
-         * <li> <code>Locale.ROOT</code>
-         * </ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
          *
          * <li>Special cases for Chinese.  When an input <code>Locale</code> has the
          * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
@@ -2209,21 +2288,21 @@
          * is empty, no script is supplied.  For example, for <code>Locale("zh", "CN")
          * </code>, the candidate list will be:
          * <ul>
-         * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
-         * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
-         * <li> [<em>L</em>("zh"), <em>C</em>("CN")]
-         * <li> [<em>L</em>("zh")]
-         * <li> <code>Locale.ROOT</code>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
          * </ul>
          *
          * For <code>Locale("zh", "TW")</code>, the candidate list will be:
          * <ul>
-         * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
-         * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
-         * <li> [<em>L</em>("zh"), <em>C</em>("TW")]
-         * <li> [<em>L</em>("zh")]
-         * <li> <code>Locale.ROOT</code>
-         * </ul>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
          *
          * <li>Special cases for Norwegian.  Both <code>Locale("no", "NO",
          * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
@@ -2231,10 +2310,10 @@
          * list is generated up to [<em>L</em>("nn")], and then the following
          * candidates are added:
          *
-         * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
-         * <li> [<em>L</em>("no"), <em>C</em>("NO")]
-         * <li> [<em>L</em>("no")]
-         * <li> <code>Locale.ROOT</code>
+         * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
          * </ul>
          *
          * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
@@ -2251,20 +2330,18 @@
          * candidate list:
          *
          * <ul>
-         * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
-         * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
-         * <li> [<em>L</em>("nb"), <em>C</em>("NO")]
-         * <li> [<em>L</em>("no"), <em>C</em>("NO")]
-         * <li> [<em>L</em>("nb")]
-         * <li> [<em>L</em>("no")]
-         * <li> <code>Locale.ROOT</code>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("nb")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
          * </ul>
          *
          * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
          * except that locales with "no" would appear before the corresponding
          * locales with "nb".</li>
-         *
-         * </li>
          * </ol>
          *
          * <p>The default implementation uses an {@link ArrayList} that
@@ -2284,9 +2361,9 @@
          * is returned. And if the resource bundles for the "ja" and
          * "" <code>Locale</code>s are found, then the runtime resource
          * lookup path (parent chain) is:
-         * <pre>
+         * <pre>{@code
          *     Messages_ja -> Messages
-         * </pre>
+         * }</pre>
          *
          * @param baseName
          *        the base name of the resource bundle, a fully
@@ -2353,18 +2430,27 @@
                     if (script.length() == 0 && region.length() > 0) {
                         // Supply script for users who want to use zh_Hans/zh_Hant
                         // as bundle names (recommended for Java7+)
-                        if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
+                        switch (region) {
+                        case "TW":
+                        case "HK":
+                        case "MO":
                             script = "Hant";
-                        } else if (region.equals("CN") || region.equals("SG")) {
+                            break;
+                        case "CN":
+                        case "SG":
                             script = "Hans";
+                            break;
                         }
                     } else if (script.length() > 0 && region.length() == 0) {
                         // Supply region(country) for users who still package Chinese
                         // bundles using old convension.
-                        if (script.equals("Hans")) {
+                        switch (script) {
+                        case "Hans":
                             region = "CN";
-                        } else if (script.equals("Hant")) {
+                            break;
+                        case "Hant":
                             region = "TW";
+                            break;
                         }
                     }
                 }
@@ -2565,6 +2651,7 @@
             ResourceBundle bundle = null;
             if (format.equals("java.class")) {
                 try {
+                    @SuppressWarnings("unchecked")
                     Class<? extends ResourceBundle> bundleClass
                         = (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
 
@@ -2579,7 +2666,10 @@
                 } catch (ClassNotFoundException e) {
                 }
             } else if (format.equals("java.properties")) {
-                final String resourceName = toResourceName(bundleName, "properties");
+                final String resourceName = toResourceName0(bundleName, "properties");
+                if (resourceName == null) {
+                    return bundle;
+                }
                 final ClassLoader classLoader = loader;
                 final boolean reloadFlag = reload;
                 InputStream stream = null;
@@ -2610,8 +2700,10 @@
                 }
                 if (stream != null) {
                     try {
+                        // Android-changed: Use UTF-8 for property based resources. b/26879578
                         bundle = new PropertyResourceBundle(
                                 new InputStreamReader(stream, StandardCharsets.UTF_8));
+                        // bundle = new PropertyResourceBundle(stream);
                     } finally {
                         stream.close();
                     }
@@ -2734,7 +2826,10 @@
             }
             boolean result = false;
             try {
-                String resourceName = toResourceName(toBundleName(baseName, locale), format);
+                String resourceName = toResourceName0(toBundleName(baseName, locale), format);
+                if (resourceName == null) {
+                    return result;
+                }
                 URL url = loader.getResource(resourceName);
                 if (url != null) {
                     long lastModified = 0;
@@ -2780,7 +2875,7 @@
          * and <code>variant</code> are the language, script, country, and variant
          * values of <code>locale</code>, respectively. Final component values that
          * are empty Strings are omitted along with the preceding '_'.  When the
-         * script is empty, the script value is ommitted along with the preceding '_'.
+         * script is empty, the script value is omitted along with the preceding '_'.
          * If all of the values are empty strings, then <code>baseName</code>
          * is returned.
          *
@@ -2868,6 +2963,15 @@
             sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
             return sb.toString();
         }
+
+        private String toResourceName0(String bundleName, String suffix) {
+            // application protocol check
+            if (bundleName.contains("://")) {
+                return null;
+            } else {
+                return toResourceName(bundleName, suffix);
+            }
+        }
     }
 
     private static class SingleFormatControl extends Control {
diff --git a/ojluni/src/main/java/java/util/ServiceLoader.java b/ojluni/src/main/java/java/util/ServiceLoader.java
index 4b3b029..8a0b3a8 100644
--- a/ojluni/src/main/java/java/util/ServiceLoader.java
+++ b/ojluni/src/main/java/java/util/ServiceLoader.java
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -66,12 +66,13 @@
  *
  * <p><a name="format"> A service provider is identified by placing a
  * <i>provider-configuration file</i> in the resource directory
- * <tt>META-INF/services</tt>.  The file's name is the fully-qualified <a
+ * <tt>META-INF/services</tt>.</a>  The file's name is the fully-qualified <a
  * href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
  * The file contains a list of fully-qualified binary names of concrete
  * provider classes, one per line.  Space and tab characters surrounding each
  * name, as well as blank lines, are ignored.  The comment character is
- * <tt>'#'</tt> (<tt>'&#92;u0023'</tt>, <font size="-1">NUMBER SIGN</font>); on
+ * <tt>'#'</tt> (<tt>'&#92;u0023'</tt>,
+ * <font style="font-size:smaller;">NUMBER SIGN</font>); on
  * each line all characters following the first comment character are ignored.
  * The file must be encoded in UTF-8.
  *
@@ -186,10 +187,14 @@
     private static final String PREFIX = "META-INF/services/";
 
     // The class or interface representing the service being loaded
-    private Class<S> service;
+    private final Class<S> service;
 
     // The class loader used to locate, load, and instantiate providers
-    private ClassLoader loader;
+    private final ClassLoader loader;
+
+    // The access control context taken when the ServiceLoader is created
+    // Android-changed: do not use legacy security code
+    // private final AccessControlContext acc;
 
     // Cached providers, in instantiation order
     private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
@@ -214,25 +219,28 @@
     }
 
     private ServiceLoader(Class<S> svc, ClassLoader cl) {
-        service = svc;
-        loader = cl;
+        service = Objects.requireNonNull(svc, "Service interface cannot be null");
+        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
+        // Android-changed: Do not use legacy security code (System.getSecurtiyManager()
+        // is always null).
+        // acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
         reload();
     }
 
-    private static void fail(Class service, String msg, Throwable cause)
+    private static void fail(Class<?> service, String msg, Throwable cause)
         throws ServiceConfigurationError
     {
         throw new ServiceConfigurationError(service.getName() + ": " + msg,
                                             cause);
     }
 
-    private static void fail(Class service, String msg)
+    private static void fail(Class<?> service, String msg)
         throws ServiceConfigurationError
     {
         throw new ServiceConfigurationError(service.getName() + ": " + msg);
     }
 
-    private static void fail(Class service, URL u, int line, String msg)
+    private static void fail(Class<?> service, URL u, int line, String msg)
         throws ServiceConfigurationError
     {
         fail(service, u + ":" + line + ": " + msg);
@@ -241,7 +249,7 @@
     // Parse a single line from the given configuration file, adding the name
     // on the line to the names list.
     //
-    private int parseLine(Class service, URL u, BufferedReader r, int lc,
+    private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
                           List<String> names)
         throws IOException, ServiceConfigurationError
     {
@@ -287,7 +295,7 @@
     //         If an I/O error occurs while reading from the given URL, or
     //         if a configuration-file format error is detected
     //
-    private Iterator<String> parse(Class service, URL u)
+    private Iterator<String> parse(Class<?> service, URL u)
         throws ServiceConfigurationError
     {
         InputStream in = null;
@@ -328,7 +336,7 @@
             this.loader = loader;
         }
 
-        public boolean hasNext() {
+        private boolean hasNextService() {
             if (nextName != null) {
                 return true;
             }
@@ -353,10 +361,9 @@
             return true;
         }
 
-        public S next() {
-            if (!hasNext()) {
+        private S nextService() {
+            if (!hasNextService())
                 throw new NoSuchElementException();
-            }
             String cn = nextName;
             nextName = null;
             Class<?> c = null;
@@ -364,13 +371,18 @@
                 c = Class.forName(cn, false, loader);
             } catch (ClassNotFoundException x) {
                 fail(service,
+                     // Android-changed: Let the ServiceConfigurationError have a cause.
                      "Provider " + cn + " not found", x);
+                     // "Provider " + cn + " not found");
             }
             if (!service.isAssignableFrom(c)) {
+                // Android-changed: Let the ServiceConfigurationError have a cause.
                 ClassCastException cce = new ClassCastException(
                         service.getCanonicalName() + " is not assignable from " + c.getCanonicalName());
                 fail(service,
                      "Provider " + cn  + " not a subtype", cce);
+                // fail(service,
+                //        "Provider " + cn  + " not a subtype");
             }
             try {
                 S p = service.cast(c.newInstance());
@@ -378,12 +390,40 @@
                 return p;
             } catch (Throwable x) {
                 fail(service,
-                     "Provider " + cn + " could not be instantiated: " + x,
+                     "Provider " + cn + " could not be instantiated",
                      x);
             }
             throw new Error();          // This cannot happen
         }
 
+        public boolean hasNext() {
+            // Android-changed: do not use legacy security code
+            /* if (acc == null) { */
+                return hasNextService();
+            /*
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+
+        public S next() {
+            // Android-changed: do not use legacy security code
+            /* if (acc == null) { */
+                return nextService();
+            /*
+            } else {
+                PrivilegedAction<S> action = new PrivilegedAction<S>() {
+                    public S run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+
         public void remove() {
             throw new UnsupportedOperationException();
         }
@@ -427,6 +467,12 @@
      * Invoking its {@link java.util.Iterator#remove() remove} method will
      * cause an {@link UnsupportedOperationException} to be thrown.
      *
+     * @implNote When adding providers to the cache, the {@link #iterator
+     * Iterator} processes resources in the order that the {@link
+     * java.lang.ClassLoader#getResources(java.lang.String)
+     * ClassLoader.getResources(String)} method finds the service configuration
+     * files.
+     *
      * @return  An iterator that lazily loads providers for this loader's
      *          service
      */
@@ -459,6 +505,8 @@
      * Creates a new service loader for the given service type and class
      * loader.
      *
+     * @param  <S> the class of the service type
+     *
      * @param  service
      *         The interface or abstract class representing the service
      *
@@ -492,6 +540,8 @@
      * ServiceLoader.load(<i>service</i>,
      *                    Thread.currentThread().getContextClassLoader())</pre></blockquote>
      *
+     * @param  <S> the class of the service type
+     *
      * @param  service
      *         The interface or abstract class representing the service
      *
@@ -521,6 +571,8 @@
      * have been installed into the current Java virtual machine; providers on
      * the application's class path will be ignored.
      *
+     * @param  <S> the class of the service type
+     *
      * @param  service
      *         The interface or abstract class representing the service
      *
@@ -536,6 +588,8 @@
         return ServiceLoader.load(service, prev);
     }
 
+    // Android-changed BEGIN: Add a method to instantiate a class from a system
+    // property (used in other parts of libcore).
     /**
      * Internal API to support built-in SPIs that check a system property first.
      * Returns an instance specified by a property with the class' binary name, or null if
@@ -554,6 +608,7 @@
             throw new Error(e);
         }
     }
+    // Android-changed END
 
     /**
      * Returns a string describing this service.
diff --git a/ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java b/ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java
new file mode 100644
index 0000000..e731f0f
--- /dev/null
+++ b/ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, 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.util.spi;
+
+import java.util.ResourceBundle;
+
+/**
+ * An interface for service providers that provide implementations of {@link
+ * java.util.ResourceBundle.Control}. The <a
+ * href="../ResourceBundle.html#default_behavior">default resource bundle loading
+ * behavior</a> of the {@code ResourceBundle.getBundle} factory methods that take
+ * no {@link java.util.ResourceBundle.Control} instance can be modified with {@code
+ * ResourceBundleControlProvider} implementations.
+ *
+ * <p>Provider implementations must be packaged using the <a
+ * href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/extensions/index.html">Java Extension
+ * Mechanism</a> as installed extensions. Refer to {@link java.util.ServiceLoader}
+ * for the extension packaging. Any installed {@code
+ * ResourceBundleControlProvider} implementations are loaded using {@link
+ * java.util.ServiceLoader} at the {@code ResourceBundle} class loading time.
+ *
+ * @author Masayoshi Okutsu
+ * @since 1.8
+ * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control)
+ *      ResourceBundle.getBundle
+ * @see java.util.ServiceLoader#loadInstalled(Class)
+ */
+public interface ResourceBundleControlProvider {
+    /**
+     * Returns a {@code ResourceBundle.Control} instance that is used
+     * to handle resource bundle loading for the given {@code
+     * baseName}. This method must return {@code null} if the given
+     * {@code baseName} isn't handled by this provider.
+     *
+     * @param baseName the base name of the resource bundle
+     * @return a {@code ResourceBundle.Control} instance,
+     *         or {@code null} if the given {@code baseName} is not
+     *         applicable to this provider.
+     * @throws NullPointerException if {@code baseName} is {@code null}
+     */
+    public ResourceBundle.Control getControl(String baseName);
+}
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index bf4126a..5818d65 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -1179,6 +1179,7 @@
     ojluni/src/main/java/java/util/spi/CurrencyNameProvider.java \
     ojluni/src/main/java/java/util/spi/LocaleNameProvider.java \
     ojluni/src/main/java/java/util/spi/LocaleServiceProvider.java \
+    ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java \
     ojluni/src/main/java/java/util/spi/TimeZoneNameProvider.java \
     ojluni/src/main/java/jdk/net/ExtendedSocketOptions.java \
     ojluni/src/main/java/jdk/net/NetworkPermission.java \