我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android 解决WebView多进程崩溃的方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android 解决WebView多进程崩溃的方法

问题

在android 9.0系统上如果多个进程使用WebView需要使用官方提供的api在子进程中给webview的数据文件夹设置后缀:


WebView.setDataDirectorySuffix(suffix);

否则将会报出以下错误:


Using WebView from more than one process at once with the same data directory is not supported. https://crbug.com/558377

1 com.android.webview.chromium.WebViewChromiumAwInit.startChromiumLocked(WebViewChromiumAwInit.java:63)
2 com.android.webview.chromium.WebViewChromiumAwInitForP.startChromiumLocked(WebViewChromiumAwInitForP.java:3)
3 com.android.webview.chromium.WebViewChromiumAwInit$3.run(WebViewChromiumAwInit.java:3)
4 android.os.Handler.handleCallback(Handler.java:873)
5 android.os.Handler.dispatchMessage(Handler.java:99)
6 android.os.Looper.loop(Looper.java:220)
7 android.app.ActivityThread.main(ActivityThread.java:7437)
8 java.lang.reflect.Method.invoke(Native Method)
9 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:500)
10 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:865)

通过使用官方提供的方法后问题只减少了一部分,从bugly后台依然能收到此问题的大量崩溃信息,以至于都冲上了崩溃问题Top3。

问题分析

从源码分析调用链最终调用到了AwDataDirLock类中的lock方法。


public class WebViewChromiumAwInit {
 protected void startChromiumLocked() {
   ...
   AwBrowserProcess.start();
   ... 
 }
}
public final class AwBrowserProcess {
 public static void start() {
   ...
   AwDataDirLock.lock(appContext);
}

AwDataDirLock.java


abstract class AwDataDirLock {
 private static final String TAG = "AwDataDirLock";
 private static final String EXCLUSIVE_LOCK_FILE = "webview_data.lock";
 // This results in a maximum wait time of 1.5s
 private static final int LOCK_RETRIES = 16;
 private static final int LOCK_SLEEP_MS = 100;
 private static RandomAccessFile sLockFile;
 private static FileLock sExclusiveFileLock;

 static void lock(final Context appContext) {
  try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("AwDataDirLock.lock");
    StrictModeContext ignored = StrictModeContext.allowDiskWrites()) {
   if (sExclusiveFileLock != null) {
    // We have already called lock() and successfully acquired the lock in this process.
    // This shouldn't happen, but is likely to be the result of an app catching an
    // exception thrown during initialization and discarding it, causing us to later
    // attempt to initialize WebView again. There's no real advantage to failing the
    // locking code when this happens; we may as well count this as the lock being
    // acquired and let init continue (though the app may experience other problems
    // later).
    return;
   }
   // If we already called lock() but didn't succeed in getting the lock, it's possible the
   // app caught the exception and tried again later. As above, there's no real advantage
   // to failing here, so only open the lock file if we didn't already open it before.
   if (sLockFile == null) {
    String dataPath = PathUtils.getDataDirectory();
    File lockFile = new File(dataPath, EXCLUSIVE_LOCK_FILE);
    try {
   // Note that the file is kept open intentionally.
     sLockFile = new RandomAccessFile(lockFile, "rw");
    } catch (IOException e) {
    // Failing to create the lock file is always fatal; even if multiple processes
    // are using the same data directory we should always be able to access the file
    // itself.
     throw new RuntimeException("Failed to create lock file " + lockFile, e);
    }
   }
   // Android versions before 11 have edge cases where a new instance of an app process can
   // be started while an existing one is still in the process of being killed. This can
   // still happen on Android 11+ because the platform has a timeout for waiting, but it's
   // much less likely. Retry the lock a few times to give the old process time to fully go
   // away.
   for (int attempts = 1; attempts <= LOCK_RETRIES; ++attempts) {
    try {
     sExclusiveFileLock = sLockFile.getChannel().tryLock();
    } catch (IOException e) {
    // Older versions of Android incorrectly throw IOException when the flock()
    // call fails with EAGAIN, instead of returning null. Just ignore it.
    }
    if (sExclusiveFileLock != null) {
     // We got the lock; write out info for debugging.
     writeCurrentProcessInfo(sLockFile);
     return;
    }
    // If we're not out of retries, sleep and try again.
    if (attempts == LOCK_RETRIES) break;
    try {
     Thread.sleep(LOCK_SLEEP_MS);
    } catch (InterruptedException e) {
    }
   }
   // We failed to get the lock even after retrying.
   // Many existing apps rely on this even though it's known to be unsafe.
   // Make it fatal when on P for apps that target P or higher
   String error = getLockFailureReason(sLockFile);
   boolean dieOnFailure = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
     && appContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P;
   if (dieOnFailure) {
    throw new RuntimeException(error);
   } else {
    Log.w(TAG, error);
   }
  }
 }

