Commit 9b660407 authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

[WebLayer] Use crazy linker for M- and "/." trick for N+

Instead of copying libraries on M-, this changes to using the crazy
linker, which loads the library without any knowledge of what libraries
have been loaded by the system linker. This requires manual JNI
registration. To make sure we only register WebLayer JNI when needed,
a minimal set of JNI methods is registered, and the full set is
registered later if we require WebView compatibility.

In N+, we switch to prepending "/." to library paths instead of using
symlinks, which allows us to avoid writing any files to the apps data
directory. This simplifies the interface quite a bit, allowing
initializeWebViewCompatibilityMode() to be sync instead of async. I will
follow up with the Android team to make sure we have a better solution
for future versions of Android.

The API has not been used in the client app yet, so it should be safe
to remove M- support for the copy library approach in the
implementation. The old version of initializeWebViewCompatibilityMode()
was kept so the WebLayer API version compat tests would still pass.

TBR=agrieve@chromium.org

Bug: 1051358
Change-Id: I2cd5ae0e025feaeb5c41cf9ddfafc91cd09fbad7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2090024
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749973}
parent 43548e91
...@@ -63,6 +63,6 @@ source_set("webview_entry_point") { ...@@ -63,6 +63,6 @@ source_set("webview_entry_point") {
if (webview_includes_weblayer) { if (webview_includes_weblayer) {
defines = [ "WEBVIEW_INCLUDES_WEBLAYER" ] defines = [ "WEBVIEW_INCLUDES_WEBLAYER" ]
deps += [ "//weblayer:weblayer_lib" ] deps += [ "//weblayer:weblayer_lib_webview" ]
} }
} }
...@@ -32,6 +32,10 @@ bool NativeInit(base::android::LibraryProcessType library_process_type) { ...@@ -32,6 +32,10 @@ bool NativeInit(base::android::LibraryProcessType library_process_type) {
// Most of the initialization is done in LibraryLoadedOnMainThread(), not here. // Most of the initialization is done in LibraryLoadedOnMainThread(), not here.
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
base::android::InitVM(vm); base::android::InitVM(vm);
#if defined(WEBVIEW_INCLUDES_WEBLAYER)
if (!weblayer::RegisterMinimalNatives())
return -1;
#endif
base::android::SetNativeInitializationHook(&NativeInit); base::android::SetNativeInitializationHook(&NativeInit);
return JNI_VERSION_1_4; return JNI_VERSION_1_4;
} }
...@@ -132,6 +132,11 @@ template("system_webview_apk_or_module_tmpl") { ...@@ -132,6 +132,11 @@ template("system_webview_apk_or_module_tmpl") {
"//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline", "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline",
] ]
loadable_modules = [ "$root_out_dir/libcrashpad_handler_trampoline.so" ] loadable_modules = [ "$root_out_dir/libcrashpad_handler_trampoline.so" ]
if (webview_includes_weblayer) {
deps += [ "//base/android/linker:chromium_android_linker" ]
loadable_modules +=
[ "$root_out_dir/libchromium_android_linker$shlib_extension" ]
}
} }
if (_include_secondary_support) { if (_include_secondary_support) {
_trampoline = "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)" _trampoline = "//third_party/crashpad/crashpad/handler:crashpad_handler_trampoline($android_secondary_abi_toolchain)"
...@@ -142,6 +147,11 @@ template("system_webview_apk_or_module_tmpl") { ...@@ -142,6 +147,11 @@ template("system_webview_apk_or_module_tmpl") {
_secondary_out_dir = get_label_info(_trampoline, "root_out_dir") _secondary_out_dir = get_label_info(_trampoline, "root_out_dir")
secondary_abi_loadable_modules = secondary_abi_loadable_modules =
[ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ] [ "$_secondary_out_dir/libcrashpad_handler_trampoline.so" ]
if (webview_includes_weblayer) {
deps += [ "//base/android/linker:chromium_android_linker($android_secondary_abi_toolchain)" ]
secondary_abi_loadable_modules +=
[ "$_secondary_out_dir/libchromium_android_linker$shlib_extension" ]
}
} }
if (!_use_trichrome_library || android_64bit_target_cpu) { if (!_use_trichrome_library || android_64bit_target_cpu) {
......
...@@ -124,6 +124,9 @@ public class LibraryLoader { ...@@ -124,6 +124,9 @@ public class LibraryLoader {
// Whether the configuration has been set. // Whether the configuration has been set.
private boolean mConfigurationSet; private boolean mConfigurationSet;
// Runs after all native libraries have been loaded.
private Runnable mPostLoadHook;
@IntDef({LoadState.NOT_LOADED, LoadState.MAIN_DEX_LOADED, LoadState.LOADED}) @IntDef({LoadState.NOT_LOADED, LoadState.MAIN_DEX_LOADED, LoadState.LOADED})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
private @interface LoadState { private @interface LoadState {
...@@ -147,10 +150,6 @@ public class LibraryLoader { ...@@ -147,10 +150,6 @@ public class LibraryLoader {
// will be reported via UMA. Set once when the libraries are done loading. // will be reported via UMA. Set once when the libraries are done loading.
private long mLibraryLoadTimeMs; private long mLibraryLoadTimeMs;
// The suffix to add when loading the library. This is useful if a library with the same name is
// loaded in the same process, as can be the case with WebView/WebLayer.
private String mLibrarySuffix = "";
/** /**
* Call this method to determine if the chromium project must load the library * Call this method to determine if the chromium project must load the library
* directly from a zip file. * directly from a zip file.
...@@ -186,13 +185,10 @@ public class LibraryLoader { ...@@ -186,13 +185,10 @@ public class LibraryLoader {
mLibraryProcessType = type; mLibraryProcessType = type;
} }
/** /** Sets a function to run after all native libraries have been loaded. */
* Sets a suffix to use when loading the library. This will be appended to the library names public void setPostLoadHook(Runnable postLoadHook) {
* for calls to System.loadLibrary().
*/
public void setLibrarySuffix(String suffix) {
assert mLoadState == LoadState.NOT_LOADED; assert mLoadState == LoadState.NOT_LOADED;
mLibrarySuffix = suffix; mPostLoadHook = postLoadHook;
} }
/** /**
...@@ -492,7 +488,7 @@ public class LibraryLoader { ...@@ -492,7 +488,7 @@ public class LibraryLoader {
// Load libraries using the system linker. // Load libraries using the system linker.
for (String library : NativeLibraries.LIBRARIES) { for (String library : NativeLibraries.LIBRARIES) {
if (!isInZipFile()) { if (!isInZipFile()) {
System.loadLibrary(library + mLibrarySuffix); System.loadLibrary(library);
} else { } else {
// Load directly from the APK. // Load directly from the APK.
boolean is64Bit = ApiHelperForM.isProcess64Bit(); boolean is64Bit = ApiHelperForM.isProcess64Bit();
...@@ -540,6 +536,10 @@ public class LibraryLoader { ...@@ -540,6 +536,10 @@ public class LibraryLoader {
} catch (UnsatisfiedLinkError e) { } catch (UnsatisfiedLinkError e) {
throw new ProcessInitException(LoaderErrors.NATIVE_LIBRARY_LOAD_FAILED, e); throw new ProcessInitException(LoaderErrors.NATIVE_LIBRARY_LOAD_FAILED, e);
} }
if (mPostLoadHook != null) {
mPostLoadHook.run();
}
} }
@VisibleForTesting @VisibleForTesting
......
...@@ -61,6 +61,7 @@ void SetNativeInitializationHook( ...@@ -61,6 +61,7 @@ void SetNativeInitializationHook(
void SetNonMainDexJniRegistrationHook( void SetNonMainDexJniRegistrationHook(
NonMainDexJniRegistrationHook jni_registration_hook) { NonMainDexJniRegistrationHook jni_registration_hook) {
DCHECK(!g_jni_registration_hook);
g_jni_registration_hook = jni_registration_hook; g_jni_registration_hook = jni_registration_hook;
} }
......
...@@ -40,6 +40,7 @@ CHROME_SPECIFIC = BuildFileMatchRegex( ...@@ -40,6 +40,7 @@ CHROME_SPECIFIC = BuildFileMatchRegex(
# WebView specific files which are not in Monochrome.apk # WebView specific files which are not in Monochrome.apk
WEBVIEW_SPECIFIC = BuildFileMatchRegex( WEBVIEW_SPECIFIC = BuildFileMatchRegex(
r'lib/.*/libwebviewchromium\.so', r'lib/.*/libwebviewchromium\.so',
r'lib/.*/libchromium_android_linker\.so',
r'assets/webview_licenses.notice', r'assets/webview_licenses.notice',
r'res/.*/icon_webview(.webp)?', r'res/.*/icon_webview(.webp)?',
r'META-INF/.*', r'META-INF/.*',
......
...@@ -86,7 +86,7 @@ if (is_android) { ...@@ -86,7 +86,7 @@ if (is_android) {
} }
} }
static_library("weblayer_lib") { source_set("weblayer_lib_base") {
sources = [ sources = [
"app/content_main_delegate_impl.cc", "app/content_main_delegate_impl.cc",
"app/content_main_delegate_impl.h", "app/content_main_delegate_impl.h",
...@@ -303,6 +303,7 @@ static_library("weblayer_lib") { ...@@ -303,6 +303,7 @@ static_library("weblayer_lib") {
if (is_android) { if (is_android) {
sources += [ sources += [
"$target_gen_dir/browser/java/weblayer_minimal_jni_registration.h",
"app/jni_onload.cc", "app/jni_onload.cc",
"app/jni_onload.h", "app/jni_onload.h",
"browser/android/exception_filter.cc", "browser/android/exception_filter.cc",
...@@ -344,13 +345,16 @@ static_library("weblayer_lib") { ...@@ -344,13 +345,16 @@ static_library("weblayer_lib") {
"//android_webview:generate_aw_strings", "//android_webview:generate_aw_strings",
"//components/android_system_error_page", "//components/android_system_error_page",
"//components/autofill/android:provider", "//components/autofill/android:provider",
"//components/crash/android:crash_android",
"//components/crash/android:crashpad_main", "//components/crash/android:crashpad_main",
"//components/embedder_support/android:context_menu", "//components/embedder_support/android:context_menu",
"//components/embedder_support/android:util",
"//components/embedder_support/android:web_contents_delegate", "//components/embedder_support/android:web_contents_delegate",
"//components/embedder_support/android/metrics", "//components/embedder_support/android/metrics",
"//components/javascript_dialogs", "//components/javascript_dialogs",
"//components/metrics", "//components/metrics",
"//components/minidump_uploader", "//components/minidump_uploader",
"//components/permissions/android:native",
"//components/safe_browsing/content/common:interfaces", "//components/safe_browsing/content/common:interfaces",
"//components/safe_browsing/content/renderer:throttles", "//components/safe_browsing/content/renderer:throttles",
"//components/safe_browsing/core/common", "//components/safe_browsing/core/common",
...@@ -358,6 +362,7 @@ static_library("weblayer_lib") { ...@@ -358,6 +362,7 @@ static_library("weblayer_lib") {
"//services/resource_coordinator/public/cpp/memory_instrumentation:browser", "//services/resource_coordinator/public/cpp/memory_instrumentation:browser",
"//ui/android", "//ui/android",
"//weblayer/browser/java:jni", "//weblayer/browser/java:jni",
"//weblayer/browser/java:weblayer_minimal_jni_registration",
"//weblayer/browser/safe_browsing:safe_browsing", "//weblayer/browser/safe_browsing:safe_browsing",
] ]
} else { } else {
...@@ -399,6 +404,45 @@ static_library("weblayer_lib") { ...@@ -399,6 +404,45 @@ static_library("weblayer_lib") {
} }
} }
if (is_android) {
# Lib used in standalone WebView which allows manual JNI registration.
static_library("weblayer_lib_webview") {
public_deps = [ ":weblayer_lib_base" ]
deps = [
"//base",
"//weblayer/browser/java:jni",
"//weblayer/browser/java:weblayer_jni_registration",
]
sources = [
"$target_gen_dir/browser/java/weblayer_jni_registration.h",
"browser/web_view_compatibility_helper_impl.cc",
]
defines = [ "WEBLAYER_MANUAL_JNI_REGISTRATION" ]
# Explicit dependency required for JNI registration to be able to
# find the native side functions.
if (is_component_build) {
deps += [
"//device/gamepad",
"//media/midi",
"//ui/events/devices",
]
}
}
# Lib used in Monochrome which does not support manual JNI registration.
# Separate from the standalone WebView version to reduce APK size.
static_library("weblayer_lib") {
public_deps = [ ":weblayer_lib_base" ]
deps = [ "//weblayer/browser/java:jni" ]
sources = [ "browser/web_view_compatibility_helper_impl.cc" ]
}
} else {
static_library("weblayer_lib") {
public_deps = [ ":weblayer_lib_base" ]
}
}
grit("resources") { grit("resources") {
source = "weblayer_resources.grd" source = "weblayer_resources.grd"
...@@ -420,7 +464,7 @@ if (is_android) { ...@@ -420,7 +464,7 @@ if (is_android) {
shared_library("libweblayer") { shared_library("libweblayer") {
sources = [ "app/entry_point.cc" ] sources = [ "app/entry_point.cc" ]
deps = [ deps = [
":weblayer_lib", ":weblayer_lib_webview",
"//base", "//base",
"//content/public/app:both", "//content/public/app:both",
] ]
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "content/public/app/content_jni_onload.h" #include "content/public/app/content_jni_onload.h"
#include "content/public/app/content_main.h" #include "content/public/app/content_main.h"
#include "weblayer/app/content_main_delegate_impl.h" #include "weblayer/app/content_main_delegate_impl.h"
#include "weblayer/browser/java/weblayer_minimal_jni_registration.h"
namespace weblayer { namespace weblayer {
...@@ -34,4 +35,9 @@ bool OnJNIOnLoadInit() { ...@@ -34,4 +35,9 @@ bool OnJNIOnLoadInit() {
return true; return true;
} }
bool RegisterMinimalNatives() {
return weblayer_minimal::RegisterMainDexNatives(
base::android::AttachCurrentThread());
}
} // namespace weblayer } // namespace weblayer
...@@ -11,6 +11,10 @@ namespace weblayer { ...@@ -11,6 +11,10 @@ namespace weblayer {
bool OnJNIOnLoadInit(); bool OnJNIOnLoadInit();
// Registers the minimal set of natives needed to later register the full set of
// natives if WebView compatibility is needed.
bool RegisterMinimalNatives();
} // namespace weblayer } // namespace weblayer
#endif // WEBLAYER_APP_JNI_ONLOAD_H_ #endif // WEBLAYER_APP_JNI_ONLOAD_H_
...@@ -32,8 +32,7 @@ public class WebViewCompatibilityTest { ...@@ -32,8 +32,7 @@ public class WebViewCompatibilityTest {
public void testBothLoadPage() throws Exception { public void testBothLoadPage() throws Exception {
TestThreadUtils.runOnUiThreadBlocking(() -> { TestThreadUtils.runOnUiThreadBlocking(() -> {
WebLayer.initializeWebViewCompatibilityMode( WebLayer.initializeWebViewCompatibilityMode(
InstrumentationRegistry.getTargetContext().getApplicationContext(), InstrumentationRegistry.getTargetContext().getApplicationContext());
InstrumentationRegistry.getTargetContext().getCacheDir(), null);
}); });
mActivityTestRule.launchShellWithUrl(mActivityTestRule.getTestDataURL("simple_page.html")); mActivityTestRule.launchShellWithUrl(mActivityTestRule.getTestDataURL("simple_page.html"));
WebView webView = TestThreadUtils.runOnUiThreadBlocking( WebView webView = TestThreadUtils.runOnUiThreadBlocking(
......
...@@ -32,6 +32,18 @@ java_cpp_enum("generated_enums") { ...@@ -32,6 +32,18 @@ java_cpp_enum("generated_enums") {
] ]
} }
_webview_compat_sources =
[ "org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java" ]
android_library("webview_compat_java") {
sources = _webview_compat_sources
deps = [
"//base:base_java",
"//base:jni_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
android_library("java") { android_library("java") {
sources = [ sources = [
"org/chromium/weblayer_private/ActionModeCallback.java", "org/chromium/weblayer_private/ActionModeCallback.java",
...@@ -75,6 +87,7 @@ android_library("java") { ...@@ -75,6 +87,7 @@ android_library("java") {
":gms_bridge_java", ":gms_bridge_java",
":interfaces_java", ":interfaces_java",
":weblayer_resources", ":weblayer_resources",
":webview_compat_java",
"//base:base_java", "//base:base_java",
"//base:jni_java", "//base:jni_java",
"//components/autofill/android:provider_java", "//components/autofill/android:provider_java",
...@@ -117,6 +130,20 @@ android_library("java") { ...@@ -117,6 +130,20 @@ android_library("java") {
"//third_party/android_sdk:public_framework_system_java" "//third_party/android_sdk:public_framework_system_java"
} }
generate_jni_registration("weblayer_jni_registration") {
targets = [ ":java" ]
header_output = "$target_gen_dir/$target_name.h"
sources_blacklist = _webview_compat_sources
namespace = "weblayer"
}
generate_jni_registration("weblayer_minimal_jni_registration") {
targets = [ ":webview_compat_java" ]
header_output = "$target_gen_dir/$target_name.h"
namespace = "weblayer_minimal"
no_transitive_deps = true
}
android_resources("weblayer_test_resources") { android_resources("weblayer_test_resources") {
resource_dirs = [ "res_test" ] resource_dirs = [ "res_test" ]
custom_package = "org.chromium.weblayer_private.test" custom_package = "org.chromium.weblayer_private.test"
...@@ -153,6 +180,7 @@ generate_jni("jni") { ...@@ -153,6 +180,7 @@ generate_jni("jni") {
"org/chromium/weblayer_private/UrlBarControllerImpl.java", "org/chromium/weblayer_private/UrlBarControllerImpl.java",
"org/chromium/weblayer_private/WebLayerExceptionFilter.java", "org/chromium/weblayer_private/WebLayerExceptionFilter.java",
"org/chromium/weblayer_private/WebLayerImpl.java", "org/chromium/weblayer_private/WebLayerImpl.java",
"org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java",
"org/chromium/weblayer_private/metrics/MetricsServiceClient.java", "org/chromium/weblayer_private/metrics/MetricsServiceClient.java",
"org/chromium/weblayer_private/metrics/UmaUtils.java", "org/chromium/weblayer_private/metrics/UmaUtils.java",
"org/chromium/weblayer_private/resources/ResourceMapper.java", "org/chromium/weblayer_private/resources/ResourceMapper.java",
......
...@@ -190,9 +190,10 @@ public final class WebLayerImpl extends IWebLayer.Stub { ...@@ -190,9 +190,10 @@ public final class WebLayerImpl extends IWebLayer.Stub {
mIsWebViewCompatMode = remoteContext != null mIsWebViewCompatMode = remoteContext != null
&& !remoteContext.getClassLoader().equals(WebLayerImpl.class.getClassLoader()); && !remoteContext.getClassLoader().equals(WebLayerImpl.class.getClassLoader());
if (mIsWebViewCompatMode && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { if (mIsWebViewCompatMode && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
// We need to change the library name for Android M and below, otherwise the system will // Load the library with the crazy linker.
// load the version loaded for WebView. LibraryLoader.getInstance().setLinkerImplementation(true, false);
LibraryLoader.getInstance().setLibrarySuffix("-weblayer"); LibraryLoader.getInstance().setPostLoadHook(
WebViewCompatibilityHelperImpl::registerJni);
} }
Context appContext = minimalInitForContext(appContextWrapper, remoteContextWrapper); Context appContext = minimalInitForContext(appContextWrapper, remoteContextWrapper);
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.weblayer_private;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.MainDex;
import org.chromium.base.annotations.NativeMethods;
/**
* Minimal native interface to allow registering all natives if WebView compatibility is needed.
*/
@MainDex
@JNINamespace("weblayer")
public final class WebViewCompatibilityHelperImpl {
public static void registerJni() {
WebViewCompatibilityHelperImplJni.get().registerJni();
}
@NativeMethods
interface Natives {
void registerJni();
}
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "weblayer/browser/java/jni/WebViewCompatibilityHelperImpl_jni.h"
#if defined(WEBLAYER_MANUAL_JNI_REGISTRATION)
#include "base/android/library_loader/library_loader_hooks.h" // nogncheck
#include "weblayer/browser/java/weblayer_jni_registration.h" // nogncheck
#endif
namespace weblayer {
namespace {
#if defined(WEBLAYER_MANUAL_JNI_REGISTRATION)
void RegisterNonMainDexNativesHook() {
RegisterNonMainDexNatives(base::android::AttachCurrentThread());
}
#endif
} // namespace
void JNI_WebViewCompatibilityHelperImpl_RegisterJni(JNIEnv* env) {
#if defined(WEBLAYER_MANUAL_JNI_REGISTRATION)
RegisterMainDexNatives(base::android::AttachCurrentThread());
base::android::SetNonMainDexJniRegistrationHook(
RegisterNonMainDexNativesHook);
#endif
}
} // namespace weblayer
...@@ -7,9 +7,12 @@ ...@@ -7,9 +7,12 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/threading/scoped_blocking_call.h" #include "base/threading/scoped_blocking_call.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/version_info/android/channel_getter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#if defined(OS_ANDROID)
#include "components/version_info/android/channel_getter.h"
#endif
using version_info::Channel; using version_info::Channel;
namespace weblayer { namespace weblayer {
...@@ -47,7 +50,11 @@ WebLayerVariationsServiceClient::GetNetworkTimeTracker() { ...@@ -47,7 +50,11 @@ WebLayerVariationsServiceClient::GetNetworkTimeTracker() {
} }
Channel WebLayerVariationsServiceClient::GetChannel() { Channel WebLayerVariationsServiceClient::GetChannel() {
#if defined(OS_ANDROID)
return version_info::android::GetChannel(); return version_info::android::GetChannel();
#else
return version_info::Channel::UNKNOWN;
#endif
} }
bool WebLayerVariationsServiceClient::OverridesRestrictParameter( bool WebLayerVariationsServiceClient::OverridesRestrictParameter(
......
...@@ -14,6 +14,7 @@ import android.os.RemoteException; ...@@ -14,6 +14,7 @@ import android.os.RemoteException;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.util.AndroidRuntimeException; import android.util.AndroidRuntimeException;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
...@@ -33,7 +34,6 @@ import java.lang.reflect.Field; ...@@ -33,7 +34,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
/** /**
* WebLayer is responsible for initializing state necessary to use any of the classes in web layer. * WebLayer is responsible for initializing state necessary to use any of the classes in web layer.
...@@ -59,18 +59,12 @@ public class WebLayer { ...@@ -59,18 +59,12 @@ public class WebLayer {
@NonNull @NonNull
private final IWebLayer mImpl; private final IWebLayer mImpl;
private static WebViewCompatibilityHelper sWebViewCompatHelper; private static ClassLoader sWebViewCompatClassLoader;
/** The result of calling {@link #initializeWebViewCompatibilityMode}. */ /** The result of calling {@link #initializeWebViewCompatibilityMode}. */
public enum WebViewCompatibilityResult { public enum WebViewCompatibilityResult {
/** Native libs were copied to data directory. */ /** Compatibility mode has been successfully set up. */
SUCCESS_COPIED, SUCCESS,
/** Correct libs have already been copied, or symlinks were used. */
SUCCESS_CACHED,
/** IOException was thrown, could mean there is not enough disk space. */
FAILURE_IO_ERROR,
/** This version of the WebLayer implementation does not support WebView compatibility. */ /** This version of the WebLayer implementation does not support WebView compatibility. */
FAILURE_UNSUPPORTED_VERSION, FAILURE_UNSUPPORTED_VERSION,
...@@ -100,18 +94,24 @@ public class WebLayer { ...@@ -100,18 +94,24 @@ public class WebLayer {
} }
} }
/** Deprecated. Use initializeWebViewCompatibilityMode(Context) instead. */
public static void initializeWebViewCompatibilityMode(@NonNull Context appContext,
@NonNull File baseDir, @NonNull Callback<WebViewCompatibilityResult> callback) {
WebViewCompatibilityResult result = initializeWebViewCompatibilityMode(appContext);
if (callback != null) {
callback.onResult(result);
}
}
/** /**
* Performs initialization needed to run WebView and WebLayer in the same process. This should * Performs initialization needed to run WebView and WebLayer in the same process.
* be called as early as possible if this functionality is needed.
* *
* @param appContext The hosting application's Context. * @param appContext The hosting application's Context.
* @param baseDir The directory to copy any necessary files into.
* @param callback Callback called on success or failure.
*/ */
public static void initializeWebViewCompatibilityMode(@NonNull Context appContext, public static WebViewCompatibilityResult initializeWebViewCompatibilityMode(
@NonNull File baseDir, @NonNull Callback<WebViewCompatibilityResult> callback) { @NonNull Context appContext) {
ThreadCheck.ensureOnUiThread(); ThreadCheck.ensureOnUiThread();
if (sWebViewCompatHelper != null) { if (sWebViewCompatClassLoader != null) {
throw new AndroidRuntimeException( throw new AndroidRuntimeException(
"initializeWebViewCompatibilityMode() has already been called."); "initializeWebViewCompatibilityMode() has already been called.");
} }
...@@ -121,13 +121,14 @@ public class WebLayer { ...@@ -121,13 +121,14 @@ public class WebLayer {
+ "loaded."); + "loaded.");
} }
try { try {
sWebViewCompatHelper = WebViewCompatibilityHelper.initialize( Pair<ClassLoader, WebLayer.WebViewCompatibilityResult> result =
appContext, getOrCreateRemoteContext(appContext), baseDir, callback); WebViewCompatibilityHelper.initialize(
appContext, getOrCreateRemoteContext(appContext));
sWebViewCompatClassLoader = result.first;
return result.second;
} catch (Exception e) { } catch (Exception e) {
if (callback != null) {
callback.onResult(WebViewCompatibilityResult.FAILURE_OTHER);
}
Log.e(TAG, "Unable to initialize WebView compatibility", e); Log.e(TAG, "Unable to initialize WebView compatibility", e);
return WebViewCompatibilityResult.FAILURE_OTHER;
} }
} }
...@@ -265,8 +266,8 @@ public class WebLayer { ...@@ -265,8 +266,8 @@ public class WebLayer {
int majorVersion = -1; int majorVersion = -1;
String version = "<unavailable>"; String version = "<unavailable>";
try { try {
if (sWebViewCompatHelper != null) { if (sWebViewCompatClassLoader != null) {
remoteClassLoader = sWebViewCompatHelper.getWebLayerClassLoader(); remoteClassLoader = sWebViewCompatClassLoader;
} }
if (remoteClassLoader == null) { if (remoteClassLoader == null) {
remoteClassLoader = getOrCreateRemoteContext(appContext).getClassLoader(); remoteClassLoader = getOrCreateRemoteContext(appContext).getClassLoader();
...@@ -285,7 +286,7 @@ public class WebLayer { ...@@ -285,7 +286,7 @@ public class WebLayer {
majorVersion = mFactory.getImplementationMajorVersion(); majorVersion = mFactory.getImplementationMajorVersion();
version = mFactory.getImplementationVersion(); version = mFactory.getImplementationVersion();
} catch (PackageManager.NameNotFoundException | ReflectiveOperationException } catch (PackageManager.NameNotFoundException | ReflectiveOperationException
| RemoteException | ExecutionException | InterruptedException e) { | RemoteException e) {
Log.e(TAG, "Unable to create WebLayerFactory", e); Log.e(TAG, "Unable to create WebLayerFactory", e);
} }
mAvailable = available; mAvailable = available;
......
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