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