Providers: Eagerly initialize default providers.

Also change ProviderConfig to try loading providers on the boot
classpath before attempting the System class loader. This lets us
initialize things at compile time.

bug: 27805718

Change-Id: I4f33c752c0cb1e96f5b8c863fc32413cc8ec7fa0
diff --git a/ojluni/src/main/java/sun/security/jca/ProviderConfig.java b/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
index 62f8bdd..fc4ee76 100755
--- a/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
+++ b/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
@@ -208,58 +208,68 @@
                 if (debug != null) {
                     debug.println("Loading provider: " + ProviderConfig.this);
                 }
+
                 try {
-                    ClassLoader cl = ClassLoader.getSystemClassLoader();
-                    Class<?> provClass;
-                    if (cl != null) {
-                        provClass = cl.loadClass(className);
-                    } else {
-                        provClass = Class.forName(className);
-                    }
-                    Object obj;
-                    if (hasArgument() == false) {
-                        obj = provClass.newInstance();
-                    } else {
-                        Constructor<?> cons = provClass.getConstructor(CL_STRING);
-                        obj = cons.newInstance(argument);
-                    }
-                    if (obj instanceof Provider) {
-                        if (debug != null) {
-                            debug.println("Loaded provider " + obj);
+                    // First try with the boot classloader.
+                    return initProvider(className, Object.class.getClassLoader());
+                } catch (Exception e1) {
+                    // If that fails, try with the system classloader.
+                    try {
+                        return initProvider(className, ClassLoader.getSystemClassLoader());
+                    } catch (Exception e) {
+                        Throwable t;
+                        if (e instanceof InvocationTargetException) {
+                            t = ((InvocationTargetException)e).getCause();
+                        } else {
+                            t = e;
                         }
-                        return (Provider)obj;
-                    } else {
                         if (debug != null) {
-                            debug.println(className + " is not a provider");
+                            debug.println("Error loading provider " + ProviderConfig.this);
+                            t.printStackTrace();
                         }
-                        disableLoad();
+                        // provider indicates fatal error, pass through exception
+                        if (t instanceof ProviderException) {
+                            throw (ProviderException)t;
+                        }
+                        // provider indicates that loading should not be retried
+                        if (t instanceof UnsupportedOperationException) {
+                            disableLoad();
+                        }
                         return null;
                     }
-                } catch (Exception e) {
-                    Throwable t;
-                    if (e instanceof InvocationTargetException) {
-                        t = ((InvocationTargetException)e).getCause();
-                    } else {
-                        t = e;
-                    }
-                    if (debug != null) {
-                        debug.println("Error loading provider " + ProviderConfig.this);
-                        t.printStackTrace();
-                    }
-                    // provider indicates fatal error, pass through exception
-                    if (t instanceof ProviderException) {
-                        throw (ProviderException)t;
-                    }
-                    // provider indicates that loading should not be retried
-                    if (t instanceof UnsupportedOperationException) {
-                        disableLoad();
-                    }
-                    return null;
                 }
             }
         });
     }
 
+    private Provider initProvider(String className, ClassLoader cl) throws Exception {
+        Class<?> provClass;
+        if (cl != null) {
+            provClass = cl.loadClass(className);
+        } else {
+            provClass = Class.forName(className);
+        }
+        Object obj;
+        if (hasArgument() == false) {
+            obj = provClass.newInstance();
+        } else {
+            Constructor<?> cons = provClass.getConstructor(CL_STRING);
+            obj = cons.newInstance(argument);
+        }
+        if (obj instanceof Provider) {
+            if (debug != null) {
+                debug.println("Loaded provider " + obj);
+            }
+            return (Provider)obj;
+        } else {
+            if (debug != null) {
+                debug.println(className + " is not a provider");
+            }
+            disableLoad();
+            return null;
+        }
+    }
+
     /**
      * Perform property expansion of the provider value.
      *
diff --git a/ojluni/src/main/java/sun/security/jca/Providers.java b/ojluni/src/main/java/sun/security/jca/Providers.java
index d66d4f8..2212dc2 100755
--- a/ojluni/src/main/java/sun/security/jca/Providers.java
+++ b/ojluni/src/main/java/sun/security/jca/Providers.java
@@ -56,6 +56,15 @@
         // triggers a getInstance() call (although that should not happen)
         providerList = ProviderList.EMPTY;
         providerList = ProviderList.fromSecurityProperties();
+
+        // removeInvalid is specified to try initializing all configured providers
+        // and removing those that aren't instantiable. This has the side effect
+        // of eagerly initializing all providers.
+        final int numConfiguredProviders = providerList.size();
+        providerList = providerList.removeInvalid();
+        if (numConfiguredProviders != providerList.size()) {
+            throw new AssertionError("Unable to configure default providers");
+        }
     }
 
     private Providers() {