aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/incrementaldeployment
diff options
context:
space:
mode:
authorGravatar Lukacs Berki <lberki@google.com>2015-12-14 16:53:30 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2015-12-15 12:00:24 +0000
commit6c6c89239b74e3cf1c45c551d7eedd8d0e44f816 (patch)
treeebd54a3221d52fe30c0711af43832ad29366b5dd /src/tools/android/java/com/google/devtools/build/android/incrementaldeployment
parent3d9312e64a825c06f5e2e8883320089f1fa158ef (diff)
Make the stub application instantiate content providers with the right Application class.
-- MOS_MIGRATED_REVID=110158926
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/incrementaldeployment')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/incrementaldeployment/StubApplication.java67
1 files changed, 66 insertions, 1 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/incrementaldeployment/StubApplication.java b/src/tools/android/java/com/google/devtools/build/android/incrementaldeployment/StubApplication.java
index d7af594271..a0498c2484 100644
--- a/src/tools/android/java/com/google/devtools/build/android/incrementaldeployment/StubApplication.java
+++ b/src/tools/android/java/com/google/devtools/build/android/incrementaldeployment/StubApplication.java
@@ -76,6 +76,8 @@ public class StubApplication extends Application {
private String externalResourceFile;
private Application realApplication;
+ private Object stashedContentProviders;
+
public StubApplication() {
String[] stubApplicationData = getResourceAsString("stub_application_data.txt").split("\n");
realClassName = stubApplicationData[0];
@@ -453,6 +455,68 @@ public class StubApplication extends Application {
}
}
+ private static Field getField(Object instance, String fieldName)
+ throws ClassNotFoundException {
+ for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return field;
+ } catch (NoSuchFieldException e) {
+ // IllegalStateException will be thrown below
+ }
+ }
+
+ throw new IllegalStateException("Field '" + fieldName + "' not found");
+ }
+
+ private void enableContentProviders() {
+ Log.v("INCREMENTAL", "enableContentProviders");
+ try {
+ Class<?> activityThread = Class.forName("android.app.ActivityThread");
+ Method mCurrentActivityThread = activityThread.getMethod("currentActivityThread");
+ mCurrentActivityThread.setAccessible(true);
+ Object currentActivityThread = mCurrentActivityThread.invoke(null);
+ Object boundApplication = getField(
+ currentActivityThread, "mBoundApplication").get(currentActivityThread);
+ getField(boundApplication, "providers").set(boundApplication, stashedContentProviders);
+ if (stashedContentProviders != null) {
+ Method mInstallContentProviders = activityThread.getDeclaredMethod(
+ "installContentProviders", Context.class, List.class);
+ mInstallContentProviders.setAccessible(true);
+ mInstallContentProviders.invoke(
+ currentActivityThread, realApplication, stashedContentProviders);
+ stashedContentProviders = null;
+ }
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
+ | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ // ActivityThread instantiates all the content providers between attachBaseContext() and
+ // onCreate(). Since we replace the Application instance in onCreate(), this may fail if
+ // they depend on the correct Application being present, so we postpone instantiating the
+ // content providers until we have the real Application instance.
+ private void disableContentProviders() {
+ Log.v("INCREMENTAL", "disableContentProviders");
+ try {
+ Class<?> activityThread = Class.forName("android.app.ActivityThread");
+ Method mCurrentActivityThread = activityThread.getMethod("currentActivityThread");
+ mCurrentActivityThread.setAccessible(true);
+ Object currentActivityThread = mCurrentActivityThread.invoke(null);
+ Object boundApplication = getField(
+ currentActivityThread, "mBoundApplication").get(currentActivityThread);
+ Field fProviders = getField(boundApplication, "providers");
+
+ stashedContentProviders = fProviders.get(boundApplication);
+ fProviders.set(boundApplication, null);
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
+ | InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
@Override
protected void attachBaseContext(Context context) {
instantiateRealApplication(
@@ -469,7 +533,7 @@ public class StubApplication extends Application {
ContextWrapper.class.getDeclaredMethod("attachBaseContext", Context.class);
attachBaseContext.setAccessible(true);
attachBaseContext.invoke(realApplication, context);
-
+ disableContentProviders();
} catch (Exception e) {
throw new IllegalStateException(e);
}
@@ -479,6 +543,7 @@ public class StubApplication extends Application {
public void onCreate() {
monkeyPatchApplication();
monkeyPatchExistingResources();
+ enableContentProviders();
super.onCreate();
realApplication.onCreate();
}