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 7c9bcca2ca1757405196b7a48b5cb2075b9c7a8c..0a5f9fb914f2e4eb51c023625ef62a27e4ddc7bf 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 String getClassNameFromMetadata(String key, Context context) |
|
nyquist
2016/02/10 07:08:32
Nit: Could this be static now?
agrieve
2016/02/10 16:47:15
Done.
|
| + 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); |
| } |