Commit b4b8a01e authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

[WebLayer] Load resources correctly for standalone WebView APK

This fixes resources loading, and allows WebLayer to work with the
standalone WebView APK, which previously would crash with a
Resources$NotFoundException exception.

Adds a run_weblayer_shell_webview build target for testing with
standalone WebView.

Change-Id: If1063efdfbf462ccf36bc54f796d3b934a456274
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1854204Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706086}
parent 55f96bee
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
import("//build/config/android/config.gni") import("//build/config/android/config.gni")
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
android_resources("weblayer_resources") {
resource_dirs = []
custom_package = "org.chromium.weblayer_private"
}
android_library("java") { android_library("java") {
java_files = [ java_files = [
"org/chromium/weblayer_private/BrowserControllerImpl.java", "org/chromium/weblayer_private/BrowserControllerImpl.java",
...@@ -25,6 +30,7 @@ android_library("java") { ...@@ -25,6 +30,7 @@ android_library("java") {
deps = [ deps = [
":client_java", ":client_java",
":weblayer_resources",
"//base:base_java", "//base:base_java",
"//base:jni_java", "//base:jni_java",
"//content/public/android:content_java", "//content/public/android:content_java",
......
...@@ -52,8 +52,12 @@ public final class WebLayerImpl extends IWebLayer.Stub { ...@@ -52,8 +52,12 @@ public final class WebLayerImpl extends IWebLayer.Stub {
} }
@Override @Override
public void initAndLoadAsync( public void initAndLoadAsync(IObjectWrapper webLayerContextWrapper,
IObjectWrapper webLayerContextWrapper, IObjectWrapper loadedCallbackWrapper) { 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); Context context = ObjectWrapper.unwrap(webLayerContextWrapper, Context.class);
ContextUtils.initApplicationContext(context); ContextUtils.initApplicationContext(context);
ResourceBundle.setNoAvailableLocalePaks(); ResourceBundle.setNoAvailableLocalePaks();
......
...@@ -16,7 +16,8 @@ interface IWebLayer { ...@@ -16,7 +16,8 @@ interface IWebLayer {
// when load completes. |webLayerContext| is a Context that refers to the // when load completes. |webLayerContext| is a Context that refers to the
// WebLayer implementation. // WebLayer implementation.
void initAndLoadAsync(in IObjectWrapper webLayerContext, void initAndLoadAsync(in IObjectWrapper webLayerContext,
in IObjectWrapper loadedCallback) = 1; in IObjectWrapper loadedCallback,
int resourcesPackageId) = 1;
// Blocks until loading has completed. // Blocks until loading has completed.
void loadSync() = 2; void loadSync() = 2;
......
...@@ -10,7 +10,6 @@ import android.content.ContextWrapper; ...@@ -10,7 +10,6 @@ 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;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
...@@ -48,26 +47,9 @@ public final class WebLayer { ...@@ -48,26 +47,9 @@ 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 application) private static IWebLayer connectToWebLayerImplementation(Context remoteContext)
throws UnsupportedVersionException { throws UnsupportedVersionException {
try { try {
// TODO: Make asset loading work on L, where WebViewDelegate doesn't exist.
// WebViewDelegate.addWebViewAssetPath() accesses the currently loaded package info from
// WebViewFactory, so we have to fake it.
PackageInfo implPackageInfo = application.getPackageManager().getPackageInfo(
getImplPackageName(application), PackageManager.GET_META_DATA);
Field packageInfo = WebViewFactory.class.getDeclaredField("sPackageInfo");
packageInfo.setAccessible(true);
packageInfo.set(null, implPackageInfo);
// TODO(torne): Figure out how to load assets for production.
// Load assets using the WebViewDelegate.
Constructor constructor = WebViewDelegate.class.getDeclaredConstructor();
constructor.setAccessible(true);
WebViewDelegate delegate = (WebViewDelegate) constructor.newInstance();
delegate.addWebViewAssetPath(application);
Context remoteContext = createRemoteContext(application);
Class webLayerClass = remoteContext.getClassLoader().loadClass( Class webLayerClass = remoteContext.getClassLoader().loadClass(
"org.chromium.weblayer_private.WebLayerImpl"); "org.chromium.weblayer_private.WebLayerImpl");
...@@ -86,6 +68,35 @@ public final class WebLayer { ...@@ -86,6 +68,35 @@ 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) {
WebViewDelegate delegate;
PackageInfo implPackageInfo;
try {
// TODO: Make asset loading work on L, where WebViewDelegate doesn't exist.
// WebViewDelegate.addWebViewAssetPath() accesses the currently loaded package info from
// WebViewFactory, so we have to fake it.
implPackageInfo = appContext.getPackageManager().getPackageInfo(
getImplPackageName(appContext), PackageManager.GET_META_DATA);
Field packageInfo = WebViewFactory.class.getDeclaredField("sPackageInfo");
packageInfo.setAccessible(true);
packageInfo.set(null, implPackageInfo);
// TODO(torne): Figure out how to load assets for production.
// Load assets using the WebViewDelegate.
Constructor constructor = WebViewDelegate.class.getDeclaredConstructor();
constructor.setAccessible(true);
delegate = (WebViewDelegate) constructor.newInstance();
} catch (Exception e) {
throw new AndroidRuntimeException(e);
}
delegate.addWebViewAssetPath(appContext);
return delegate.getPackageId(appContext.getResources(), implPackageInfo.packageName);
}
/** /**
* Asynchronously creates and initializes WebLayer. Calling this more than once returns the same * Asynchronously creates and initializes WebLayer. Calling this more than once returns the same
* object. * object.
...@@ -97,9 +108,10 @@ public final class WebLayer { ...@@ -97,9 +108,10 @@ 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) {
IWebLayer iWebLayer = connectToWebLayerImplementation( Context remoteContext = createRemoteContext(appContext.getApplicationContext());
appContext.getApplicationContext()); IWebLayer iWebLayer = connectToWebLayerImplementation(remoteContext);
sFuture = new WebLayerLoadFuture(iWebLayer, appContext); int resourcesPackageId = loadAssets(appContext, remoteContext);
sFuture = new WebLayerLoadFuture(iWebLayer, remoteContext, resourcesPackageId);
} }
return sFuture; return sFuture;
} }
...@@ -110,7 +122,7 @@ public final class WebLayer { ...@@ -110,7 +122,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 application) { WebLayerLoadFuture(IWebLayer iWebLayer, Context remoteContext, int resourcesPackageId) {
mIWebLayer = iWebLayer; mIWebLayer = iWebLayer;
ValueCallback<Boolean> loadCallback = new ValueCallback<Boolean>() { ValueCallback<Boolean> loadCallback = new ValueCallback<Boolean>() {
@Override @Override
...@@ -121,8 +133,8 @@ public final class WebLayer { ...@@ -121,8 +133,8 @@ public final class WebLayer {
} }
}; };
try { try {
iWebLayer.initAndLoadAsync(ObjectWrapper.wrap(createRemoteContext(application)), iWebLayer.initAndLoadAsync(ObjectWrapper.wrap(remoteContext),
ObjectWrapper.wrap(loadCallback)); ObjectWrapper.wrap(loadCallback), resourcesPackageId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw new APICallException(e); throw new APICallException(e);
} }
...@@ -219,11 +231,6 @@ public final class WebLayer { ...@@ -219,11 +231,6 @@ public final class WebLayer {
return wrapContext(getBaseContext().getApplicationContext(), remoteContext); return wrapContext(getBaseContext().getApplicationContext(), remoteContext);
} }
@Override
public Resources getResources() {
return remoteContext.getResources();
}
@Override @Override
public ClassLoader getClassLoader() { public ClassLoader getClassLoader() {
return remoteContext.getClassLoader(); return remoteContext.getClassLoader();
......
...@@ -129,6 +129,23 @@ if (public_android_sdk) { ...@@ -129,6 +129,23 @@ if (public_android_sdk) {
"//chrome/android:trichrome_library_apk", "//chrome/android:trichrome_library_apk",
] ]
} }
generate_wrapper("run_weblayer_shell_webview") {
testonly = true
wrapper_script = "$root_out_dir/bin/run_weblayer_shell_webview"
executable = "//weblayer/tools/run_weblayer_shell.py"
executable_args = [
"--shell-apk-path",
"@WrappedPath(apks/WebLayerShellWebView.apk)",
"--support-apk-path",
"@WrappedPath(apks/SystemWebView.apk)",
]
deps = [
":weblayer_shell_webview_apk",
"//android_webview:system_webview_apk",
]
}
} }
demo_apk_manifest = "$target_gen_dir/demo_apk_manifest/AndroidManifest.xml" demo_apk_manifest = "$target_gen_dir/demo_apk_manifest/AndroidManifest.xml"
...@@ -230,6 +247,7 @@ android_apk("weblayer_support_apk") { ...@@ -230,6 +247,7 @@ android_apk("weblayer_support_apk") {
min_sdk_version = 21 min_sdk_version = 21
target_sdk_version = 28 target_sdk_version = 28
android_manifest_dep = ":weblayer_support_manifest" android_manifest_dep = ":weblayer_support_manifest"
shared_resources = true
native_lib_version_rule = "//build/util:chrome_version_json" native_lib_version_rule = "//build/util:chrome_version_json"
_native_lib_file = _native_lib_file =
......
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