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; |
} |
/** |