Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -581,12 +581,32 @@ class WebViewActivity :
}

override fun onRenderProcessGone(view: WebView?, handler: RenderProcessGoneDetail?): Boolean {
Timber.e("onRenderProcessGone: webView crashed")
view?.let {
reload()
lifecycleScope.launch {
webViewAddJavascriptInterface()
val didCrash = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
handler?.didCrash() == true
} else {
// On API < 26 didCrash() is unavailable; treat as a crash so we still recover.
true
}
Comment on lines +584 to +589
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API < 26 branch/comment is misleading: framework WebViewClient.onRenderProcessGone(...) is only invoked on API ≥ 26, so this branch won’t run in practice. Consider simplifying to val didCrash = handler?.didCrash() == true and updating the comment accordingly (or rewording it as a defensive fallback for unexpected/null detail rather than an API-level behavior).

Suggested change
val didCrash = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
handler?.didCrash() == true
} else {
// On API < 26 didCrash() is unavailable; treat as a crash so we still recover.
true
}
val didCrash = handler?.didCrash() == true

Copilot uses AI. Check for mistakes.
Timber.e(
"onRenderProcessGone: WebView renderer is gone (didCrash=$didCrash). " +
"This is commonly triggered by a GPU context loss or out-of-memory in the " +
"renderer process (see #5823 — Mali GPU + EXT_robustness on Android 10), " +
"which can leave dashboard cards rendering as blank/greyed-out surfaces. " +
"Recreating the activity to recover with a fresh WebView.",
)
// Per the android.webkit.WebView contract, once the render process is gone the
// WebView instance is unusable and must not be touched again — calling reload()
// on the dead WebView is a no-op and leaves the user looking at greyed-out
// cards forever. Detach and destroy the dead WebView so its native resources
// are released, then recreate the activity to rebuild a fresh WebView and
// reload the last URL through the normal onCreate path. Returning `true` tells
// the system we have handled the crash so the hosting app process is not killed.
if (!isFinishing && !isRelaunching) {
view?.let { dead ->
(dead.parent as? android.view.ViewGroup)?.removeView(dead)
dead.destroy()
}
recreate()
}
Comment on lines +604 to 610
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling recreate() unconditionally on every onRenderProcessGone can lead to a fast recreation loop if the renderer keeps getting killed immediately (e.g., persistent GPU/driver failure), which can degrade UX and battery and potentially make the app unusable. Consider adding a simple guard/backoff (e.g., only recreate once per activity instance, or rate-limit recreations using a timestamp in savedInstanceState / a field) and fall back to finishing the activity or showing an error state if it repeats.

Copilot uses AI. Check for mistakes.

return true
Expand Down
Loading