Merge "Add API to allow apps more control over instantiation" into oc-dr1-dev

This commit is contained in:
TreeHugger Robot
2017-06-22 19:29:58 +00:00
committed by Android (Google) Code Review
2 changed files with 133 additions and 13 deletions

View File

@@ -2708,8 +2708,14 @@ public final class ActivityThread {
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
if (appContext.getApplicationContext() instanceof Application) {
activity = ((Application) appContext.getApplicationContext())
.instantiateActivity(cl, component.getClassName(), r.intent);
}
if (activity == null) {
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
}
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
@@ -3234,7 +3240,8 @@ public final class ActivityThread {
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
receiver = instantiate(cl, component, data.intent, app,
Application::instantiateReceiver);
} catch (Exception e) {
if (DEBUG_BROADCAST) Slog.i(TAG,
"Finishing failed broadcast to " + data.intent.getComponent());
@@ -3322,12 +3329,13 @@ public final class ActivityThread {
} else {
try {
if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
agent = (BackupAgent) cl.loadClass(classname).newInstance();
agent = instantiate(cl, classname, context,
Application::instantiateBackupAgent);
// set up the agent's context
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(agent);
agent.attach(context);
@@ -3387,9 +3395,12 @@ public final class ActivityThread {
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
Application app = null;
try {
app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
service = instantiate(cl, data.info.name, data.intent, app,
Application::instantiateService);
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
@@ -3404,7 +3415,6 @@ public final class ActivityThread {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
@@ -5721,8 +5731,8 @@ public final class ActivityThread {
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
mInstrumentation = instantiate(cl, data.instrumentationName.getClassName(),
instrContext, Application::instantiateInstrumentation);
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
@@ -6267,8 +6277,8 @@ public final class ActivityThread {
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
localProvider = instantiate(cl, info.name, context,
Application::instantiateProvider);
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
@@ -6467,6 +6477,38 @@ public final class ActivityThread {
}
}
private <T> T instantiate(ClassLoader cl, String className, Context c,
Instantiator<T> instantiator)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
if (c.getApplicationContext() instanceof Application) {
T a = instantiator.instantiate((Application) c.getApplicationContext(),
cl, className);
if (a != null) return a;
}
return (T) cl.loadClass(className).newInstance();
}
private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c,
IntentInstantiator<T> instantiator)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
if (c.getApplicationContext() instanceof Application) {
T a = instantiator.instantiate((Application) c.getApplicationContext(),
cl, className, intent);
if (a != null) return a;
}
return (T) cl.loadClass(className).newInstance();
}
private interface Instantiator<T> {
T instantiate(Application app, ClassLoader cl, String className)
throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
private interface IntentInstantiator<T> {
T instantiate(Application app, ClassLoader cl, String className, Intent intent)
throws ClassNotFoundException, IllegalAccessException, InstantiationException;
}
private static class EventLoggingReporter implements EventLogger.Reporter {
@Override
public void report (int code, Object... list) {

View File

@@ -16,17 +16,20 @@
package android.app;
import java.util.ArrayList;
import android.annotation.CallSuper;
import android.app.backup.BackupAgent;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
import android.content.ContentProvider;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import java.util.ArrayList;
/**
* Base class for maintaining global application state. You can provide your own
* implementation by creating a subclass and specifying the fully-qualified name
@@ -289,4 +292,79 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
}
}
}
/**
* Allows application to override the creation of activities. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes. Return null to use the default creation flow.
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
* @param intent Intent creating the class.
* @hide
*/
public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
return null;
}
/**
* Allows application to override the creation of receivers. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes. Return null to use the default creation flow.
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
* @param intent Intent creating the class.
* @hide
*/
public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) {
return null;
}
/**
* Allows application to override the creation of services. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes. Return null to use the default creation flow.
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
* @param intent Intent creating the class.
* @hide
*/
public Service instantiateService(ClassLoader cl, String className, Intent intent) {
return null;
}
/**
* Allows application to override the creation of providers. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes. Return null to use the default creation flow.
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
* @hide
*/
public ContentProvider instantiateProvider(ClassLoader cl, String className) {
return null;
}
/**
* Allows application to override the creation of backup agents. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes. Return null to use the default creation flow.
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
* @hide
*/
public BackupAgent instantiateBackupAgent(ClassLoader cl, String className) {
return null;
}
/**
* Allows application to override the creation of instrumentation. This can be used to
* perform things such as dependency injection or class loader changes to these
* classes. Return null to use the default creation flow.
* @param cl The default classloader to use for instantiation.
* @param className The class to be instantiated.
* @hide
*/
public Instrumentation instantiateInstrumentation(ClassLoader cl, String className) {
return null;
}
}