Actually use ServiceLoader in places where we had a hard-coded equivalent.

I've also removed a file that was causing us to use this code unnecessarily
at run-time to explicitly specify the built-in default PreferencesFactory.

I haven't touched Charset, but should come back and fix that too at some
point.

Change-Id: I3a2145041d048078bdb55ae7b8fa4ec9d8726922
diff --git a/libcore/luni/src/main/java/java/util/ServiceLoader.java b/libcore/luni/src/main/java/java/util/ServiceLoader.java
index 2f28dff..335a1db 100644
--- a/libcore/luni/src/main/java/java/util/ServiceLoader.java
+++ b/libcore/luni/src/main/java/java/util/ServiceLoader.java
@@ -62,6 +62,8 @@
  * 
  * <p>Note that each iteration creates new instances of the various service implementations, so
  * any heavily-used code will likely want to cache the known implementations itself and reuse them.
+ * Note also that the candidate classes are instantiated lazily as you call {@code next} on the
+ * iterator: construction of the iterator itself does not instantiate any of the providers.
  * 
  * @param <S> the service class or interface
  * @since 1.6
@@ -106,13 +108,17 @@
     }
 
     /**
-     * Constructs a service loader.
+     * Constructs a service loader. If {@code classLoader} is null, the system class loader
+     * is used.
      * 
      * @param service the service class or interface
-     * @param loader the class loader
+     * @param classLoader the class loader
      * @return a new ServiceLoader
      */
     public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader classLoader) {
+        if (classLoader == null) {
+            classLoader = ClassLoader.getSystemClassLoader();
+        }
         return new ServiceLoader<S>(service, classLoader);
     }
 
@@ -120,16 +126,12 @@
         services.clear();
         try {
             String name = "META-INF/services/" + service.getName();
-            services.addAll(Collections.list(classLoader().getResources(name)));
+            services.addAll(Collections.list(classLoader.getResources(name)));
         } catch (IOException e) {
             return;
         }
     }
 
-    private ClassLoader classLoader() {
-        return (classLoader != null) ? classLoader : ClassLoader.getSystemClassLoader();
-    }
-
     /**
      * Constructs a service loader, using the current thread's context class loader.
      * 
@@ -156,6 +158,29 @@
         return ServiceLoader.load(service, cl);
     }
 
+    /**
+     * 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
+     * no such property is set.
+     * @hide
+     */
+    public static <S> S loadFromSystemProperty(final Class<S> service) {
+        return AccessController.doPrivileged(new PrivilegedAction<S>() {
+            public S run() {
+                try {
+                    final String className = System.getProperty(service.getName());
+                    if (className != null) {
+                        Class<?> c = ClassLoader.getSystemClassLoader().loadClass(className);
+                        return (S) c.newInstance();
+                    }
+                    return null;
+                } catch (Exception e) {
+                    throw new Error(e);
+                }
+            }
+        });
+    }
+
     @Override
     public String toString() {
         return "ServiceLoader for " + service.getName();
@@ -190,11 +215,7 @@
             }
             String className = queue.remove();
             try {
-                if (classLoader == null) {
-                    return service.cast(Class.forName(className).newInstance());
-                } else {
-                    return service.cast(classLoader.loadClass(className).newInstance());
-                }
+                return service.cast(classLoader.loadClass(className).newInstance());
             } catch (Exception e) {
                 throw new ServiceConfigurationError("Couldn't instantiate class " + className, e);
             }
diff --git a/libcore/nio/src/main/java/java/nio/channels/spi/SelectorProvider.java b/libcore/nio/src/main/java/java/nio/channels/spi/SelectorProvider.java
index 7692f2f..ab898af 100644
--- a/libcore/nio/src/main/java/java/nio/channels/spi/SelectorProvider.java
+++ b/libcore/nio/src/main/java/java/nio/channels/spi/SelectorProvider.java
@@ -17,10 +17,7 @@
 
 package java.nio.channels.spi;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
 import java.nio.channels.Channel;
 import java.nio.channels.DatagramChannel;
 import java.nio.channels.Pipe;
