Merge "Create AppComponentFactory.instantiateClassLoader API"

This commit is contained in:
David Brazdil
2018-11-22 11:09:15 +00:00
committed by Gerrit Code Review
3 changed files with 65 additions and 18 deletions

View File

@@ -4200,8 +4200,10 @@ package android.app {
public class AppComponentFactory { public class AppComponentFactory {
ctor public 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.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 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.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.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; 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;

View File

@@ -20,6 +20,7 @@ import android.annotation.Nullable;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo;
/** /**
* Interface used to control the instantiation of manifest elements. * Interface used to control the instantiation of manifest elements.
@@ -32,6 +33,17 @@ import android.content.Intent;
*/ */
public class AppComponentFactory { 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 * 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 * perform things such as dependency injection or class loader changes to these
@@ -121,6 +133,19 @@ public class AppComponentFactory {
return (ContentProvider) cl.loadClass(className).newInstance(); 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 * @hide
*/ */

View File

@@ -117,6 +117,7 @@ public final class LoadedApk {
private File mCredentialProtectedDataDirFile; private File mCredentialProtectedDataDirFile;
@UnsupportedAppUsage @UnsupportedAppUsage
private final ClassLoader mBaseClassLoader; private final ClassLoader mBaseClassLoader;
private ClassLoader mDefaultClassLoader;
private final boolean mSecurityViolation; private final boolean mSecurityViolation;
private final boolean mIncludeCode; private final boolean mIncludeCode;
private final boolean mRegisterPackage; private final boolean mRegisterPackage;
@@ -224,9 +225,10 @@ public final class LoadedApk {
mSecurityViolation = false; mSecurityViolation = false;
mIncludeCode = true; mIncludeCode = true;
mRegisterPackage = false; mRegisterPackage = false;
mClassLoader = ClassLoader.getSystemClassLoader();
mResources = Resources.getSystem(); 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) { void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
assert info.packageName.equals("android"); assert info.packageName.equals("android");
mApplicationInfo = info; mApplicationInfo = info;
mClassLoader = classLoader; mDefaultClassLoader = classLoader;
mAppComponentFactory = createAppFactory(info, classLoader); mAppComponentFactory = createAppFactory(info, mDefaultClassLoader);
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
} }
private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) { private AppComponentFactory createAppFactory(ApplicationInfo appInfo, ClassLoader cl) {
if (appInfo.appComponentFactory != null && cl != null) { if (appInfo.appComponentFactory != null && cl != null) {
try { try {
return (AppComponentFactory) cl.loadClass(appInfo.appComponentFactory) AppComponentFactory factory = (AppComponentFactory) cl.loadClass(
.newInstance(); 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) { } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
Slog.e(TAG, "Unable to instantiate appComponentFactory", e); Slog.e(TAG, "Unable to instantiate appComponentFactory", e);
} }
@@ -357,7 +365,7 @@ public final class LoadedApk {
getClassLoader()); getClassLoader());
} }
} }
mAppComponentFactory = createAppFactory(aInfo, mClassLoader); mAppComponentFactory = createAppFactory(aInfo, mDefaultClassLoader);
} }
private void setApplicationInfo(ApplicationInfo aInfo) { private void setApplicationInfo(ApplicationInfo aInfo) {
@@ -633,11 +641,12 @@ public final class LoadedApk {
} }
if (mBaseClassLoader != null) { if (mBaseClassLoader != null) {
mClassLoader = mBaseClassLoader; mDefaultClassLoader = mBaseClassLoader;
} else { } else {
mClassLoader = ClassLoader.getSystemClassLoader(); mDefaultClassLoader = ClassLoader.getSystemClassLoader();
} }
mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader); mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
return; return;
} }
@@ -715,9 +724,9 @@ public final class LoadedApk {
// call System.loadLibrary() on a classloader from a LoadedApk with // call System.loadLibrary() on a classloader from a LoadedApk with
// mIncludeCode == false). // mIncludeCode == false).
if (!mIncludeCode) { if (!mIncludeCode) {
if (mClassLoader == null) { if (mDefaultClassLoader == null) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
mClassLoader = ApplicationLoaders.getDefault().getClassLoader( mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(
"" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp, "" /* codePath */, mApplicationInfo.targetSdkVersion, isBundledApp,
librarySearchPath, libraryPermittedPath, mBaseClassLoader, librarySearchPath, libraryPermittedPath, mBaseClassLoader,
null /* classLoaderName */); null /* classLoaderName */);
@@ -725,6 +734,10 @@ public final class LoadedApk {
mAppComponentFactory = AppComponentFactory.DEFAULT; mAppComponentFactory = AppComponentFactory.DEFAULT;
} }
if (mClassLoader == null) {
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader);
}
return; return;
} }
@@ -741,16 +754,16 @@ public final class LoadedApk {
", JNI path: " + librarySearchPath); ", JNI path: " + librarySearchPath);
boolean needToSetupJitProfiles = false; boolean needToSetupJitProfiles = false;
if (mClassLoader == null) { if (mDefaultClassLoader == null) {
// Temporarily disable logging of disk reads on the Looper thread // Temporarily disable logging of disk reads on the Looper thread
// as this is early and necessary. // as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader, libraryPermittedPath, mBaseClassLoader,
mApplicationInfo.classLoaderName); mApplicationInfo.classLoaderName);
mAppComponentFactory = createAppFactory(mApplicationInfo, mClassLoader); mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
StrictMode.setThreadPolicy(oldPolicy); StrictMode.setThreadPolicy(oldPolicy);
// Setup the class loader paths for profiling. // 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 // Temporarily disable logging of disk reads on the Looper thread as this is necessary
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try { try {
ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths); ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, libPaths);
} finally { } finally {
StrictMode.setThreadPolicy(oldPolicy); StrictMode.setThreadPolicy(oldPolicy);
} }
@@ -799,7 +812,7 @@ public final class LoadedApk {
if (!extraLibPaths.isEmpty()) { if (!extraLibPaths.isEmpty()) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try { try {
ApplicationLoaders.getDefault().addNative(mClassLoader, extraLibPaths); ApplicationLoaders.getDefault().addNative(mDefaultClassLoader, extraLibPaths);
} finally { } finally {
StrictMode.setThreadPolicy(oldPolicy); StrictMode.setThreadPolicy(oldPolicy);
} }
@@ -807,7 +820,7 @@ public final class LoadedApk {
if (addedPaths != null && addedPaths.size() > 0) { if (addedPaths != null && addedPaths.size() > 0) {
final String add = TextUtils.join(File.pathSeparator, addedPaths); 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. // Setup the new code paths for profiling.
needToSetupJitProfiles = true; needToSetupJitProfiles = true;
} }
@@ -824,6 +837,13 @@ public final class LoadedApk {
if (needToSetupJitProfiles && !ActivityThread.isSystem()) { if (needToSetupJitProfiles && !ActivityThread.isSystem()) {
setupJitProfileSupport(); 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 @UnsupportedAppUsage