| 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 |