@@ -28,8 +25,7 @@
 import java.nio.channels.SocketChannel;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.Enumeration;
-
+import java.util.ServiceLoader;
 import org.apache.harmony.luni.platform.Platform;
 import org.apache.harmony.nio.internal.SelectorProviderImpl;
 
@@ -38,19 +34,12 @@
  * providing instances of {@link DatagramChannel}, {@link Pipe},
  * {@link java.nio.channels.Selector} , {@link ServerSocketChannel}, and
  * {@link SocketChannel}. All the methods of this class are thread-safe.
- * <p>
- * A provider instance can be retrieved through a system property or the
- * configuration file in a jar file; if no provide is available that way then
+ *
+ * <p>A provider instance can be retrieved through a system property or the
+ * configuration file in a jar file; if no provider is available that way then
  * the system default provider is returned.
  */
-public abstract class SelectorProvider extends Object {
-
-    private static final String SYMBOL_COMMENT = "#"; //$NON-NLS-1$
-
-    private static final String PROVIDER_IN_SYSTEM_PROPERTY = "java.nio.channels.spi.SelectorProvider"; //$NON-NLS-1$
-
-    private static final String PROVIDER_IN_JAR_RESOURCE = "META-INF/services/java.nio.channels.spi.SelectorProvider"; //$NON-NLS-1$
-
+public abstract class SelectorProvider {
     private static SelectorProvider provider = null;
 
     private static Channel inheritedChannel;
@@ -87,103 +76,29 @@
      * @return the provider.
      */
     synchronized public static SelectorProvider provider() {
-        if (null == provider) {
-            provider = loadProviderByProperty();
-            if (null == provider) {
+        if (provider == null) {
+            provider = ServiceLoader.loadFromSystemProperty(SelectorProvider.class);
+            if (provider == null) {
                 provider = loadProviderByJar();
             }
-            if (null == provider) {
-                provider = AccessController
-                        .doPrivileged(new PrivilegedAction<SelectorProvider>() {
-                            public SelectorProvider run() {
-                                return new SelectorProviderImpl();
-                            }
-                        });
+            if (provider == null) {
+                provider = AccessController.doPrivileged(new PrivilegedAction<SelectorProvider>() {
+                    public SelectorProvider run() {
+                        return new SelectorProviderImpl();
+                    }
+                });
             }
         }
         return provider;
     }
 
-    /*
-     * load the provider in the jar file of class path.
-     */
-    static SelectorProvider loadProviderByJar() {
-        Enumeration<URL> enumeration = null;
-
-        ClassLoader classLoader = AccessController
-                .doPrivileged(new PrivilegedAction<ClassLoader>() {
-                    public ClassLoader run() {
-                        return ClassLoader.getSystemClassLoader();
-                    }
-                });
-        try {
-            enumeration = classLoader.getResources(PROVIDER_IN_JAR_RESOURCE);
-        } catch (IOException e) {
-            throw new Error(e);
-        }
-        if (null == enumeration) {
-            return null;
-        }
-        // for every jar, read until we find the provider name.
-        while (enumeration.hasMoreElements()) {
-            BufferedReader br = null;
-            String className = null;
-            try {
-                br = new BufferedReader(
-                        new InputStreamReader(enumeration.nextElement().openStream()));
-            } catch (Exception e) {
-                continue;
-            }
-            try {
-                // only the first class is loaded ,as spec says, not the same as
-                // we do before.
-                while ((className = br.readLine()) != null) {
-                    className = className.trim();
-                    int siteComment = className.indexOf(SYMBOL_COMMENT);
-                    className = (-1 == siteComment) ? className : className
-                            .substring(0, siteComment);
-                    if (0 < className.length()) {
-                        return (SelectorProvider) classLoader.loadClass(
-                                className).newInstance();
-                    }
-                }
-            } catch (Exception e) {
-                throw new Error(e);
-            } finally {
-                try {
-                    br.close();
-                } catch (IOException ioe) {
-                    // Ignore
-                }
-            }
+    private static SelectorProvider loadProviderByJar() {
+        for (SelectorProvider provider : ServiceLoader.load(SelectorProvider.class, null)) {
+            return provider;
         }
         return null;
     }
 
-    /*
-     * Load by system property.
-     */
-    static SelectorProvider loadProviderByProperty() {
-        return AccessController
-                .doPrivileged(new PrivilegedAction<SelectorProvider>() {
-                    public SelectorProvider run() {
-                        try {
-                            final String className = System
-                                    .getProperty(PROVIDER_IN_SYSTEM_PROPERTY);
-                            if (null != className) {
-                                Class<?> spClass = ClassLoader
-                                        .getSystemClassLoader().loadClass(
-                                                className);
-                                return (SelectorProvider) spClass.newInstance();
-                            }
-                            return null;
-                        } catch (Exception e) {
-                            throw new Error(e);
-                        }
-                    }
-                });
-    }
-
     /**
      * Creates a new open {@code DatagramChannel}.
      * 
diff --git a/libcore/prefs/src/main/java/java/util/prefs/Preferences.java b/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
index b128858..e79d9eb 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
@@ -16,14 +16,6 @@
 
 package java.util.prefs;
 
-// BEGIN android-added
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.Enumeration;
-// END android-added
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -31,7 +23,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Locale;
-
+import java.util.ServiceLoader;
 import org.apache.harmony.prefs.internal.nls.Messages;
 
 /**
@@ -110,123 +102,24 @@
      */
     public static final int MAX_VALUE_LENGTH = 8192;
 
-    // BEGIN android-added
-    /**
-     * The name of the configuration file where preferences factory class names
-     * can be specified.
-     */
-    private static final String FACTORY_CONFIGURATION_FILE_NAME = "META-INF/services/java.util.prefs.PreferencesFactory"; //$NON-NLS-1$
-
-    /**
-     * The encoding of configuration files
-     */
-    private static final String CONFIGURATION_FILE_ENCODING = "UTF-8"; //$NON-NLS-1$
-
-    /**
-     * The comment string used in configuration files
-     */
-    private static final String CONFIGURATION_FILE_COMMENT = "#"; //$NON-NLS-1$
-
-    // END android-added
-
     //permission
-    private static final RuntimePermission PREFS_PERM = new RuntimePermission("preferences"); //$NON-NLS-1$
+    private static final RuntimePermission PREFS_PERM = new RuntimePermission("preferences");
 
     //factory used to get user/system prefs root
-    private static final PreferencesFactory factory;
+    private static final PreferencesFactory factory = findPreferencesFactory();
 
-    // BEGIN android-removed
-    // // default provider factory name for Windows
-    // private static final String DEFAULT_FACTORY_NAME_WIN = "java.util.prefs.RegistryPreferencesFactoryImpl"; //$NON-NLS-1$
-    //
-    // // default provider factory name for Unix
-    // private static final String DEFAULT_FACTORY_NAME_UNIX = "java.util.prefs.FilePreferencesFactoryImpl"; //$NON-NLS-1$
-    // END android-removed
-
-    static {
-        String factoryClassName = AccessController.doPrivileged(new PrivilegedAction<String>() {
-            public String run() {
-                return System.getProperty("java.util.prefs.PreferencesFactory"); //$NON-NLS-1$
-            }
-        });
-        // BEGIN android-removed
-        // // set default provider
-        // if (factoryClassName == null) {
-        //     String osName = AccessController.doPrivileged(new PrivilegedAction<String>() {
-        //         public String run() {
-        //             return System.getProperty("os.name"); //$NON-NLS-1$
-        //         }
-        //     });
-        //
-        //     // only comparing ASCII, so assume english locale
-        //     osName = (osName == null ? null : osName.toLowerCase(Locale.ENGLISH));
-        //
-        //     if (osName != null && osName.startsWith("windows")) {
-        //         factoryClassName = DEFAULT_FACTORY_NAME_WIN;
-        //     } else {
-        //         factoryClassName = DEFAULT_FACTORY_NAME_UNIX;
-        //     }
-        // }
-        // try {
-        //     ClassLoader loader = Thread.currentThread().getContextClassLoader();
-        //     if(loader == null){
-        //         loader = ClassLoader.getSystemClassLoader();
-        //     }
-        //     Class<?> factoryClass = loader.loadClass(factoryClassName);
-        //     factory = (PreferencesFactory) factoryClass.newInstance();
-        // } catch (Exception e) {
-        //     // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
-        //     throw new InternalError(Messages.getString("prefs.10", factoryClassName, e));   //$NON-NLS-1$
-        // }
-        // BEGIN android-added
-        ClassLoader loader = Thread.currentThread().getContextClassLoader();
-        if (loader == null) {
-            loader = ClassLoader.getSystemClassLoader();
+    private static PreferencesFactory findPreferencesFactory() {
+        // Try the system property first...
+        PreferencesFactory result = ServiceLoader.loadFromSystemProperty(PreferencesFactory.class);
+        if (result != null) {
+            return result;
         }
-        if (factoryClassName == null) {
-            Enumeration<URL> en = null;
-            try {
-                en = loader.getResources(FACTORY_CONFIGURATION_FILE_NAME);
-                BufferedReader reader = null;
-                int commentIndex = 0;
-                while (en.hasMoreElements()) {
-                    try {
-                        InputStream is = en.nextElement().openStream();
-                        // Read each line for charset provider class names
-                        reader = new BufferedReader(new InputStreamReader(is,
-                                CONFIGURATION_FILE_ENCODING));
-                        factoryClassName = reader.readLine();
-                        commentIndex = factoryClassName.indexOf(CONFIGURATION_FILE_COMMENT);
-                        if (commentIndex > 0) {
-                            factoryClassName = factoryClassName.substring(0, commentIndex).trim();
-                        }
-                        if (factoryClassName.length() > 0) {
-                            break;
-                        }
-                    } catch (IOException ex) {
-                        // ignore if a resource couldn't be read
-                    }
-                }
-            } catch (Exception e) {
-                // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by
-                // {1}
-                throw new InternalError(Messages.getString("prefs.10",
-                        FACTORY_CONFIGURATION_FILE_NAME, e)); //$NON-NLS-1$
-            }
+        // Then use ServiceLoader for META-INF/services/...
+        for (PreferencesFactory impl : ServiceLoader.load(PreferencesFactory.class, null)) {
+            return impl;
         }
-
-        if (factoryClassName == null) {
-            factoryClassName = "java.util.prefs.FilePreferencesFactoryImpl";
-        }
-
-        try {
-            Class<?> c = loader.loadClass(factoryClassName);
-            factory = (PreferencesFactory)c.newInstance();
-        } catch (Exception e) {
-            // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
-            throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$
-        }
-        // END android-added
+        // Finally return a default...
+        return new FilePreferencesFactoryImpl();
     }
 
     /**
diff --git a/libcore/prefs/src/main/resources/META-INF/services/java.util.prefs.PreferencesFactory b/libcore/prefs/src/main/resources/META-INF/services/java.util.prefs.PreferencesFactory
deleted file mode 100644
index ebb514c..0000000
--- a/libcore/prefs/src/main/resources/META-INF/services/java.util.prefs.PreferencesFactory
+++ /dev/null
@@ -1 +0,0 @@
-java.util.prefs.FilePreferencesFactoryImpl