Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(357)

Side by Side Diff: build/android/incremental_install/java/org/chromium/incrementalinstall/BootstrapApplication.java

Issue 1409603002: GN Incremental Install: Add support for running with instrumentation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.incrementalinstall; 5 package org.chromium.incrementalinstall;
6 6
7 import android.app.Application; 7 import android.app.Application;
8 import android.app.Instrumentation;
9 import android.content.ComponentName;
8 import android.content.Context; 10 import android.content.Context;
9 import android.content.pm.ApplicationInfo; 11 import android.content.pm.ApplicationInfo;
10 import android.content.pm.PackageManager; 12 import android.content.pm.PackageManager;
11 import android.content.pm.PackageManager.NameNotFoundException; 13 import android.content.pm.PackageManager.NameNotFoundException;
14 import android.os.Bundle;
12 import android.util.Log; 15 import android.util.Log;
13 16
14 import java.io.File; 17 import java.io.File;
15 import java.lang.ref.WeakReference; 18 import java.lang.ref.WeakReference;
16 import java.util.List; 19 import java.util.List;
17 import java.util.Map; 20 import java.util.Map;
18 21
19 /** 22 /**
20 * An Application that replaces itself with another Application (as defined in 23 * An Application that replaces itself with another Application (as defined in
21 * the "incremental-install-real-app" meta-data tag within the 24 * the "incremental-install-real-app" meta-data tag within the
22 * AndroidManifest.xml). It loads the other application only after side-loading 25 * AndroidManifest.xml). It loads the other application only after side-loading
23 * its .so and .dex files from /data/local/tmp. 26 * its .so and .dex files from /data/local/tmp.
24 */ 27 */
25 public final class BootstrapApplication extends Application { 28 public final class BootstrapApplication extends Application {
26 private static final String TAG = "cr.incrementalinstall"; 29 private static final String TAG = "cr.incrementalinstall";
27 private static final String MANAGED_DIR_PREFIX = "/data/local/tmp/incrementa l-app-"; 30 private static final String MANAGED_DIR_PREFIX = "/data/local/tmp/incrementa l-app-";
28 private static final String REAL_APP_META_DATA_NAME = "incremental-install-r eal-app"; 31 private static final String REAL_APP_META_DATA_NAME = "incremental-install-r eal-app";
32 private static final String REAL_INSTRUMENTATION_META_DATA_NAME =
33 "incremental-install-real-instrumentation";
29 34
30 private ClassLoaderPatcher mClassLoaderPatcher; 35 private ClassLoaderPatcher mClassLoaderPatcher;
31 private Application mRealApplication; 36 private Application mRealApplication;
37 private Instrumentation mRealInstrumentation;
32 private Object mStashedProviderList; 38 private Object mStashedProviderList;
33 private Object mActivityThread; 39 private Object mActivityThread;
34 40
35 @Override 41 @Override
36 protected void attachBaseContext(Context context) { 42 protected void attachBaseContext(Context context) {
37 super.attachBaseContext(context); 43 super.attachBaseContext(context);
38 File incrementalRootDir = new File(MANAGED_DIR_PREFIX + context.getPacka geName()); 44 File incrementalRootDir = new File(MANAGED_DIR_PREFIX + context.getPacka geName());
39 File libDir = new File(incrementalRootDir, "lib"); 45 File libDir = new File(incrementalRootDir, "lib");
40 File dexDir = new File(incrementalRootDir, "dex"); 46 File dexDir = new File(incrementalRootDir, "dex");
41 File installLockFile = new File(incrementalRootDir, "install.lock"); 47 File installLockFile = new File(incrementalRootDir, "install.lock");
(...skipping 16 matching lines...) Expand all
58 } 64 }
59 } 65 }
60 66
61 mClassLoaderPatcher.importNativeLibs(libDir); 67 mClassLoaderPatcher.importNativeLibs(libDir);
62 mClassLoaderPatcher.loadDexFiles(dexDir); 68 mClassLoaderPatcher.loadDexFiles(dexDir);
63 69
64 if (isFirstRun && mClassLoaderPatcher.mIsPrimaryProcess) { 70 if (isFirstRun && mClassLoaderPatcher.mIsPrimaryProcess) {
65 LockFile.clearInstallerLock(firstRunLockFile); 71 LockFile.clearInstallerLock(firstRunLockFile);
66 } 72 }
67 73
74 Bundle metadata = getManifestMetadata();
75 if (Reflect.getField(mActivityThread, "mInstrumentationAppDir") != n ull) {
76 initInstrumentation(metadata.getString(REAL_INSTRUMENTATION_META _DATA_NAME));
77 } else {
78 Log.i(TAG, "No instrumentation active.");
79 }
80
81 // This allows us to detect the instrumentation.onCreate() call.
82 Reflect.setField(mActivityThread, "mInstrumentation",
83 new BootstrapInstrumentation(this));
84
68 // attachBaseContext() is called from ActivityThread#handleBindAppli cation() and 85 // attachBaseContext() is called from ActivityThread#handleBindAppli cation() and
69 // Application#mApplication is changed right after we return. Thus, we cannot swap 86 // Application#mApplication is changed right after we return. Thus, we cannot swap
70 // the Application instances until onCreate() is called. 87 // the Application instances until onCreate() is called.
71 String realApplicationName = getRealApplicationName(); 88 String realApplicationName = metadata.getString(REAL_APP_META_DATA_N AME);
72 Log.i(TAG, "Instantiating " + realApplicationName); 89 Log.i(TAG, "Instantiating " + realApplicationName);
73 mRealApplication = 90 mRealApplication =
74 (Application) Reflect.newInstance(Class.forName(realApplicat ionName)); 91 (Application) Reflect.newInstance(Class.forName(realApplicat ionName));
75 Reflect.invokeMethod(mRealApplication, "attachBaseContext", context) ; 92 Reflect.invokeMethod(mRealApplication, "attachBaseContext", context) ;
76 93
77 // Between attachBaseContext() and onCreate(), ActivityThread tries to instantiate 94 // Between attachBaseContext() and onCreate(), ActivityThread tries to instantiate
78 // all ContentProviders. The ContentProviders break without the corr ect Application 95 // all ContentProviders. The ContentProviders break without the corr ect Application
79 // class being installed, so temporarily pretend there are no provid ers, and then 96 // class being installed, so temporarily pretend there are no provid ers, and then
80 // instantiate them explicitly within onCreate(). 97 // instantiate them explicitly within onCreate().
81 disableContentProviders(); 98 disableContentProviders();
82 Log.i(TAG, "Waiting for onCreate"); 99 Log.i(TAG, "Waiting for onCreate");
83 } catch (Exception e) { 100 } catch (Exception e) {
84 throw new RuntimeException("Incremental install failed.", e); 101 throw new RuntimeException("Incremental install failed.", e);
85 } 102 }
86 } 103 }
87 104
105 /**
106 * Instantiates and initializes mRealInstrumentation (the real Instrumentati on class).
107 */
108 private void initInstrumentation(String realInstrumentationName)
109 throws ReflectiveOperationException {
110 Log.i(TAG, "Instantiating instrumentation " + realInstrumentationName);
111 mRealInstrumentation = (Instrumentation) Reflect.newInstance(
112 Class.forName(realInstrumentationName));
113 Instrumentation oldInstrumentation =
114 (Instrumentation) Reflect.getField(mActivityThread, "mInstrument ation");
115
116 // Initialize the fields that are set by Instrumentation.init().
117 String[] initFields = {"mThread", "mMessageQueue", "mInstrContext", "mAp pContext",
118 "mWatcher", "mUiAutomationConnection"};
119 for (String fieldName : initFields) {
120 Reflect.setField(mRealInstrumentation, fieldName,
121 Reflect.getField(oldInstrumentation, fieldName));
122 }
123 // But make sure the correct ComponentName is used.
124 ComponentName newName = new ComponentName(
125 oldInstrumentation.getComponentName().getPackageName(), realInst rumentationName);
126 Reflect.setField(mRealInstrumentation, "mComponent", newName);
127 }
128
129 /**
130 * Called by BootstrapInstrumentation from Instrumentation.onCreate().
131 */
132 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
133 Log.i(TAG, "Instrumentation.onCreate() called. Swapping references.");
134 try {
135 swapApplicationReferences();
136 enableContentProviders();
137 if (mRealInstrumentation != null) {
138 Reflect.setField(mActivityThread, "mInstrumentation", mRealInstr umentation);
139 mRealInstrumentation.onCreate(arguments);
140 }
141 } catch (Exception e) {
142 throw new RuntimeException("Incremental install failed.", e);
143 }
144 }
145
88 @Override 146 @Override
89 public void onCreate() { 147 public void onCreate() {
90 super.onCreate(); 148 super.onCreate();
91 try { 149 try {
92 Log.i(TAG, "onCreate() called. Swapping Application references"); 150 Log.i(TAG, "Application.onCreate() called.");
93 swapApplicationReferences();
94 enableContentProviders();
95 Log.i(TAG, "Calling onCreate");
96 mRealApplication.onCreate(); 151 mRealApplication.onCreate();
97 } catch (Exception e) { 152 } catch (Exception e) {
98 throw new RuntimeException("Incremental install failed.", e); 153 throw new RuntimeException("Incremental install failed.", e);
99 } 154 }
100 } 155 }
101 156
102 /** 157 /**
103 * Returns the class name of the real Application class (recorded in the 158 * Returns the class name of the real Application class (recorded in the
104 * AndroidManifest.xml) 159 * AndroidManifest.xml)
105 */ 160 */
106 private String getRealApplicationName() throws NameNotFoundException { 161 private Bundle getManifestMetadata() throws NameNotFoundException {
107 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPack ageName(), 162 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPack ageName(),
108 PackageManager.GET_META_DATA); 163 PackageManager.GET_META_DATA);
109 return appInfo.metaData.getString(REAL_APP_META_DATA_NAME); 164 return appInfo.metaData;
110 } 165 }
111 166
112 /** 167 /**
113 * Nulls out ActivityThread.mBoundApplication.providers. 168 * Nulls out ActivityThread.mBoundApplication.providers.
114 */ 169 */
115 private void disableContentProviders() throws ReflectiveOperationException { 170 private void disableContentProviders() throws ReflectiveOperationException {
116 Object data = Reflect.getField(mActivityThread, "mBoundApplication"); 171 Object data = Reflect.getField(mActivityThread, "mBoundApplication");
117 mStashedProviderList = Reflect.getField(data, "providers"); 172 mStashedProviderList = Reflect.getField(data, "providers");
118 Reflect.setField(data, "providers", null); 173 Reflect.setField(data, "providers", null);
119 } 174 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 for (Map.Entry<String, WeakReference<?>> entry : packageMap.entrySet ()) { 213 for (Map.Entry<String, WeakReference<?>> entry : packageMap.entrySet ()) {
159 Object loadedApk = entry.getValue().get(); 214 Object loadedApk = entry.getValue().get();
160 if (loadedApk != null && Reflect.getField(loadedApk, "mApplicati on") == this) { 215 if (loadedApk != null && Reflect.getField(loadedApk, "mApplicati on") == this) {
161 Reflect.setField(loadedApk, "mApplication", mRealApplication ); 216 Reflect.setField(loadedApk, "mApplication", mRealApplication );
162 Reflect.setField(mRealApplication, "mLoadedApk", loadedApk); 217 Reflect.setField(mRealApplication, "mLoadedApk", loadedApk);
163 } 218 }
164 } 219 }
165 } 220 }
166 } 221 }
167 } 222 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698