Commit ff82c558 authored by Torne (Richard Coles)'s avatar Torne (Richard Coles) Committed by Commit Bot

weblayer: share WebView's context wrapper.

Use ClassLoaderContextWrapperFactory from WebView instead of wrapping
the context ourselves, as the requirements are the same. Move the
wrapping to the implementation side instead of the client side so that
we can update it easily in future.

This means that there's no longer any need for the client side to hold
on to the Context for the implementation, as only the ClassLoader is
actually required to bootstrap loading; ClassLoaderContextWrapperFactory
simply uses its own classloader instead of requiring that a
Context/ClassLoader be passed in.

Change-Id: I9fb4418da7267b8f015b61c08d44cb6fa2faf65d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1867409Reviewed-by: default avatarClark DuVall <cduvall@chromium.org>
Commit-Queue: Richard Coles <torne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#707841}
parent e3494791
...@@ -40,6 +40,7 @@ android_library("java") { ...@@ -40,6 +40,7 @@ android_library("java") {
":weblayer_resources", ":weblayer_resources",
"//base:base_java", "//base:base_java",
"//base:jni_java", "//base:jni_java",
"//components/embedder_support/android:application_java",
"//content/public/android:content_java", "//content/public/android:content_java",
"//ui/android:ui_java", "//ui/android:ui_java",
] ]
......
...@@ -11,6 +11,7 @@ import android.os.IBinder; ...@@ -11,6 +11,7 @@ import android.os.IBinder;
import org.chromium.base.annotations.UsedByReflection; import org.chromium.base.annotations.UsedByReflection;
import org.chromium.base.process_launcher.ChildProcessService; import org.chromium.base.process_launcher.ChildProcessService;
import org.chromium.components.embedder_support.application.ClassLoaderContextWrapperFactory;
import org.chromium.content_public.app.ChildProcessServiceFactory; import org.chromium.content_public.app.ChildProcessServiceFactory;
import org.chromium.weblayer_private.aidl.IChildProcessService; import org.chromium.weblayer_private.aidl.IChildProcessService;
import org.chromium.weblayer_private.aidl.IObjectWrapper; import org.chromium.weblayer_private.aidl.IObjectWrapper;
...@@ -21,8 +22,10 @@ public final class ChildProcessServiceImpl extends IChildProcessService.Stub { ...@@ -21,8 +22,10 @@ public final class ChildProcessServiceImpl extends IChildProcessService.Stub {
private ChildProcessService mService; private ChildProcessService mService;
@UsedByReflection("WebLayer") @UsedByReflection("WebLayer")
public static IBinder create(Service service, Context context) { public static IBinder create(Service service, Context appContext) {
return new ChildProcessServiceImpl(service, context); // Wrap the app context so that it can be used to load WebLayer implementation classes.
appContext = ClassLoaderContextWrapperFactory.get(appContext);
return new ChildProcessServiceImpl(service, appContext);
} }
@Override @Override
......
...@@ -15,6 +15,7 @@ import org.chromium.base.PathUtils; ...@@ -15,6 +15,7 @@ import org.chromium.base.PathUtils;
import org.chromium.base.annotations.UsedByReflection; import org.chromium.base.annotations.UsedByReflection;
import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.components.embedder_support.application.ClassLoaderContextWrapperFactory;
import org.chromium.content_public.browser.BrowserStartupController; import org.chromium.content_public.browser.BrowserStartupController;
import org.chromium.content_public.browser.ChildProcessCreationParams; import org.chromium.content_public.browser.ChildProcessCreationParams;
import org.chromium.content_public.browser.DeviceUtils; import org.chromium.content_public.browser.DeviceUtils;
...@@ -52,18 +53,21 @@ public final class WebLayerImpl extends IWebLayer.Stub { ...@@ -52,18 +53,21 @@ public final class WebLayerImpl extends IWebLayer.Stub {
} }
@Override @Override
public void initAndLoadAsync(IObjectWrapper webLayerContextWrapper, public void initAndLoadAsync(IObjectWrapper appContextWrapper,
IObjectWrapper loadedCallbackWrapper, int resourcesPackageId) { IObjectWrapper loadedCallbackWrapper, int resourcesPackageId) {
// TODO: The call to onResourcesLoaded() can be slow, we may need to parallelize this with // TODO: The call to onResourcesLoaded() can be slow, we may need to parallelize this with
// other expensive startup tasks. // other expensive startup tasks.
R.onResourcesLoaded(resourcesPackageId); R.onResourcesLoaded(resourcesPackageId);
Context context = ObjectWrapper.unwrap(webLayerContextWrapper, Context.class); // Wrap the app context so that it can be used to load WebLayer implementation classes.
ContextUtils.initApplicationContext(context); Context appContext = ClassLoaderContextWrapperFactory.get(
ObjectWrapper.unwrap(appContextWrapper, Context.class));
ContextUtils.initApplicationContext(appContext);
ResourceBundle.setAvailablePakLocales(new String[] {}, LocaleConfig.UNCOMPRESSED_LOCALES); ResourceBundle.setAvailablePakLocales(new String[] {}, LocaleConfig.UNCOMPRESSED_LOCALES);
PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
ChildProcessCreationParams.set(context.getPackageName(), false /* isExternalService */, ChildProcessCreationParams.set(appContext.getPackageName(), false /* isExternalService */,
LibraryProcessType.PROCESS_WEBLAYER_CHILD, true /* bindToCaller */, LibraryProcessType.PROCESS_WEBLAYER_CHILD, true /* bindToCaller */,
false /* ignoreVisibilityForImportance */, false /* ignoreVisibilityForImportance */,
"org.chromium.weblayer.ChildProcessService$Privileged", "org.chromium.weblayer.ChildProcessService$Privileged",
......
...@@ -13,9 +13,9 @@ import org.chromium.weblayer_private.aidl.IRemoteFragmentClient; ...@@ -13,9 +13,9 @@ import org.chromium.weblayer_private.aidl.IRemoteFragmentClient;
interface IWebLayer { interface IWebLayer {
// Initializes WebLayer and starts loading. It is expected that is called // Initializes WebLayer and starts loading. It is expected that is called
// before anything else. |loadedCallback| is a ValueCallback that is called // before anything else. |loadedCallback| is a ValueCallback that is called
// when load completes. |webLayerContext| is a Context that refers to the // when load completes. |appContext| is a Context that refers to the
// WebLayer implementation. // Application using WebLayer.
void initAndLoadAsync(in IObjectWrapper webLayerContext, void initAndLoadAsync(in IObjectWrapper appContext,
in IObjectWrapper loadedCallback, in IObjectWrapper loadedCallback,
int resourcesPackageId) = 1; int resourcesPackageId) = 1;
......
...@@ -26,12 +26,13 @@ public abstract class ChildProcessService extends Service { ...@@ -26,12 +26,13 @@ public abstract class ChildProcessService extends Service {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
try { try {
Context remoteContext = WebLayer.createRemoteContext(getApplication()); Context appContext = getApplicationContext();
ClassLoader remoteClassLoader = WebLayer.createRemoteClassLoader(appContext);
mImpl = IChildProcessService.Stub.asInterface( mImpl = IChildProcessService.Stub.asInterface(
(IBinder) remoteContext.getClassLoader() (IBinder) remoteClassLoader
.loadClass("org.chromium.weblayer_private.ChildProcessServiceImpl") .loadClass("org.chromium.weblayer_private.ChildProcessServiceImpl")
.getMethod("create", Service.class, Context.class) .getMethod("create", Service.class, Context.class)
.invoke(null, this, remoteContext)); .invoke(null, this, appContext));
mImpl.onCreate(); mImpl.onCreate();
} catch (Exception e) { } catch (Exception e) {
throw new APICallException(e); throw new APICallException(e);
......
...@@ -4,9 +4,7 @@ ...@@ -4,9 +4,7 @@
package org.chromium.weblayer; package org.chromium.weblayer;
import android.content.ComponentCallbacks;
import android.content.Context; import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
...@@ -47,11 +45,11 @@ public final class WebLayer { ...@@ -47,11 +45,11 @@ public final class WebLayer {
* Loads the WebLayer implementation and returns the IWebLayer. This does *not* trigger the * Loads the WebLayer implementation and returns the IWebLayer. This does *not* trigger the
* implementation to start. * implementation to start.
*/ */
private static IWebLayer connectToWebLayerImplementation(Context remoteContext) private static IWebLayer connectToWebLayerImplementation(ClassLoader remoteClassLoader)
throws UnsupportedVersionException { throws UnsupportedVersionException {
try { try {
Class webLayerClass = remoteContext.getClassLoader().loadClass( Class webLayerClass =
"org.chromium.weblayer_private.WebLayerImpl"); remoteClassLoader.loadClass("org.chromium.weblayer_private.WebLayerImpl");
// Check version before doing anything else on the implementation side. // Check version before doing anything else on the implementation side.
if (!(boolean) webLayerClass.getMethod("checkVersion", Integer.TYPE) if (!(boolean) webLayerClass.getMethod("checkVersion", Integer.TYPE)
...@@ -72,7 +70,7 @@ public final class WebLayer { ...@@ -72,7 +70,7 @@ public final class WebLayer {
* Loads assets for WebLayer and returns the package ID to use when calling * Loads assets for WebLayer and returns the package ID to use when calling
* R.onResourcesLoaded(). * R.onResourcesLoaded().
*/ */
private static int loadAssets(Context appContext, Context remoteContext) { private static int loadAssets(Context appContext) {
WebViewDelegate delegate; WebViewDelegate delegate;
PackageInfo implPackageInfo; PackageInfo implPackageInfo;
try { try {
...@@ -109,10 +107,12 @@ public final class WebLayer { ...@@ -109,10 +107,12 @@ public final class WebLayer {
public static ListenableFuture<WebLayer> create(Context appContext) public static ListenableFuture<WebLayer> create(Context appContext)
throws UnsupportedVersionException { throws UnsupportedVersionException {
if (sFuture == null) { if (sFuture == null) {
Context remoteContext = createRemoteContext(appContext.getApplicationContext()); // Just in case the app passed an Activity context.
IWebLayer iWebLayer = connectToWebLayerImplementation(remoteContext); appContext = appContext.getApplicationContext();
int resourcesPackageId = loadAssets(appContext, remoteContext); ClassLoader remoteClassLoader = createRemoteClassLoader(appContext);
sFuture = new WebLayerLoadFuture(iWebLayer, remoteContext, resourcesPackageId); IWebLayer iWebLayer = connectToWebLayerImplementation(remoteClassLoader);
int resourcesPackageId = loadAssets(appContext);
sFuture = new WebLayerLoadFuture(iWebLayer, appContext, resourcesPackageId);
} }
return sFuture; return sFuture;
} }
...@@ -123,7 +123,7 @@ public final class WebLayer { ...@@ -123,7 +123,7 @@ public final class WebLayer {
private static final class WebLayerLoadFuture extends ListenableFuture<WebLayer> { private static final class WebLayerLoadFuture extends ListenableFuture<WebLayer> {
private final IWebLayer mIWebLayer; private final IWebLayer mIWebLayer;
WebLayerLoadFuture(IWebLayer iWebLayer, Context remoteContext, int resourcesPackageId) { WebLayerLoadFuture(IWebLayer iWebLayer, Context appContext, int resourcesPackageId) {
mIWebLayer = iWebLayer; mIWebLayer = iWebLayer;
ValueCallback<Boolean> loadCallback = new ValueCallback<Boolean>() { ValueCallback<Boolean> loadCallback = new ValueCallback<Boolean>() {
@Override @Override
...@@ -134,7 +134,7 @@ public final class WebLayer { ...@@ -134,7 +134,7 @@ public final class WebLayer {
} }
}; };
try { try {
iWebLayer.initAndLoadAsync(ObjectWrapper.wrap(remoteContext), iWebLayer.initAndLoadAsync(ObjectWrapper.wrap(appContext),
ObjectWrapper.wrap(loadCallback), resourcesPackageId); ObjectWrapper.wrap(loadCallback), resourcesPackageId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw new APICallException(e); throw new APICallException(e);
...@@ -209,47 +209,19 @@ public final class WebLayer { ...@@ -209,47 +209,19 @@ public final class WebLayer {
} }
/** /**
* Creates a Context for the remote (weblayer implementation) side. * Creates a ClassLoader for the remote (weblayer implementation) side.
*/ */
static Context createRemoteContext(Context localContext) { static ClassLoader createRemoteClassLoader(Context localContext) {
Context remoteContext;
try { try {
// TODO(cduvall): Might want to cache the remote context so we don't need to call into // TODO(cduvall): Might want to cache the remote context so we don't need to call into
// package manager more than we need to. // package manager more than we need to.
remoteContext = localContext.createPackageContext(getImplPackageName(localContext), Context remoteContext =
Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE); localContext.createPackageContext(getImplPackageName(localContext),
Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
return remoteContext.getClassLoader();
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
throw new AndroidRuntimeException(e); throw new AndroidRuntimeException(e);
} }
return wrapContext(localContext, remoteContext);
}
private static Context wrapContext(Context localContext, Context remoteContext) {
return new ContextWrapper(localContext) {
@Override
public Context getApplicationContext() {
if (getBaseContext().getApplicationContext() == getBaseContext()) return this;
return wrapContext(getBaseContext().getApplicationContext(), remoteContext);
}
@Override
public ClassLoader getClassLoader() {
return remoteContext.getClassLoader();
}
@Override
public void registerComponentCallbacks(ComponentCallbacks callback) {
// We have to override registerComponentCallbacks and unregisterComponentCallbacks
// since they call getApplicationContext().[un]registerComponentCallbacks()
// which causes us to go into a loop.
getBaseContext().registerComponentCallbacks(callback);
}
@Override
public void unregisterComponentCallbacks(ComponentCallbacks callback) {
getBaseContext().unregisterComponentCallbacks(callback);
}
};
} }
private static String getImplPackageName(Context localContext) private static String getImplPackageName(Context localContext)
......
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