Fix #45: prevent and contain multi-process WebView data-dir crash#60
Open
jim-daf wants to merge 2 commits into
Open
Fix #45: prevent and contain multi-process WebView data-dir crash#60jim-daf wants to merge 2 commits into
jim-daf wants to merge 2 commits into
Conversation
Sets a per-process WebView data directory suffix in MyApplication.onCreate so that secondary processes (typically isolated services started by Firebase / WorkManager / third party SDKs) don't trip https://crbug.com/558377: java.lang.RuntimeException: Using WebView from more than one process at once with the same data directory is not supported. Uses Application.getProcessName() (API 28+) and only applies the suffix when the current process is NOT the main app process, so the main UI process keeps using the default data dir and existing WebView storage is preserved.
The setDataDirectorySuffix workaround only helps when the colliding processes have different names. The Crashlytics report in flamyoad#45 actually shows two processes with the same name (com.flamyoad.honnoki / com.flamyoad.honnoki), which means the lock collision is most likely a stale data-dir lock left by a previously-killed instance, or a WebView provider swap mid-run. Neither is fixable by a suffix. Install a narrow Thread.setDefaultUncaughtExceptionHandler that recognises this exact RuntimeException (matched by message walk through the cause chain), logs it via Timber, and silently kills the current process so the OS releases the file lock and ActivityManager can restart any foreground component cleanly. All other exceptions are forwarded to the previous default handler (Crashlytics) untouched.
There was a problem hiding this comment.
Pull request overview
Mitigates the Android WebView multi-process “same data directory” crash (crbug.com/558377 / Issue #45) by configuring per-process WebView data dirs and adding a narrowly-scoped uncaught-exception backstop early in Application.onCreate().
Changes:
- Install a default
UncaughtExceptionHandlerthat detects the specific WebView data-dir collision crash and terminates the current process to allow a clean restart. - On API 28+, apply
WebView.setDataDirectorySuffix(...)for non-main processes to prevent cross-process WebView data directory collisions.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| */ | ||
| private fun applyWebViewDataDirectorySuffix() { | ||
| if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return | ||
| val processName = getProcessName() ?: return |
Owner
|
? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #45.
What
Two-layer mitigation for:
Both layers live in
MyApplication.onCreate()so they are wired up before any code that could lazily touch a WebView.Layer 1 — Per-process data-dir suffix (preventive)
This is the Google-documented workaround (
WebView.setDataDirectorySuffix). It fixes the common case where the collision is between the main process and a secondary:somethingprocess started by a transitive dependency (Firebase, WorkManager, a webkit-backed third-party SDK, etc.).The suffix is applied only in non-main processes, so the main UI process keeps using the default data directory and existing WebView storage / cookies are left untouched. Pre-API-28 devices skip the call.
Layer 2 — Narrow
UncaughtExceptionHandler(defensive)The Crashlytics report attached to #45 actually shows two processes with the same name (
com.flamyoad.honnoki/com.flamyoad.honnoki). That points at one of two things the suffix can't fix:AwBrowserProcessstartups.In those cases, letting the exception propagate kills the app with a user-visible "App keeps stopping" dialog and another Crashlytics record. Layer 2 installs a narrow handler that recognises this specific exception by walking the cause chain for the message
Using WebView from more than one process, logs it via Timber, and silently kills the current process viaProcess.killProcess+exitProcess. Android'sActivityManagerwill then restart any foreground component cleanly, by which time the OS has released the file lock.Every other exception is forwarded to the previous default handler (Crashlytics, etc.) untouched, so unrelated crashes still get reported normally.
Why both layers?
The result: in every code path that historically produced this exception, the user no longer sees a crash dialog and you no longer get a hard Crashlytics record for this signature.
Risk
Very low.
RuntimeExceptionmessage string. Anything else flows through to the previous default handler.Application.getProcessName()is framework-provided since API 28).Pattern source
Layer 1 matches a recurring fix pattern mined from
Justson/AgentWebPR #655 (issues #542 / #646), adapted to use the frameworkApplication.getProcessName()API instead of AgentWeb'sProcessUtilshelper so it drops in without any extra utility class. Layer 2 is the standard hardening that complements that pattern when the colliding processes share a name.