Commit 16ec437a authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

Fix ClassCastException when inflating layouts

The fix in https://crrev.com/c/2522511 almost worked, but ended up
crashing when inflating layouts. This change replaces the underlying
ClassLoader from the ContextImpl for each Activity.

Bug: 1146745
Change-Id: I23fc0b15fcd5ef80b78c82de2ab83245af1146d5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2526627Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825550}
parent 23f48a7f
......@@ -4,7 +4,14 @@
package org.chromium.chrome.browser.base;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import java.lang.reflect.Field;
/**
* Application class to use for Chrome when //chrome code is in an isolated split. This class will
......@@ -33,9 +40,56 @@ public class SplitChromeApplication extends SplitCompatApplication {
setImpl(createNonBrowserApplication());
}
super.attachBaseContext(context);
if (isBrowserProcess()) {
applyActivityClassLoaderWorkaround();
}
}
protected MainDexApplicationImpl createNonBrowserApplication() {
return new MainDexApplicationImpl();
}
/**
* Fixes Activity ClassLoader if necessary. Isolated splits can cause a ClassLoader mismatch
* between the Application and Activity ClassLoaders. We have a workaround in
* SplitCompatAppComponentFactory which overrides the Activity ClassLoader, but this does not
* change the ClassLoader for the Activity's base context. We override that ClassLoader here, so
* it matches the ClassLoader that was used to load the Activity class. Note that
* ContextUtils.getApplicationContext().getClassLoader() may not give the right ClassLoader here
* because the Activity may be in a DFM which is a child of the chrome DFM. See
* crbug.com/1146745 for more info.
*/
private static void applyActivityClassLoaderWorkaround() {
ApplicationStatus.registerStateListenerForAllActivities(
new ApplicationStatus.ActivityStateListener() {
@Override
public void onActivityStateChange(
Activity activity, @ActivityState int newState) {
if (newState != ActivityState.CREATED) {
return;
}
// ClassLoaders are already the same, no workaround needed.
if (activity.getClassLoader().equals(
activity.getClass().getClassLoader())) {
return;
}
Context baseContext = activity.getBaseContext();
while (baseContext instanceof ContextWrapper) {
baseContext = ((ContextWrapper) baseContext).getBaseContext();
}
try {
// baseContext should now be an instance of ContextImpl.
Field classLoaderField =
baseContext.getClass().getDeclaredField("mClassLoader");
classLoaderField.setAccessible(true);
classLoaderField.set(baseContext, activity.getClass().getClassLoader());
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Error fixing Activity ClassLoader.", e);
}
}
});
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment