Merge "Create AppComponentFactory.instantiateClassLoader API"
diff --git a/api/current.txt b/api/current.txt
index b192d7f..56433f3 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -4226,8 +4226,10 @@
 
   public class AppComponentFactory {
     ctor public AppComponentFactory();
+    method public android.content.pm.ApplicationInfo getApplicationInfo();
     method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
     method public android.app.Application instantiateApplication(java.lang.ClassLoader, java.lang.String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public java.lang.ClassLoader instantiateClassLoader(java.lang.ClassLoader);
     method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
     method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
     method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
diff --git a/core/java/android/app/AppComponentFactory.java b/core/java/android/app/AppComponentFactory.java
index cfaeec9..ae63291 100644
--- a/core/java/android/app/AppComponentFactory.java
+++ b/core/java/android/app/AppComponentFactory.java
@@ -20,6 +20,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 
 /**
  * Interface used to control the instantiation of manifest elements.
@@ -33,6 +34,17 @@
 public class AppComponentFactory {
 
     /**
+     * Allows application to override the creation of the default class loader.
+     * This can be used to perform things such as dependency injection or setting up
+     * a custom class loader hierarchy.
+     *
+     * @param cl        The default classloader instantiated by platform.
+     */
+    public @NonNull ClassLoader instantiateClassLoader(@NonNull ClassLoader cl) {
+        return cl;
+    }
+
+    /**
      * Allows application to override the creation of the application object. This can be used to
      * perform things such as dependency injection or class loader changes to these
      * classes.
@@ -121,6 +133,19 @@
         return (ContentProvider) cl.loadClass(className).newInstance();
     }
 
+    private ApplicationInfo mApplicationInfo = null;
+
+    void setApplicationInfo(ApplicationInfo info) {
+        mApplicationInfo = info;
+    }
+
+    /**
+     * Returns the ApplicationInfo associated with this package.
+     */
+    public ApplicationInfo getApplicationInfo() {
+        return mApplicationInfo;
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b827d01..da4f77b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -117,6 +117,7 @@
     private File mCredentialProtectedDataDirFile;
     @UnsupportedAppUsage
     private final ClassLoader mBaseClassLoader;
+    private ClassLoader mDefaultClassLoader;
     private final boolean mSecurityViolation;
     private final boolean mIncludeCode;
     private final boolean mRegisterPackage;
@@ -224,9 +225,10 @@
         mSecurityViolation = false;
         mIncludeCode = true;
         mRegisterPackage = false;
-        mClassLoader = ClassLoader.getSystemClassLoader();
         mResources = Resources.getSystem();
-        mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
+        mDefaultClassLoader = ClassLoader.getSystemClassLoader();
+        mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
+        mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
     }
 
     /**
@@ -235,15 +237,21 @@
     void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
         assert info.packageName.equals("android");
         mApplicationInfo = info;
-        mClassLoader = classLoader;
-        mAppComponentFactory = createAppFactory(info, classLoader);
+        mDefaultClassLoader = classLoader;
+        mAppComponentFactory = createAppFactory(info, mDefaultClassLoader);
+        mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
     }
 
     private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) {
         if (appInfo.appComponentFactory != null && cl != null) {
             try {
-                return (AppComponentFactory) cl.loadClass(appInfo.appComponentFactory)
-                        .newInstance();
+                AppComponentFactory factory = (AppComponentFactory) cl.loadClass(
+                        appInfo.appComponentFactory).newInstance();
+                // Pass a copy of ApplicationInfo to the factory. Copying protects the framework
+                // from apps which would override the factory and change ApplicationInfo contents.
+                // ApplicationInfo is used to set up the default class loader.
+                factory.setApplicationInfo(new ApplicationInfo(appInfo));
+                return factory;
             } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
                 Slog.e(TAG, "Unable to instantiate appComponentFactory", e);
             }
@@ -357,7 +365,7 @@
                         getClassLoader());
             }
         }
-        mAppComponentFactory = createAppFactory(aInfo, mClassLoader);
+        mAppComponentFactory = createAppFactory(aInfo, mDefaultClassLoader);
     }
 
     private void setApplicationInfo(ApplicationInfo aInfo) {
@@ -633,11 +641,12 @@
             }
 
             if (mBaseClassLoader != null) {
-                mClassLoader = mBaseClassLoader;
+                mDefaultClassLoader = mBaseClassLoader;
             } else {
-                mClassLoader = ClassLoader.getSystemClassLoader();
+                mDefaultClassLoader = ClassLoader.getSystemClassLoader();
             }
-            mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
+            mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
+            mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
 
             return;
         }
@@ -715,9 +724,9 @@
         // call System.loadLibrary() on a classloader from a LoadedApk with
         // mIncludeCode == false).
         if (!mIncludeCode) {
-            if (mClassLoader == null) {
+            if (mDefaultClassLoader == null) {
                 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-                mClassLoader = ApplicationLoaders.getDefault().getClassLoader(
+                mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(
                         "" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp,
                         librarySearchPath, libraryPermittedPath, mBaseClassLoader,
                         null /* classLoaderName */);
@@ -725,6 +734,10 @@
                 mAppComponentFactory = AppComponentFactory.DEFAULT;
             }
 
+            if (mClassLoader == null) {
+                mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
+            }
+
             return;
         }
 
@@ -741,16 +754,16 @@
                     ", JNI path: " + librarySearchPath);
 
         boolean needToSetupJitProfiles = false;
-        if (mClassLoader == null) {
+        if (mDefaultClassLoader == null) {
             // Temporarily disable logging of disk reads on the Looper thread
             // as this is early and necessary.
             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
 
-            mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
+            mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
                     mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
                     libraryPermittedPath, mBaseClassLoader,
                     mApplicationInfo.classLoaderName);
-            mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader);
+            mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
 
             StrictMode.setThreadPolicy(oldPolicy);
             // Setup the class loader paths for profiling.
@@ -761,7 +774,7 @@
             // Temporarily disable logging of disk reads on the Looper thread as this is necessary
             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
             try {
-                ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths);
+                ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, libPaths);
             } finally {
                 StrictMode.setThreadPolicy(oldPolicy);
             }
@@ -799,7 +812,7 @@
         if (!extraLibPaths.isEmpty()) {
             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
             try {
-                ApplicationLoaders.getDefault().addNative(mClassLoader, extraLibPaths);
+                ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, extraLibPaths);
             } finally {
                 StrictMode.setThreadPolicy(oldPolicy);
             }
@@ -807,7 +820,7 @@
 
         if (addedPaths != null && addedPaths.size() > 0) {
             final String add = TextUtils.join(File.pathSeparator, addedPaths);
-            ApplicationLoaders.getDefault().addPath(mClassLoader, add);
+            ApplicationLoaders.getDefault().addPath(mDefaultClassLoader, add);
             // Setup the new code paths for profiling.
             needToSetupJitProfiles = true;
         }
@@ -824,6 +837,13 @@
         if (needToSetupJitProfiles && !ActivityThread.isSystem()) {
             setupJitProfileSupport();
         }
+
+        // Call AppComponentFactory to select/create the main class loader of this app.
+        // Since this may call code in the app, mDefaultClassLoader must be fully set up
+        // before invoking the factory.
+        if (mClassLoader == null) {
+            mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
+        }
     }
 
     @UnsupportedAppUsage