概述
Android WebView 是 Google 提供的一个预安装系统组件,用以支持 Android 应用显示网页内容。
如果您希望在客户端应用中提供 Web 应用(或只是网页),则可以使用 WebView 执行该操作。WebView 类是 Android 的 View 类的扩展,可让您将网页显示为 Activity 布局的一部分。它不会包含功能全面的网络浏览器的任何功能,例如导航控件或地址栏。WebView 默认只显示网页。
使用 WebView 非常有用的一种常见情形是,您希望在应用中提供可能需要更新的信息,例如最终用户协议或用户指南。在 Android 应用中,您可以创建一个包含 WebView 的 Activity,然后使用它来显示在线托管的文档。
另一种 WebView 可能会有所帮助的情形是,如果您的应用向用户提供始终需要互联网连接才能检索数据的数据(例如电子邮件)。在这种情况下,您可能会发现相比于执行网络请求,然后解析数据并在 Android 布局中呈现数据,在 Android 应用中编译 WebView 以显示包含所有用户数据的网页更加轻松。您可以改为设计一个专为 Android 设备定制的网页,然后在加载该网页的 Android 应用中实现 WebView。
________________________From Android
在测试RK3566 Android 11功能的时候,碰到一个奇怪的问题: 第三方浏览器APP调用系统WebView出错了。测试中用的是Via浏览器,问题表现威:白屏,UI卡死操作一会出现ANR。
问题
从logcat中看到的log:
2023-04-23 16:12:46.733 1907-1907 WebViewFactory mark.via I Loading com.android.webview version 83.0.4103.120 (code 410412053)
2023-04-23 16:12:46.735 176-176 HWC2 surfaceflinger E getRequests: invalid layer 0 found on display 0
2023-04-23 16:12:46.742 1907-1907 mark.via mark.via I The ClassLoaderContext is a special shared library.
2023-04-23 16:12:46.744 1907-1907 nativeloader mark.via D classloader namespace configured for unbundled product apk. library_path=/product/app/webview/lib/arm64:/product/app/webview/webview.apk!/lib/arm64-v8a:/product/lib64:/system/product/lib64
2023-04-23 16:12:46.747 1907-1907 webviewc...mloader mark.via E Failed to open relro file /data/misc/shared_relro/libwebviewchromium64.relro: No such file or directory
2023-04-23 16:12:46.747 1907-1907 WebViewL...yLoader mark.via W failed to load with relro file, proceeding without2023-04-23 16:12:46.775 1907-1907 AndroidRuntime mark.via E FATAL EXCEPTION: mainCaused by: java.lang.UnsatisfiedLinkError: dlopen failed: library "libwebviewchromium.so" not foundat java.lang.Runtime.loadLibrary0(Runtime.java:1087)at java.lang.Runtime.loadLibrary0(Runtime.java:1008)at java.lang.System.loadLibrary(System.java:1664)at tt.g(chromium-SystemWebView.apk-default-410412053:14)at tt.i(chromium-SystemWebView.apk-default-410412053:5) at org.chromium.android_webview.AwBrowserProcess.i(chromium-SystemWebView.apk-default-410412053:9) at com.android.webview.chromium.WebViewChromiumFactoryProvider.f(chromium-SystemWebView.apk-default-410412053:68) at com.android.webview.chromium.WebViewChromiumFactoryProvider.<init>(chromium-SystemWebView.apk-default-410412053:12) at com.android.webview.chromium.WebViewChromiumFactoryProviderForR.<init>(chromium-SystemWebView.apk-default-410412053:1) at com.android.webview.chromium.WebViewChromiumFactoryProviderForR.create(chromium-SystemWebView.apk-default-410412053:1) at java.lang.reflect.Method.invoke(Native Method) at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:266) at android.webkit.WebSettings.getDefaultUserAgent(WebSettings.java:1355) at mark.via.o.e.a.b(Unknown Source:221) at mark.via.l.p3.N1(Unknown Source:36) at androidx.fragment.app.Fragment.m2(Unknown Source:4) at androidx.fragment.app.t.f(Unknown Source:271) at androidx.fragment.app.t.m(Unknown Source:124) at androidx.fragment.app.FragmentManager.a0(Unknown Source:230) at androidx.fragment.app.FragmentManager.c1(Unknown Source:91) at androidx.fragment.app.FragmentManager.X(Unknown Source:21) at androidx.fragment.app.FragmentManager.P(Unknown Source:38) at androidx.fragment.app.FragmentManager.u(Unknown Source:11) at androidx.fragment.app.k.c(Unknown Source:4) at androidx.fragment.app.g.onStart(Unknown Source:20) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1435) at android.app.Activity.performStart(Activity.java:8046) at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3457) at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221) at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7664) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) ```
分析LOG前需要先了解一下RELRO参考Android WebView加载Chromium动态库的过程分析
frameworks/base/core/java/android/webkit/WebViewLibraryLoader.java
private static class RelroFileCreator {// Called in an unprivileged child process to create the relro file.public static void main(String[] args) {boolean result = false;boolean is64Bit = VMRuntime.getRuntime().is64Bit();try {if (args.length != 2 || args[0] == null || args[1] == null) {Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));return;}String packageName = args[0];String libraryFileName = args[1];Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), package: "+ packageName + " library: " + libraryFileName);if (!sAddressSpaceReserved) {Log.e(LOGTAG, "can't create relro file; address space not reserved");return;}LoadedApk apk = ActivityThread.currentActivityThread().getPackageInfo(packageName,null,Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);result = nativeCreateRelroFile(libraryFileName,is64Bit ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 :CHROMIUM_WEBVIEW_NATIVE_RELRO_32,apk.getClassLoader());if (result && DEBUG) Log.v(LOGTAG, "created relro file");} finally {// We must do our best to always notify the update service, even if something fails.try {WebViewFactory.getUpdateServiceUnchecked().notifyRelroCreationCompleted();} catch (RemoteException e) {Log.e(LOGTAG, "error notifying update service", e);}if (!result) Log.e(LOGTAG, "failed to create relro file");// Must explicitly exit or else this process will just sit around after we return.System.exit(0);}}}
frameworks/base/native/webview/loader/loader.cpp
ALOGE("Failed to open relro file %s: %s", relro, strerror(errno));
jboolean DoCreateRelroFile(JNIEnv* env, const char* lib, const char* relro,if (handle == NULL) {ALOGE("Failed to load library %s: %s", lib, dlerror());unlink(relro_tmp);return JNI_FALSE;}
}
Failed to load library libwebviewchromium.so: dlopen failed: library "libwebviewchromium.so" not found
Failed to open relro file /data/misc/shared_relro/libwebviewchromium64.relro: No such file or directory
art/libnativeloader/library_namespaces.cpp
ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",//对应LOG
//classloader namespace configured for unbundled product apk. library_path=/product/app/webview/lib/arm64:/product/app/webview/webview.apk!/lib/arm64-v8a:/product/lib64:/system/product/lib64
基本定位到webview的库加载问题后,排除第三方APP问题, 重启看下webview的相关log:
2023-04-24 11:06:15.580 446-472 SystemConfig system_process I Reading permissions from /system/etc/permissions/android.software.webview.xml
2023-04-24 11:06:17.733 446-446 SystemServerTiming system_process I StartWebViewUpdateService
2023-04-24 11:06:17.733 446-446 SystemSe...Manager system_process I Starting com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:17.736 446-446 SystemServerTiming system_process D StartWebViewUpdateService took to complete: 2ms
2023-04-24 11:06:19.625 446-446 SystemServerTiming system_process I OnBootPhase_480_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:19.625 446-446 SystemServerTiming system_process D OnBootPhase_480_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:19.667 446-446 SystemServerTiming system_process I OnBootPhase_500_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:19.667 446-446 SystemServerTiming system_process D OnBootPhase_500_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:20.023 446-446 SystemServerTiming system_process I OnBootPhase_520_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:20.023 446-446 SystemServerTiming system_process D OnBootPhase_520_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:20.161 446-446 SystemServerTiming system_process I OnBootPhase_550_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:20.161 446-446 SystemServerTiming system_process D OnBootPhase_550_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:20.540 446-511 SystemSe...ngAsync system_process I InitThreadPoolExec:WebViewFactoryPreparation
2023-04-24 11:06:20.540 446-511 SystemSe...eadPool system_process D Started executing WebViewFactoryPreparation
2023-04-24 11:06:20.540 446-511 SystemServer system_process I WebViewFactoryPreparation
2023-04-24 11:06:20.540 446-511 SystemSe...ngAsync system_process I WebViewFactoryPreparation
2023-04-24 11:06:20.556 446-511 SystemSe...ngAsync system_process D WebViewFactoryPreparation took to complete: 16ms
2023-04-24 11:06:20.556 446-511 SystemSe...eadPool system_process D Finished executing WebViewFactoryPreparation
2023-04-24 11:06:20.556 446-511 SystemSe...ngAsync system_process D InitThreadPoolExec:WebViewFactoryPreparation took to complete: 17ms
2023-04-24 11:06:20.694 446-475 ActivityManager system_process I Start proc 678:WebViewLoader-armeabi-v7a/1037 [android.webkit.WebViewLibraryLoader$RelroFileCreator] for null
2023-04-24 11:06:20.768 446-475 ActivityManager system_process I Start proc 692:WebViewLoader-arm64-v8a/1037 [android.webkit.WebViewLibraryLoader$RelroFileCreator] for null
2023-04-24 11:06:20.780 678-678 WebViewL...yLoader pid-678 V RelroFileCreator (64bit = false), package: com.android.webview library: libwebviewchromium.so
2023-04-24 11:06:20.792 692-692 WebViewL...yLoader pid-692 V RelroFileCreator (64bit = true), package: com.android.webview library: libwebviewchromium.so
2023-04-24 11:06:20.809 446-446 SystemServerTiming system_process I OnBootPhase_600_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:20.809 446-446 SystemServerTiming system_process D OnBootPhase_600_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:20.837 692-692 WebViewLoader- pid-692 I The ClassLoaderContext is a special shared library.
2023-04-24 11:06:20.837 678-678 WebViewLoader- pid-678 I The ClassLoaderContext is a special shared library.
2023-04-24 11:06:20.839 692-692 nativeloader pid-692 D classloader namespace configured for unbundled product apk. library_path=/product/app/webview/lib/arm64:/product/app/webview/webview.apk!/lib/arm64-v8a:/product/lib64:/system/product/lib64
2023-04-24 11:06:20.839 678-678 nativeloader pid-678 D classloader namespace configured for unbundled product apk. library_path=/product/app/webview/lib/arm:/product/app/webview/webview.apk!/lib/armeabi-v7a:/product/lib:/system/product/lib
2023-04-24 11:06:20.857 678-678 webviewc...mloader pid-678 E Failed to load library libwebviewchromium.so: dlopen failed: library "libwebviewchromium.so" not found
2023-04-24 11:06:20.863 692-692 webviewc...mloader pid-692 E Failed to load library libwebviewchromium.so: dlopen failed: library "libwebviewchromium.so" not found
2023-04-24 11:06:20.871 678-678 WebViewL...yLoader pid-678 E failed to create relro file
2023-04-24 11:06:20.874 692-692 WebViewL...yLoader pid-692 E failed to create relro file
2023-04-24 11:06:20.881 692-692 WebViewLoader- pid-692 I System.exit called, status: 0
2023-04-24 11:06:20.886 678-678 WebViewLoader- pid-678 I System.exit called, status: 0
2023-04-24 11:06:20.915 758-758 WebViewZygoteInit pid-758 I Starting WebViewZygoteInit
2023-04-24 11:06:20.922 446-504 ActivityManager system_process I Process WebViewLoader-armeabi-v7a (pid 678) has died: psvc PER
2023-04-24 11:06:20.952 758-758 WebViewZygoteInit pid-758 I Beginning application preload for com.android.webview
2023-04-24 11:06:20.958 446-728 ActivityManager system_process I Process WebViewLoader-arm64-v8a (pid 692) has died: psvc PER
2023-04-24 11:06:20.962 758-758 webview_zygote pid-758 I The ClassLoaderContext is a special shared library.
2023-04-24 11:06:20.964 758-758 nativeloader pid-758 D classloader namespace configured for unbundled product apk. library_path=/product/app/webview/lib/arm:/product/app/webview/webview.apk!/lib/armeabi-v7a:/product/lib:/system/product/lib
2023-04-24 11:06:20.968 758-758 webviewc...mloader pid-758 E Failed to open relro file /data/misc/shared_relro/libwebviewchromium32.relro: No such file or directory
2023-04-24 11:06:20.968 758-758 WebViewL...yLoader pid-758 W failed to load with relro file, proceeding without
2023-04-24 11:06:21.004 758-758 WebViewZygoteInit pid-758 E Exception while preloading packagejava.lang.reflect.InvocationTargetExceptionat java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.WebViewZygoteInit$WebViewZygoteConnection.doPreload(WebViewZygoteInit.java:126)at com.android.internal.os.WebViewZygoteInit$WebViewZygoteConnection.handlePreloadApp(WebViewZygoteInit.java:79)at com.android.internal.os.ZygoteConnection.processOneCommand(ZygoteConnection.java:181)at com.android.internal.os.ZygoteServer.runSelectLoop(ZygoteServer.java:546)at com.android.internal.os.ChildZygoteInit.runZygoteServer(ChildZygoteInit.java:125)at com.android.internal.os.WebViewZygoteInit.main(WebViewZygoteInit.java:147)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: library "libwebviewchromium.so" not foundat java.lang.Runtime.loadLibrary0(Runtime.java:1087)at java.lang.Runtime.loadLibrary0(Runtime.java:1008)at java.lang.System.loadLibrary(System.java:1664)at com.android.webview.chromium.WebViewChromiumFactoryProvider.preloadInZygote(chromium-SystemWebView.apk-default-410412053:3)at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.WebViewZygoteInit$WebViewZygoteConnection.doPreload(WebViewZygoteInit.java:126) at com.android.internal.os.WebViewZygoteInit$WebViewZygoteConnection.handlePreloadApp(WebViewZygoteInit.java:79) at com.android.internal.os.ZygoteConnection.processOneCommand(ZygoteConnection.java:181) at com.android.internal.os.ZygoteServer.runSelectLoop(ZygoteServer.java:546) at com.android.internal.os.ChildZygoteInit.runZygoteServer(ChildZygoteInit.java:125) at com.android.internal.os.WebViewZygoteInit.main(WebViewZygoteInit.java:147) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
2023-04-24 11:06:21.004 758-758 WebViewZygoteInit pid-758 I Application preload done
2023-04-24 11:06:21.006 446-446 SystemServerTiming system_process I ssm.onStartUser-0_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:21.006 446-446 SystemServerTiming system_process D ssm.onStartUser-0_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:21.031 446-446 StorageM...Service system_process V Package com.android.webview does not have legacy storage
2023-04-24 11:06:24.986 446-468 Activity...rTiming system_process I OnBootPhase_1000_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:24.986 446-468 Activity...rTiming system_process D OnBootPhase_1000_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:26.235 446-474 SystemSe...ngAsync system_process I ssm.onUnlockingUser-0_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:26.235 446-474 SystemSe...ngAsync system_process D ssm.onUnlockingUser-0_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
2023-04-24 11:06:26.366 446-474 SystemSe...ngAsync system_process I ssm.onUnlockedUser-0_com.android.server.webkit.WebViewUpdateService
2023-04-24 11:06:26.366 446-474 SystemSe...ngAsync system_process D ssm.onUnlockedUser-0_com.android.server.webkit.WebViewUpdateService took to complete: 0ms
基本与第三方APP没什么关系, webview的lib库是在开机就加载的.
bionic/linker/linker.cpp 根据经验,先到linker打打LOG
static int open_library_in_zipfile(ZipArchiveCache* zip_archive_cache,const char* const input_path,off64_t* file_offset, std::string* realpath) {std::string normalized_path;if (!normalize_path(input_path, &normalized_path)) {PRINT("open_library_in_zipfile err normallized path");return -1;}const char* const path = normalized_path.c_str();TRACE("Trying zip file open from path \"%s\" -> normalized \"%s\"", input_path, path);// Treat an '!/' separator inside a path as the separator between the name// of the zip file on disk and the subdirectory to search within it.// For example, if path is "foo.zip!/bar/bas/x.so", then we search for// "bar/bas/x.so" within "foo.zip".const char* const separator = strstr(path, kZipFileSeparator);if (separator == nullptr) {PRINT("open_library_in_zipfile err no separator");return -1;}char buf[512];if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {PRINT("Warning: ignoring very long library path: %s", path);return -1;}buf[separator - path] = '\0';const char* zip_path = buf;const char* file_path = &buf[separator - path + 2];int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));if (fd == -1) {PRINT("open_library_in_zipfile err 0");return -1;}PRINT("open_library_in_zipfile zip_path=%s", zip_path);ZipArchiveHandle handle;if (!zip_archive_cache->get_or_open(zip_path, &handle)) {// invalid zip-file (?)close(fd);PRINT("open_library_in_zipfile err 1");return -1;}ZipEntry entry;if (FindEntry(handle, file_path, &entry) != 0) {// Entry was not found.close(fd);PRINT("open_library_in_zipfile err 2");return -1;}// Check if it is properly storedif (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {close(fd);PRINT("open_library_in_zipfile err 3, %d, %d", entry.method != kCompressStored, (entry.offset % PAGE_SIZE) != 0);return -1;}*file_offset = entry.offset;if (realpath_fd(fd, realpath)) {*realpath += separator;} else {if (!is_first_stage_init()) {PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",normalized_path.c_str());}*realpath = normalized_path;}return fd;
}
linker mark.via load_library(ns=(default), task=/product/app/webview/oat/arm64/webview.odex, flags=0x2, search_linked_namespaces=0): calling open_library with realpath=
linker mark.via open_library name=/product/app/webview/oat/arm64/webview.odex, ns=(default)
linker mark.via load_library taskName=libwebviewchromium.so
linker mark.via load_library(ns=vendor-classloader-namespace, task=libwebviewchromium.so, flags=0x2, search_linked_namespaces=1): calling open_library with realpath=
linker mark.via open_library name=libwebviewchromium.so, ns=vendor-classloader-namespace
linker mark.via open_library_in_zipfile zip_path=/product/app/webview/webview.apk
linker mark.via open_library_in_zipfile err 3, 1, 1
linker mark.via open_library_at_path /product/app/webview/webview.apk!/lib/arm64-v8a/libwebviewchromium.so FAILED
linker mark.via open_library_at_path /product/lib64/libwebviewchromium.so FAILED
linker mark.via open_library_at_path /product/lib64/libwebviewchromium.so FAILED
error 3 表明,这两个条件都有问题:entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0
看文件:
rk3568_a11$ tree out/target/product/rk3566_r/product/app/webview/
out/target/product/rk3566_r/product/app/webview/
├── oat
│ ├── arm
│ │ ├── webview.odex
│ │ └── webview.vdex
│ └── arm64
│ ├── webview.odex
│ └── webview.vdex
└── webview.apk
//Failed
linker pid-664 load_library taskName=libwebviewchromium.so
linker pid-664 load_library(ns=vendor-classloader-namespace, task=libwebviewchromium.so, flags=0x0, search_linked_namespaces=1): calling open_library with realpath=
linker pid-664 open_library name=libwebviewchromium.so, ns=vendor-classloader-namespace
linker pid-664 open_library_in_zipfile zip_path=/product/app/webview/webview.apk
linker pid-664 open_library_in_zipfile err 3, 1, 1
linker pid-664 open_library_at_path /product/app/webview/webview.apk!/lib/armeabi-v7a/libwebviewchromium.so FAILED//Success
linker pid-822 load_library taskName=libwebviewchromium.so
linker pid-822 load_library(ns=vendor-classloader-namespace, task=libwebviewchromium.so, flags=0x0, search_linked_namespaces=1): calling open_library with realpath=
linker pid-822 open_library name=libwebviewchromium.so, ns=vendor-classloader-namespace
linker pid-822 open_library_in_zipfile zip_path=/product/app/webview/webview.apk
linker pid-822 open_library_at_path /product/app/webview/webview.apk!/lib/armeabi-v7a/libwebviewchromium.so SUCCESS
解决
非逻辑问题,怀疑webview文件的问题,尝试替换掉webview试试,从另一套代码中拷贝出编译好的webview, PUSH到主板中,问题神奇地消失了。
最终发现是改了编译配置导致生成的webview.apk文件不一致导致(APK的优化对齐相关)。
在修正了文件问题后,对应目录的RELRO存在相应的文件。
rk3566:/ # ll /data/misc/shared_relro/
total 5332
-r--r--r-- 1 shared_relro shared_relro 1892352 2023-04-24 15:53 libwebviewchromium32.relro
-r--r--r-- 1 shared_relro shared_relro 3563520 2023-04-24 15:53 libwebviewchromium64.relro
参考
Shared Libraries on Android
Shared Libraries on Android
Android WebView加载Chromium动态库的过程分析
Android系统安全 — 2.0-移动终端栈溢出的保护机制设置
在 WebView 中编译 Web 应用