Chromium Code Reviews| Index: build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java |
| diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java |
| index 81e06a23d3ea5108a1b6ea09966a6f5e2c4045b4..815b7f9ae4c2816b77d99856b85e580f21e6b18a 100644 |
| --- a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java |
| +++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java |
| @@ -5,10 +5,13 @@ |
| package org.chromium.incrementalinstall; |
| import android.app.Application; |
| +import android.app.Instrumentation; |
| +import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.PackageManager.NameNotFoundException; |
| +import android.os.Bundle; |
| import android.util.Log; |
| import java.io.File; |
| @@ -26,9 +29,12 @@ public final class BootstrapApplication extends Application { |
| private static final String TAG = "cr.incrementalinstall"; |
| private static final String MANAGED_DIR_PREFIX = "/data/local/tmp/incremental-app-"; |
| private static final String REAL_APP_META_DATA_NAME = "incremental-install-real-app"; |
| + private static final String REAL_INSTRUMENTATION_META_DATA_NAME = |
| + "incremental-install-real-instrumentation"; |
| private ClassLoaderPatcher mClassLoaderPatcher; |
| private Application mRealApplication; |
| + private Instrumentation mRealInstrumentation; |
| private Object mStashedProviderList; |
| private Object mActivityThread; |
| @@ -65,10 +71,21 @@ public final class BootstrapApplication extends Application { |
| LockFile.clearInstallerLock(firstRunLockFile); |
| } |
| + Bundle metadata = getManifestMetadata(); |
| + if (Reflect.getField(mActivityThread, "mInstrumentationAppDir") != null) { |
| + initInstrumentation(metadata.getString(REAL_INSTRUMENTATION_META_DATA_NAME)); |
| + } else { |
| + Log.i(TAG, "No instrumentation active."); |
| + } |
| + |
| + // This allows us to detect the instrumentation.onCreate() call. |
| + Reflect.setField(mActivityThread, "mInstrumentation", |
| + new BootstrapInstrumentation(this)); |
| + |
| // attachBaseContext() is called from ActivityThread#handleBindApplication() and |
| // Application#mApplication is changed right after we return. Thus, we cannot swap |
| // the Application instances until onCreate() is called. |
| - String realApplicationName = getRealApplicationName(); |
| + String realApplicationName = metadata.getString(REAL_APP_META_DATA_NAME); |
| Log.i(TAG, "Instantiating " + realApplicationName); |
| mRealApplication = |
| (Application) Reflect.newInstance(Class.forName(realApplicationName)); |
| @@ -85,14 +102,52 @@ public final class BootstrapApplication extends Application { |
| } |
| } |
| + /** |
| + * Instantiates and initializes mRealInstrumentation (the real Instrumentation class). |
| + */ |
| + private void initInstrumentation(String realInstrumentationName) |
| + throws ReflectiveOperationException { |
| + Log.i(TAG, "Instantiating instrumentation " + realInstrumentationName); |
| + mRealInstrumentation = (Instrumentation) Reflect.newInstance( |
| + Class.forName(realInstrumentationName)); |
| + Instrumentation oldInstrumentation = |
| + (Instrumentation) Reflect.getField(mActivityThread, "mInstrumentation"); |
| + |
| + // Initialize the fields that are set by Instrumentation.init(). |
| + String[] initFields = {"mThread", "mMessageQueue", "mInstrContext", "mAppContext", |
| + "mWatcher", "mUiAutomationConnection"}; |
| + for (String fieldName : initFields) { |
| + Reflect.setField(mRealInstrumentation, fieldName, |
| + Reflect.getField(oldInstrumentation, fieldName)); |
| + } |
| + // But make sure the correct ComponentName is used. |
| + ComponentName newName = new ComponentName( |
| + oldInstrumentation.getComponentName().getPackageName(), realInstrumentationName); |
| + Reflect.setField(mRealInstrumentation, "mComponent", newName); |
| + } |
| + |
| + /** |
| + * Called by BootstrapInstrumentation from Instrumentation.onCreate(). |
| + */ |
| + void onInstrumentationCreate(Bundle arguments) { |
|
nyquist
2015/10/15 19:05:15
As a layman it sounds like this method will only b
agrieve
2015/10/15 19:20:48
Left the name (as I couldn't think of a better one
|
| + Log.i(TAG, "Instrumentation.onCreate() called. Swapping references."); |
| + try { |
| + swapApplicationReferences(); |
| + enableContentProviders(); |
| + if (mRealInstrumentation != null) { |
| + Reflect.setField(mActivityThread, "mInstrumentation", mRealInstrumentation); |
| + mRealInstrumentation.onCreate(arguments); |
| + } |
| + } catch (Exception e) { |
| + throw new RuntimeException("Incremental install failed.", e); |
| + } |
| + } |
| + |
| @Override |
| public void onCreate() { |
| super.onCreate(); |
| try { |
| - Log.i(TAG, "onCreate() called. Swapping Application references"); |
| - swapApplicationReferences(); |
| - enableContentProviders(); |
| - Log.i(TAG, "Calling onCreate"); |
| + Log.i(TAG, "Application.onCreate() called."); |
| mRealApplication.onCreate(); |
| } catch (Exception e) { |
| throw new RuntimeException("Incremental install failed.", e); |
| @@ -103,10 +158,10 @@ public final class BootstrapApplication extends Application { |
| * Returns the class name of the real Application class (recorded in the |
| * AndroidManifest.xml) |
| */ |
| - private String getRealApplicationName() throws NameNotFoundException { |
| + private Bundle getManifestMetadata() throws NameNotFoundException { |
| ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), |
| PackageManager.GET_META_DATA); |
| - return appInfo.metaData.getString(REAL_APP_META_DATA_NAME); |
| + return appInfo.metaData; |
| } |
| /** |