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 7c9bcca2ca1757405196b7a48b5cb2075b9c7a8c..1fb5e40b83b813aea7bae8ed88c3fc2d6f4049d3 100644 |
--- a/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java |
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java |
@@ -37,6 +37,7 @@ public final class BootstrapApplication extends Application { |
private ClassLoaderPatcher mClassLoaderPatcher; |
private Application mRealApplication; |
+ private Instrumentation mOrigInstrumentation; |
private Instrumentation mRealInstrumentation; |
private Object mStashedProviderList; |
private Object mActivityThread; |
@@ -44,41 +45,76 @@ public final class BootstrapApplication extends Application { |
@Override |
protected void attachBaseContext(Context context) { |
super.attachBaseContext(context); |
- File incrementalRootDir = new File(MANAGED_DIR_PREFIX + context.getPackageName()); |
- File libDir = new File(incrementalRootDir, "lib"); |
- File dexDir = new File(incrementalRootDir, "dex"); |
- File installLockFile = new File(incrementalRootDir, "install.lock"); |
- File firstRunLockFile = new File(incrementalRootDir, "firstrun.lock"); |
- |
try { |
mActivityThread = Reflect.invokeMethod(Class.forName("android.app.ActivityThread"), |
"currentActivityThread"); |
mClassLoaderPatcher = new ClassLoaderPatcher(context); |
- boolean isFirstRun = LockFile.installerLockExists(firstRunLockFile); |
+ mOrigInstrumentation = |
+ (Instrumentation) Reflect.getField(mActivityThread, "mInstrumentation"); |
+ Context instContext = mOrigInstrumentation.getContext(); |
+ if (instContext == null) { |
+ instContext = context; |
+ } |
+ |
+ // When running with an instrumentation that lives in a different package from the |
+ // application, we must load the dex files and native libraries from both pacakges. |
+ // This logic likely won't work when the instrumentation is incremental, but the app is |
+ // non-incremental. This configuration isn't used right now though. |
+ String appPackageName = getPackageName(); |
+ String instPackageName = instContext.getPackageName(); |
+ boolean instPackageNameDiffers = !appPackageName.equals(instPackageName); |
+ Log.i(TAG, "App PackageName: " + appPackageName); |
+ if (instPackageNameDiffers) { |
+ Log.i(TAG, "Inst PackageName: " + instPackageName); |
+ } |
+ |
+ File appIncrementalRootDir = new File(MANAGED_DIR_PREFIX + appPackageName); |
+ File appLibDir = new File(appIncrementalRootDir, "lib"); |
+ File appDexDir = new File(appIncrementalRootDir, "dex"); |
+ File appInstallLockFile = new File(appIncrementalRootDir, "install.lock"); |
+ File appFirstRunLockFile = new File(appIncrementalRootDir, "firstrun.lock"); |
+ File instIncrementalRootDir = new File(MANAGED_DIR_PREFIX + instPackageName); |
+ File instLibDir = new File(instIncrementalRootDir, "lib"); |
+ File instDexDir = new File(instIncrementalRootDir, "dex"); |
+ File instInstallLockFile = new File(instIncrementalRootDir, "install.lock"); |
+ File instFirstRunLockFile = new File(instIncrementalRootDir , "firstrun.lock"); |
+ |
+ boolean isFirstRun = LockFile.installerLockExists(appFirstRunLockFile) |
+ || (instPackageNameDiffers |
+ && LockFile.installerLockExists(instFirstRunLockFile)); |
if (isFirstRun) { |
if (mClassLoaderPatcher.mIsPrimaryProcess) { |
// Wait for incremental_install.py to finish. |
- LockFile.waitForInstallerLock(installLockFile, 30 * 1000); |
+ LockFile.waitForInstallerLock(appInstallLockFile, 30 * 1000); |
+ LockFile.waitForInstallerLock(instInstallLockFile, 30 * 1000); |
} else { |
// Wait for the browser process to create the optimized dex files |
// and copy the library files. |
- LockFile.waitForInstallerLock(firstRunLockFile, 60 * 1000); |
+ LockFile.waitForInstallerLock(appFirstRunLockFile, 60 * 1000); |
+ LockFile.waitForInstallerLock(instFirstRunLockFile, 60 * 1000); |
} |
} |
- mClassLoaderPatcher.importNativeLibs(libDir); |
- mClassLoaderPatcher.loadDexFiles(dexDir); |
+ mClassLoaderPatcher.importNativeLibs(instLibDir); |
+ mClassLoaderPatcher.loadDexFiles(instDexDir); |
+ if (instPackageNameDiffers) { |
+ mClassLoaderPatcher.importNativeLibs(appLibDir); |
+ mClassLoaderPatcher.loadDexFiles(appDexDir); |
+ } |
if (isFirstRun && mClassLoaderPatcher.mIsPrimaryProcess) { |
- LockFile.clearInstallerLock(firstRunLockFile); |
+ LockFile.clearInstallerLock(appFirstRunLockFile); |
+ if (instPackageNameDiffers) { |
+ LockFile.clearInstallerLock(instFirstRunLockFile); |
+ } |
} |
// mInstrumentationAppDir is one of a set of fields that is initialized only when |
// instrumentation is active. |
if (Reflect.getField(mActivityThread, "mInstrumentationAppDir") != null) { |
String realInstrumentationName = |
- getClassNameFromMetadata(REAL_INSTRUMENTATION_META_DATA_NAME); |
+ getClassNameFromMetadata(REAL_INSTRUMENTATION_META_DATA_NAME, instContext); |
initInstrumentation(realInstrumentationName); |
} else { |
Log.i(TAG, "No instrumentation active."); |
@@ -93,7 +129,7 @@ public final class BootstrapApplication extends Application { |
// 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 = getClassNameFromMetadata(REAL_APP_META_DATA_NAME); |
+ String realApplicationName = getClassNameFromMetadata(REAL_APP_META_DATA_NAME, context); |
Log.i(TAG, "Instantiating " + realApplicationName); |
mRealApplication = |
(Application) Reflect.newInstance(Class.forName(realApplicationName)); |
@@ -114,12 +150,14 @@ public final class BootstrapApplication extends Application { |
* Returns the fully-qualified class name for the given key, stored in a |
* <meta> witin the manifest. |
*/ |
- private String getClassNameFromMetadata(String key) throws NameNotFoundException { |
- ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), |
+ private static String getClassNameFromMetadata(String key, Context context) |
+ throws NameNotFoundException { |
+ String pkgName = context.getPackageName(); |
+ ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(pkgName, |
PackageManager.GET_META_DATA); |
String value = appInfo.metaData.getString(key); |
if (value != null && !value.contains(".")) { |
- value = getPackageName() + "." + value; |
+ value = pkgName + "." + value; |
} |
return value; |
} |
@@ -129,14 +167,12 @@ public final class BootstrapApplication extends Application { |
*/ |
private void initInstrumentation(String realInstrumentationName) |
throws ReflectiveOperationException { |
- Instrumentation oldInstrumentation = |
- (Instrumentation) Reflect.getField(mActivityThread, "mInstrumentation"); |
if (realInstrumentationName == null) { |
// This is the case when an incremental app is used as a target for an instrumentation |
// test. In this case, ActivityThread can instantiate the proper class just fine since |
// it exists within the test apk (as opposed to the incremental apk-under-test). |
Log.i(TAG, "Running with external instrumentation"); |
- mRealInstrumentation = oldInstrumentation; |
+ mRealInstrumentation = mOrigInstrumentation; |
return; |
} |
// For unit tests, the instrumentation class is replaced in the manifest by a build step |
@@ -151,11 +187,11 @@ public final class BootstrapApplication extends Application { |
"mWatcher", "mUiAutomationConnection"}; |
for (String fieldName : initFields) { |
Reflect.setField(mRealInstrumentation, fieldName, |
- Reflect.getField(oldInstrumentation, fieldName)); |
+ Reflect.getField(mOrigInstrumentation, fieldName)); |
} |
// But make sure the correct ComponentName is used. |
ComponentName newName = new ComponentName( |
- oldInstrumentation.getComponentName().getPackageName(), realInstrumentationName); |
+ mOrigInstrumentation.getComponentName().getPackageName(), realInstrumentationName); |
Reflect.setField(mRealInstrumentation, "mComponent", newName); |
} |