多进程问题导致crash
ava.lang.RuntimeException: Using WebView from more than one process at once with the same data directory is not supported. https://crbug.com/558377
at com.android.webview.chromium.WebViewChromiumAwInit.startChromiumLocked(WebViewChromiumAwInit.java:100)
at com.android.webview.chromium.WebViewChromiumAwInitForP.startChromiumLocked(WebViewChromiumAwInitForP.java:3)
at com.android.webview.chromium.WebViewChromiumAwInit.ensureChromiumStartedLocked(WebViewChromiumAwInit.java:180)
at com.android.webview.chromium.WebViewChromiumAwInit.startYourEngines(WebViewChromiumAwInit.java:161)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.startYourEngines(WebViewChromiumFactoryProvider.java:217)
at com.android.webview.chromium.WebViewChromium.init(WebViewChromium.java:44)
at android.webkit.WebView.<init>(WebView.java:432)
at android.webkit.WebView.<init>(WebView.java:358)
at android.webkit.WebView.<init>(WebView.java:341)
三年前 Android 9 Android10出现的问题 经过setDataDirectorySuffix设置后 还是top1 的crash 。 多进程假如用到同一个webview目录就会导致crash, 看日志现象是不同的pid相同的进程名,猜想有些状况下存在两个相同包名的进程。处理办法也比较简单, 发动时发现目录现已被其他进程占用了 ,那就再加上一个pid后缀。
处理:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
if (application.getPackageName().equals(currentProcessName)) {
File lockFile = new File(application.getDir("webview", Context.MODE_PRIVATE).getPath(), "webview_data.lock");
if (lockFile.exists()) {
RandomAccessFile lock = new RandomAccessFile(lockFile, "rw");
//没有被其他进程锁住
if (lock.getChannel().tryLock() != null) {
lockFile.delete()
} else {
//被其他进程锁了
HAS_WEB_LOCK = true;
WEBVIEW_PATH = "webview";
WebView.setDataDirectorySuffix(application.getPackageName() + "_" + Process.myPid());
}
}
//华为部分android 10 手机webview缓存目录为hws_webview
if (Build.VERSION.SDK_INT >= 29 && ("HuaWei".equalsIgnoreCase(Build.BRAND) || "HONOR".equalsIgnoreCase(Build.BRAND))) {
File hwLockFile = new File(application.getDir("hws_webview", Context.MODE_PRIVATE).getPath(), "webview_data.lock");
if (hwLockFile.exists()) {
RandomAccessFile hwLock = new RandomAccessFile(hwLockFile, "rw");
//没有被其他进程锁住
if (hwLock.getChannel().tryLock() != null) {
lockFile.delete()
} else {
//被其他进程锁了
HAS_WEB_LOCK = true;
WEBVIEW_PATH = "hws_webview";
WebView.setDataDirectorySuffix(application.getPackageName() + "_" + Process.myPid());
}
}
}
} else {
WebView.setDataDirectorySuffix(currentProcessName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
烘托问题导致crash
看仓库没有任何剖析思路 运用剖析工具查一波。
- 结合crash行为日志剖析出现场景。
有一次线上很多出现该问题,剖析行为日志路径大都是出现在BrowserActivity之后 检查load的url也是同一个,大概率是前端代码原因导致,前端排查发现加载了一个特别大的图片,下线图片后crash下降。
- 结合abort message ,backtrace ,java stacktrace, logcat排查问题。
不同行为路径下还少量存在该crash,这时就要去看详细crash是如何触发的了。
- 首先经过上面信息咱们能够复制粘贴到浏览器搜索一波。
- 源码盯梢 chromium.googlesource.com/chromium/sr…
看delegate->onRenderProcessGone办法回来的不同值做不同的处理,这个办法最终会调用到
android.webkit.WebViewClient的onRenderProcessGone办法
看注释webview 烘托进程退出会通知到该办法。能够用loadUrl(“chrome://crash”)测试这个case .多个webview同享render process 都需要处理不仅仅是loadUrl(“chrome://crash”)的这个webview。
这边假如不处理默许回来false render process挂了会导致使用进程也挂了。
处理:
对项目中的Webview client复现该办法 调用后上报反常埋点及当时加载url 处理webview 回来true。
但是用loadUrl(“chrome://crash”)做测试时 并没有回调该办法而直接crash。 后续对framwork层android.webkit.WebViewClient进行调试 发现这边确实断点到了 没有走子类的办法。发现是两个webview不一样。原来是咱们项目做了webview缓存池的一个功用。会提早构建下一个webview 但是这个webview的WebViewClient用是默许的WebViewClient所以回来的是false。 回到上面触发crash代码片断 确实是一个循环去触发AwContents的onRenderProcessGone 发现有没处理的就crash了。最后针对提早构建的webview也去设置一个自己的WebViewClient 。建立反常url报表
apk&so 反常不兼容导致crash
89.0.4389.90版别导致 crash
Android体系的WebView错误更新,致使很多使用溃散 zhuanlan.zhihu.com/p/359482553
so 架构不匹配导致 crash
Caused by: java.lang.RuntimeException: Cannot load WebView
at org.chromium.android_webview.AwBrowserProcess.a(PG:20)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.a(PG:81)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.<init>(PG:12)
at com.android.webview.chromium.WebViewChromiumFactoryProviderForOMR1.<init>(PG:1)
at com.android.webview.chromium.WebViewChromiumFactoryProviderForOMR1.create(PG:1)
... 39 more
Caused by: Qy0
at org.chromium.base.library_loader.LibraryLoader.a(PG:40)
at org.chromium.base.library_loader.LibraryLoader.a(PG:16)
at org.chromium.android_webview.AwBrowserProcess.a(PG:16)
... 43 more
Caused by: java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/com.android.chrome-b7SMbfSB6LfJn2_2Ai7yHA==/base.apk!/lib/armeabi-v7a/libmonochrome.so" is 32-bit instead of 64-bit
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1657)
at org.chromium.base.library_loader.LibraryLoader.a(PG:31)
... 45 more
处理: 创立webview的时候做try catch 依据仓库进行判别 降级提示用户webview版别不兼容,无法运用,辅导和建议进行升级
webview 预创立提速
发动优化发现webview 预创立耗时特别明显,现已到了耗时使命top1
trace结合xposed咱们很简单做到竞品webview 发动剖析,比照效果,比如一些app能够把解析webview apk的逻辑放到子线程,咱们也能够对这个方案进行尝试。
把上面的代码放到子线程 ,当然有个条件如下图,子线程加载要和主线程使命A一起,因为主线程webview使命肯定是要加载webview apk后执行的。 线上测试下来能平均优化100ms,抱负状况有200多ms, 当然业务假如答应在运用时再创立webview 更能提高发动速度,不过第一次翻开h5页面体会就会受到影响。
处理Webview crash 相关的报表
除了一般处理crash的一些报表 比如设备维度,体系版别维度等报表,webview crash有额定几个维度的报表能帮助咱们快速定位问题。
-
crash时load url的报表
- 还有一些crash时是和加载的url有关的,这部分客户端能做的是做一个url crash的趋势报表 发现反常及时告警推动h5同学去处理。
-
webview.apk version维度报表
比如之前89.0.4389.90的webview.apk版别的问题 就很简单经过这个报表发现。
public static List<String> getWebviewApkVersions(Application application) {
ArrayList<String> versions = new ArrayList<>();
if (application == null) {
return versions;
}
PackageManager packageManager = application.getPackageManager();
ArrayList<String> webviewPackages = new ArrayList<>();
webviewPackages.add("com.google.android.webview");
webviewPackages.add("com.android.webview");
if ("xiaomi".equalsIgnoreCase(Build.BRAND) || "redmi".equalsIgnoreCase(Build.BRAND)) {
webviewPackages.add("com.mi.webkit.core");
}
if ("huawei".equalsIgnoreCase(Build.BRAND) || "HONOR".equalsIgnoreCase(Build.BRAND)) {
webviewPackages.add("com.huawei.webview");
}
if (packageManager != null) {
for (String packageName : webviewPackages) {
PackageInfo packageInfo;
try {
packageInfo = packageManager.getPackageInfo(packageName, 0);
if (packageInfo != null) {
versions.add(packageName + "-" + packageInfo.versionName);
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
return versions;
比如这个版别肯定是有问题的。 这部分能够去检查厂商,体系版别,行为日志尝试复现,进行问题反应。