diff options
-rwxr-xr-x | api/current.txt | 2 | ||||
-rw-r--r-- | core/java/android/app/AppComponentFactory.java | 25 | ||||
-rw-r--r-- | core/java/android/app/LoadedApk.java | 56 |
3 files changed, 65 insertions, 18 deletions
diff --git a/api/current.txt b/api/current.txt index ea82498876b2..332dc8774cbf 100755 --- a/api/current.txt +++ b/api/current.txt @@ -4200,8 +4200,10 @@ package android.app { 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 cfaeec9096ed..ae632915dd2d 100644 --- a/core/java/android/app/AppComponentFactory.java +++ b/core/java/android/app/AppComponentFactory.java @@ -20,6 +20,7 @@ import android.annotation.Nullable; 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 @@ import android.content.Intent; 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 @@ public class AppComponentFactory { 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 b827d01314ce..da4f77baac41 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -117,6 +117,7 @@ public final class LoadedApk { 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 @@ public final class LoadedApk { 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 @@ public final class LoadedApk { 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 @@ public final class LoadedApk { getClassLoader()); } } - mAppComponentFactory = createAppFactory(aInfo, mClassLoader); + mAppComponentFactory = createAppFactory(aInfo, mDefaultClassLoader); } private void setApplicationInfo(ApplicationInfo aInfo) { @@ -633,11 +641,12 @@ public final class LoadedApk { } 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 @@ public final class LoadedApk { // 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 @@ public final class LoadedApk { mAppComponentFactory = AppComponentFactory.DEFAULT; } + if (mClassLoader == null) { + mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader); + } + return; } @@ -741,16 +754,16 @@ public final class LoadedApk { ", 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 @@ public final class LoadedApk { // 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 @@ public final class LoadedApk { 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 @@ public final class LoadedApk { 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 @@ public final class LoadedApk { 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 |