OLD | NEW |
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; | 8 import android.app.Instrumentation; |
9 import android.content.ComponentName; | 9 import android.content.ComponentName; |
10 import android.content.Context; | 10 import android.content.Context; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 } | 67 } |
68 } | 68 } |
69 | 69 |
70 mClassLoaderPatcher.importNativeLibs(libDir); | 70 mClassLoaderPatcher.importNativeLibs(libDir); |
71 mClassLoaderPatcher.loadDexFiles(dexDir); | 71 mClassLoaderPatcher.loadDexFiles(dexDir); |
72 | 72 |
73 if (isFirstRun && mClassLoaderPatcher.mIsPrimaryProcess) { | 73 if (isFirstRun && mClassLoaderPatcher.mIsPrimaryProcess) { |
74 LockFile.clearInstallerLock(firstRunLockFile); | 74 LockFile.clearInstallerLock(firstRunLockFile); |
75 } | 75 } |
76 | 76 |
77 Bundle metadata = getManifestMetadata(); | |
78 // mInstrumentationAppDir is one of a set of fields that is initiali
zed only when | 77 // mInstrumentationAppDir is one of a set of fields that is initiali
zed only when |
79 // instrumentation is active. | 78 // instrumentation is active. |
80 if (Reflect.getField(mActivityThread, "mInstrumentationAppDir") != n
ull) { | 79 if (Reflect.getField(mActivityThread, "mInstrumentationAppDir") != n
ull) { |
81 initInstrumentation(metadata.getString(REAL_INSTRUMENTATION_META
_DATA_NAME)); | 80 String realInstrumentationName = |
| 81 getClassNameFromMetadata(REAL_INSTRUMENTATION_META_DATA_
NAME); |
| 82 initInstrumentation(realInstrumentationName); |
82 } else { | 83 } else { |
83 Log.i(TAG, "No instrumentation active."); | 84 Log.i(TAG, "No instrumentation active."); |
84 } | 85 } |
85 | 86 |
86 // Even when instrumentation is not enabled, ActivityThread uses a d
efault | 87 // Even when instrumentation is not enabled, ActivityThread uses a d
efault |
87 // Instrumentation instance internally. We hook it here in order to
hook into the | 88 // Instrumentation instance internally. We hook it here in order to
hook into the |
88 // call to Instrumentation.onCreate(). | 89 // call to Instrumentation.onCreate(). |
89 Reflect.setField(mActivityThread, "mInstrumentation", | 90 Reflect.setField(mActivityThread, "mInstrumentation", |
90 new BootstrapInstrumentation(this)); | 91 new BootstrapInstrumentation(this)); |
91 | 92 |
92 // attachBaseContext() is called from ActivityThread#handleBindAppli
cation() and | 93 // attachBaseContext() is called from ActivityThread#handleBindAppli
cation() and |
93 // Application#mApplication is changed right after we return. Thus,
we cannot swap | 94 // Application#mApplication is changed right after we return. Thus,
we cannot swap |
94 // the Application instances until onCreate() is called. | 95 // the Application instances until onCreate() is called. |
95 String realApplicationName = metadata.getString(REAL_APP_META_DATA_N
AME); | 96 String realApplicationName = getClassNameFromMetadata(REAL_APP_META_
DATA_NAME); |
96 Log.i(TAG, "Instantiating " + realApplicationName); | 97 Log.i(TAG, "Instantiating " + realApplicationName); |
97 mRealApplication = | 98 mRealApplication = |
98 (Application) Reflect.newInstance(Class.forName(realApplicat
ionName)); | 99 (Application) Reflect.newInstance(Class.forName(realApplicat
ionName)); |
99 Reflect.invokeMethod(mRealApplication, "attachBaseContext", context)
; | 100 Reflect.invokeMethod(mRealApplication, "attachBaseContext", context)
; |
100 | 101 |
101 // Between attachBaseContext() and onCreate(), ActivityThread tries
to instantiate | 102 // Between attachBaseContext() and onCreate(), ActivityThread tries
to instantiate |
102 // all ContentProviders. The ContentProviders break without the corr
ect Application | 103 // all ContentProviders. The ContentProviders break without the corr
ect Application |
103 // class being installed, so temporarily pretend there are no provid
ers, and then | 104 // class being installed, so temporarily pretend there are no provid
ers, and then |
104 // instantiate them explicitly within onCreate(). | 105 // instantiate them explicitly within onCreate(). |
105 disableContentProviders(); | 106 disableContentProviders(); |
106 Log.i(TAG, "Waiting for Instrumentation.onCreate"); | 107 Log.i(TAG, "Waiting for Instrumentation.onCreate"); |
107 } catch (Exception e) { | 108 } catch (Exception e) { |
108 throw new RuntimeException("Incremental install failed.", e); | 109 throw new RuntimeException("Incremental install failed.", e); |
109 } | 110 } |
110 } | 111 } |
111 | 112 |
112 /** | 113 /** |
| 114 * Returns the fully-qualified class name for the given key, stored in a |
| 115 * <meta> witin the manifest. |
| 116 */ |
| 117 private String getClassNameFromMetadata(String key) throws NameNotFoundExcep
tion { |
| 118 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPack
ageName(), |
| 119 PackageManager.GET_META_DATA); |
| 120 String value = appInfo.metaData.getString(key); |
| 121 if (!value.contains(".")) { |
| 122 value = getPackageName() + "." + value; |
| 123 } |
| 124 return value; |
| 125 } |
| 126 |
| 127 /** |
113 * Instantiates and initializes mRealInstrumentation (the real Instrumentati
on class). | 128 * Instantiates and initializes mRealInstrumentation (the real Instrumentati
on class). |
114 */ | 129 */ |
115 private void initInstrumentation(String realInstrumentationName) | 130 private void initInstrumentation(String realInstrumentationName) |
116 throws ReflectiveOperationException { | 131 throws ReflectiveOperationException { |
117 Log.i(TAG, "Instantiating instrumentation " + realInstrumentationName); | 132 Log.i(TAG, "Instantiating instrumentation " + realInstrumentationName); |
118 mRealInstrumentation = (Instrumentation) Reflect.newInstance( | 133 mRealInstrumentation = (Instrumentation) Reflect.newInstance( |
119 Class.forName(realInstrumentationName)); | 134 Class.forName(realInstrumentationName)); |
120 Instrumentation oldInstrumentation = | 135 Instrumentation oldInstrumentation = |
121 (Instrumentation) Reflect.getField(mActivityThread, "mInstrument
ation"); | 136 (Instrumentation) Reflect.getField(mActivityThread, "mInstrument
ation"); |
122 | 137 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 super.onCreate(); | 171 super.onCreate(); |
157 try { | 172 try { |
158 Log.i(TAG, "Application.onCreate() called."); | 173 Log.i(TAG, "Application.onCreate() called."); |
159 mRealApplication.onCreate(); | 174 mRealApplication.onCreate(); |
160 } catch (Exception e) { | 175 } catch (Exception e) { |
161 throw new RuntimeException("Incremental install failed.", e); | 176 throw new RuntimeException("Incremental install failed.", e); |
162 } | 177 } |
163 } | 178 } |
164 | 179 |
165 /** | 180 /** |
166 * Returns the class name of the real Application class (recorded in the | |
167 * AndroidManifest.xml) | |
168 */ | |
169 private Bundle getManifestMetadata() throws NameNotFoundException { | |
170 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPack
ageName(), | |
171 PackageManager.GET_META_DATA); | |
172 return appInfo.metaData; | |
173 } | |
174 | |
175 /** | |
176 * Nulls out ActivityThread.mBoundApplication.providers. | 181 * Nulls out ActivityThread.mBoundApplication.providers. |
177 */ | 182 */ |
178 private void disableContentProviders() throws ReflectiveOperationException { | 183 private void disableContentProviders() throws ReflectiveOperationException { |
179 Object data = Reflect.getField(mActivityThread, "mBoundApplication"); | 184 Object data = Reflect.getField(mActivityThread, "mBoundApplication"); |
180 mStashedProviderList = Reflect.getField(data, "providers"); | 185 mStashedProviderList = Reflect.getField(data, "providers"); |
181 Reflect.setField(data, "providers", null); | 186 Reflect.setField(data, "providers", null); |
182 } | 187 } |
183 | 188 |
184 /** | 189 /** |
185 * Restores the value of ActivityThread.mBoundApplication.providers, and inv
okes | 190 * Restores the value of ActivityThread.mBoundApplication.providers, and inv
okes |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 for (Map.Entry<String, WeakReference<?>> entry : packageMap.entrySet
()) { | 226 for (Map.Entry<String, WeakReference<?>> entry : packageMap.entrySet
()) { |
222 Object loadedApk = entry.getValue().get(); | 227 Object loadedApk = entry.getValue().get(); |
223 if (loadedApk != null && Reflect.getField(loadedApk, "mApplicati
on") == this) { | 228 if (loadedApk != null && Reflect.getField(loadedApk, "mApplicati
on") == this) { |
224 Reflect.setField(loadedApk, "mApplication", mRealApplication
); | 229 Reflect.setField(loadedApk, "mApplication", mRealApplication
); |
225 Reflect.setField(mRealApplication, "mLoadedApk", loadedApk); | 230 Reflect.setField(mRealApplication, "mLoadedApk", loadedApk); |
226 } | 231 } |
227 } | 232 } |
228 } | 233 } |
229 } | 234 } |
230 } | 235 } |
OLD | NEW |