 private static void writeCurrentProcessInfo(final RandomAccessFile file) {
  try {
   // Truncate the file first to get rid of old data.
   file.setLength(0);
   file.writeInt(Process.myPid());
   file.writeUTF(ContextUtils.getProcessName());
  } catch (IOException e) {
   // Don't crash just because something failed here, as it's only for debugging.
   Log.w(TAG, "Failed to write info to lock file", e);
  }
 }

 private static String getLockFailureReason(final RandomAccessFile file) {
  final StringBuilder error = new StringBuilder("Using WebView from more than one process at "
    + "once with the same data directory is not supported. https://crbug.com/558377 "
    + ": Current process ");
  error.append(ContextUtils.getProcessName());
  error.append(" (pid ").append(Process.myPid()).append("), lock owner ");
  try {
   int pid = file.readInt();
   String processName = file.readUTF();
   error.append(processName).append(" (pid ").append(pid).append(")");
   // Check the status of the pid holding the lock by sending it a null signal.
   // This doesn't actually send a signal, just runs the kernel access checks.
   try {
    Os.kill(pid, 0);
    // No exception means the process exists and has the same uid as us, so is
    // probably an instance of the same app. Leave the message alone.
   } catch (ErrnoException e) {
    if (e.errno == OsConstants.Eclass="lazy" data-srcH) {
     // pid did not exist - the lock should have been released by the kernel,
     // so this process info is probably wrong.
     error.append(" doesn't exist!");
    } else if (e.errno == OsConstants.EPERM) {
     // pid existed but didn't have the same uid as us.
     // Most likely the pid has just been recycled for a new process
     error.append(" pid has been reused!");
    } else {
     // EINVAL is the only other documented return value for kill(2) and should never
     // happen for signal 0, so just complain generally.
     error.append(" status unknown!");
    }
   }
  } catch (IOException e) {
   // We'll get IOException if we failed to read the pid and process name; e.g. if the
   // lockfile is from an old version of WebView or an IO error occurred somewhere.
   error.append(" unknown");
  }
  return error.toString();
 }
}

lock方法会对webview数据目录中的webview_data.lock文件在for循环中尝试加锁16次,注释中也说明了这么做的原因:可能出现的极端情况是一个旧进程正在被杀死时一个新的进程启动了,看来Google工程师对这个问题也很头痛;如果加锁成功会将该进程id和进程名写入到文件,如果加锁失败则会抛出异常。所以在android9.0以上检测应用是否存在多进程共用WebView数据目录的原理就是进程持有WebView数据目录中的webview_data.lock文件的锁。所以如果子进程也对相同文件尝试加锁则会导致应用崩溃。

解决方案

目前大部分手机会在应用崩溃时自动重启应用,猜测当手机系统运行较慢时这时就会出现注释中提到的当一个旧进程正在被杀死时一个新的进程启动了的情况。既然获取文件锁失败就会发生崩溃,并且该文件只是用于加锁判断是否存在多进程共用WebView数据目录,每次加锁成功都会重新写入对应进程信息,那么我们可以在应用启动时对该文件尝试加锁,如果加锁失败就删除该文件并重新创建,加锁成功就立即释放锁,这样当系统尝试加锁时理论上是可以加锁成功的,也就避免了这个问题的发生。


