diff options
author | 2015-12-14 16:53:30 +0000 | |
---|---|---|
committer | 2015-12-15 12:00:24 +0000 | |
commit | 6c6c89239b74e3cf1c45c551d7eedd8d0e44f816 (patch) | |
tree | ebd54a3221d52fe30c0711af43832ad29366b5dd /src/tools/android/java/com/google/devtools/build/android/incrementaldeployment | |
parent | 3d9312e64a825c06f5e2e8883320089f1fa158ef (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.java | 67 |
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(); } |