日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Android 解決WebView多進程崩潰的方法

瀏覽:112日期:2022-09-20 13:33:38
問題

在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/5583771 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.ESRCH) { // 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多進程崩潰的資料請關注好吧啦網其它相關文章!

標簽: Android
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美天堂在线| 国产精品久久久久久妇女| 嫩呦国产一区二区三区av| 精品久久久中文字幕| 激情欧美国产欧美| 视频一区日韩精品| 男女男精品网站| 岛国av免费在线观看| 在线 亚洲欧美在线综合一区| 精品一区二区三区在线观看视频| 视频一区日韩精品| 欧美精品三级在线| 欧产日产国产精品视频| 亚洲精品高潮| 日韩和欧美的一区| 久久国产精品美女| 欧美特黄一区| 国产美女高潮在线| 日韩大片在线| 亚洲手机在线| 久久激五月天综合精品| 欧产日产国产精品视频| 亚洲精品日本| 久久精品国产大片免费观看| 9国产精品视频| 久久精品三级| 欧美日韩免费观看一区=区三区| 韩国精品主播一区二区在线观看| 捆绑调教美女网站视频一区| 日韩高清中文字幕一区| 日韩精品久久久久久久电影99爱| 日韩欧美中文| 91免费精品国偷自产在线在线| 香蕉成人久久| 欧美日韩一区二区国产| 久久久成人网| 中文字幕一区二区三区在线视频| 亚洲国产福利| 狠狠干综合网| 日产精品一区| 日本在线成人| 久久久成人网| 国产视频一区在线观看一区免费| 国产精品人人爽人人做我的可爱| 国产毛片久久久| 99久久99视频只有精品| 97精品国产福利一区二区三区| 国产毛片精品久久| 日本不卡视频在线| 亚洲午夜av| 亚洲欧洲午夜| 日韩欧美另类一区二区| 久久九九电影| 国产午夜精品一区二区三区欧美 | 成人精品高清在线视频| 精品成人18| 国内亚洲精品| 蜜臀av在线播放一区二区三区| 亚洲一二三区视频| 国产精品久久久久久久免费软件| 国产第一亚洲| 欧美日韩激情| 日韩精品三级| 日本一区二区高清不卡| 美女av在线免费看| 亚洲欧美成人综合| 国产精品一级| 久久精品成人| 国产欧美三级| 欧美亚洲国产一区| 亚洲免费福利一区| 日韩一区二区三区精品视频第3页 日韩一区二区三区免费视频 | 国产成人77亚洲精品www| 国产欧美另类| 国产精品国码视频| 成人影视亚洲图片在线| 99精品视频在线观看免费播放| 精品日韩一区| 国产视频一区免费看| 青青草91视频| 日韩欧美综合| 蜜臀av性久久久久蜜臀aⅴ流畅 | 伊人久久大香伊蕉在人线观看热v| 国产不卡精品在线| 91成人在线| 成人福利av| 日韩激情一区| 免费av一区二区三区四区| 国产调教一区二区三区| 久久精品91| av不卡在线| 91精品国产91久久久久久黑人| 日本中文字幕不卡| 亚洲精品2区| 欧美日韩国产欧| 蜜臀精品久久久久久蜜臀| 免费成人在线视频观看| 亚洲永久精品唐人导航网址| 亚洲精品无播放器在线播放| 久久只有精品| 蜜桃久久久久久| 国产精品亚洲成在人线| 99精品视频在线观看免费播放| 亚洲一区二区三区无吗| 精品久久一区| 91欧美日韩在线| 石原莉奈一区二区三区在线观看| 欧美丰满日韩| 麻豆精品av| 日本午夜精品一区二区三区电影| av资源新版天堂在线| 91成人福利| 麻豆一区二区三| 黄色免费成人| 夜夜嗨网站十八久久| 国产美女精品视频免费播放软件| 青青草精品视频| 日韩在线观看| 欧美一级网址| 国产精品一国产精品| 日本va欧美va瓶| 国产精品美女久久久| 国产精品yjizz视频网| 伊人久久亚洲热| av资源亚洲| 麻豆精品在线| 日韩不卡一二三区| 视频一区中文字幕国产| 国产91一区| 成人精品动漫一区二区三区| 久久不卡国产精品一区二区| 国产高清不卡| 日韩1区在线| 日韩精品午夜| 国产精品白浆| 国产欧美丝祙| 狠狠干综合网| 日韩综合一区二区| 视频一区视频二区在线观看| 精品中文字幕一区二区三区| 国产欧美日韩精品一区二区免费| 国产乱人伦丫前精品视频| 亚洲精品自拍| 麻豆久久一区| 老司机久久99久久精品播放免费| 免费av一区| 亚洲一级少妇| 秋霞影院一区二区三区| 亚洲不卡av不卡一区二区| 蜜臀av免费一区二区三区| 免费日韩av片| 国产亚洲一区二区三区啪| 国产精品日本一区二区不卡视频| 麻豆精品久久久| 免费欧美一区| 日韩一二三区在线观看| 精品精品99| 亚洲资源av| 欧美日韩亚洲一区| 神马午夜在线视频| 亚洲深夜福利在线观看| 亚洲一区二区三区中文字幕在线观看| 日韩中文字幕av电影| 国产精品一区二区免费福利视频| 精品久久影院| 国产精品日韩欧美一区| 国产精品99久久免费| 日韩在线短视频| 日韩黄色免费网站| 欧美国产美女| 91亚洲精品在看在线观看高清| 麻豆精品蜜桃| 日本电影久久久| 99热精品久久| 青青草91久久久久久久久| 久久三级视频| 日韩一二三区在线观看| 久久精品亚洲人成影院| 国产欧美日韩一区二区三区在线| 欧美日中文字幕| 精品一区二区三区的国产在线观看| 国产精品日本欧美一区二区三区| 麻豆精品视频在线观看视频| 亚洲三级国产| 蜜桃久久av一区| 99视频在线精品国自产拍免费观看| 精品亚洲a∨| 久久av网址| 国产精区一区二区| 日韩欧美久久| 日韩一区精品| 日韩欧美三区| 久久xxxx| 99tv成人| 欧美日韩三区| 日韩午夜一区| 亚洲一卡久久| 一本一道久久a久久| 蜜桃视频一区二区| 亚洲欧美网站在线观看|