private static void handleWebviewDir(Context context) {
  if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
   return;
  }
  try {
   String suffix = "";
   String processName = getProcessName(context);
   if (!TextUtils.equals(context.getPackageName(), processName)) {//判断不等于默认进程名称
    suffix = TextUtils.isEmpty(processName) ? context.getPackageName() : processName;
    WebView.setDataDirectorySuffix(suffix);
    suffix = "_" + suffix;
   }
   tryLockOrRecreateFile(context,suffix);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 @TargetApi(Build.VERSION_CODES.P)
 private static void tryLockOrRecreateFile(Context context,String suffix) {
  String sb = context.getDataDir().getAbsolutePath() +
    "/app_webview"+suffix+"/webview_data.lock";
  File file = new File(sb);
  if (file.exists()) {
   try {
    FileLock tryLock = new RandomAccessFile(file, "rw").getChannel().tryLock();
    if (tryLock != null) {
     tryLock.close();
    } else {
     createFile(file, file.delete());
    }
   } catch (Exception e) {
    e.printStackTrace();
    boolean deleted = false;
    if (file.exists()) {
     deleted = file.delete();
    }
    createFile(file, deleted);
   }
  }
 }

 private static void createFile(File file, boolean deleted){
  try {
   if (deleted && !file.exists()) {
    file.createNewFile();
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

使用此方案应用上线后该问题崩溃次数减少了90%以上。也许Google工程师应该考虑下换一种技术方案检测应用是否存在多进程共用WebView数据目录。

以上就是Android 解决WebView多进程崩溃的方法的详细内容,更多关于Android 解决WebView多进程崩溃的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android 解决WebView多进程崩溃的方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android如何解决WebView多进程崩溃的问题

小编给大家分享一下Android如何解决WebView多进程崩溃的问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!问题在android 9.0系统上如果多个进程
2023-06-14

Chrome 78标签页意外崩溃的解决方法

Chrome 78标签页意外崩溃的解决方法,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。如果你在将浏览器更新至 Chrome 78 后遇到了标签页显示“Aw,Snap!”错
2023-06-16

Android 6.0调用相机图册崩溃的完美解决方案

最近客户更新系统发现,以前的项目在调用相机的时候,闪退掉了,很奇怪,后来查阅后发现,Android 6.0以后需要程序授权相机权限,默认会给出提示,让用户授权,个人感觉这一特性很好,大概如下: 导入Android V4, V7包! Andr
2022-06-06

android webview 中localStorage无效的解决方法

我在 android里面 使用html5的 localStorage 为什么存不进去也读不出来呀 网上搜了好多都没效果代码如下: mainWebView = (WebView)this.findViewById(R.id.mainWebV
2022-06-06

阿里云服务器崩溃的原因及解决方法

阿里云服务器是一种基于云计算技术的高性能计算服务,广泛应用于企业级的信息化建设。然而,最近有用户反映阿里云服务器崩溃了,这给用户带来了诸多不便。那么,阿里云服务器崩溃的原因是什么呢?我们应该如何解决这个问题呢?本文将对此进行详细说明。阿里云服务器崩溃的原因主要有以下几点:系统错误:阿里云服务器的运行依赖于一个稳定
阿里云服务器崩溃的原因及解决方法
2023-12-14

win10游戏崩溃的原因及解决方法是什么

Win10游戏崩溃的原因可能有很多,包括以下几点:1. 硬件问题:游戏过于占用系统资源,导致硬件性能不足而崩溃。解决方法:升级硬件,如增加内存、更换显卡等。2. 软件冲突:与其他软件或驱动程序发生冲突,导致游戏崩溃。解决方法:关闭或卸载与游
2023-08-30

Android编程实现WebView添加进度条的方法

本文实例讲述了Android编程实现WebView添加进度条的方法。分享给大家供大家参考,具体如下: 标准的XML界面
2022-06-06

win10手机预览版10080 Cortana搜索崩溃的解决方法

微软已向Windows Insider用户推送最新jswin10手机预览版10080更新,并公布win10手机预览版10080已知Bug汇总,其中有Cortana微软小娜遭遇一部分问android题。下文一起来看看win10手机预览版100
2023-06-15

阿里云服务器数据库老崩溃的解决方法

随着云计算技术的发展,越来越多的企业和个人开始使用阿里云服务器。然而,随着服务器的使用,可能会出现一些问题,如数据库老崩溃。这篇文章将详细介绍如何解决阿里云服务器数据库老崩溃的问题。一、问题原因分析资源不足:阿里云服务器的数据库运行需要足够的资源,如内存、CPU等。如果服务器的资源不足,数据库可能会出现崩溃。数据
阿里云服务器数据库老崩溃的解决方法
2023-10-28

Linux上定位后台服务偶发崩溃的解决方法

问题描述 在最近的后台服务中,新增将某个指令的请求数据落盘保存的功能。在具体实现时,采用成员变量来保存请求消息代理头,在接收响应以及消息管理类释放时进行销毁。测试反馈,该服务偶发崩溃。 问题分析 测试环境上运行的是rel版程序,由于在编译时
2022-06-03

Win8.1下IE11浏览器无响应崩溃问题的解决方法

还有一周的时间,Windows 8.1将向全球发行,所有零售版的Windows8用户将可以获得免费升级。相信有不少爱好者已经升级到Windows 8.1 RTM系统。由于IE11浏览器对于目前的网页和插件类存在着兼容性问题,因此经常会遇到I
2022-06-04

Win7复制大文件时突然崩溃的可行解决方法

Win7在复制大文件的过程中,相信很多朋友都有遇到系统突然崩溃的问题,这种情况出现时总会让很多人惊出一身冷汗,特别是程序显示“未响应”时,那真是一点补救的方法都没有,因此为了防止这种情况的发生,我们应当事先做一些工作
2023-06-11

MySQL数据库崩溃的常见原因和解决方法是什么

这篇“MySQL数据库崩溃的常见原因和解决方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MySQL数据库崩溃的常见
2023-07-05

win8下火狐安装firebug调试程序后打开崩溃的问题解决方法

自编程从装了win8以来,不是蓝屏就是死机,然后就是触摸板不能用,再又是USB接口突然不灵了。如果说之前的种种问题还是可以可以解决的吧,今天调试程序,要装个火狐的(主要是用firebug)调试网站,装好了刚打开就提示编程客栈崩溃,以为是火狐
2023-06-04

Android编程使WebView支持HTML5 Video全屏播放的解决方法

本文实例讲述了Android编程使WebView支持HTML5 Video全屏播放的解决方法。分享给大家供大家参考,具体如下: 1)需要在AndroidManifest.xml文件中声明需要使用HardwareAccelerate, 可以细
2022-06-06

Win7系统打开计算机管理导致explore.exe崩溃的解决方法

许多用户都会对“计算机管理”进行设置某项功python能。在win7系统中右键电脑图标选择管理调用设备管理器这个工具的时候,出现了桌面崩溃,而无法正常使用计算机管理工具。使用管理工具而导致桌面explore.exe崩
2023-06-08

Win8.1资源管理器崩溃或重启从软件方面解决的可行方法

微软最新推出的Win8.1系统可谓问题不断,经常有用户出现安装以及各类使用问题,近期又发现不少升级Win8.1用户出现了资源管理器崩溃或重启的问题。针对此问题,小编研究与整理了一些网上比较可行的解决办法,遇到此类问题的朋友不妨试试,或许可以
2022-06-04

解决MongoDB技术开发中遇到的崩溃恢复问题的方法研究

解决MongoDB技术开发中遇到的崩溃恢复问题的方法研究摘要:MongoDB作为一种非关系型数据库,具有高性能、高可扩展性等特点,并被广泛应用于各种大数据项目。然而,由于其特殊的存储引擎和分布式架构,MongoDB的开发过程中可能会出现崩溃
2023-10-22

掌握xp系统的还原方法轻松解决系统崩溃或是中毒

电脑在很多时候也不是万能的,它们时常会因为某些问题,而导致系统崩溃,或是中毒等等,所以xp电脑用户们,要是能够掌握住xp系统的还原方法,那用起电脑来就能够更加的得心http://www.cppcns.com应手js。 1、用还原卡(硬件)还
2023-05-31

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录