Skip to content

fix(DefaultUIController): guard SSL-error dialog against finishing activity (#1065)#1081

Open
jim-daf wants to merge 1 commit intoJustson:androidxfrom
jim-daf:fix/security-issue-1065
Open

fix(DefaultUIController): guard SSL-error dialog against finishing activity (#1065)#1081
jim-daf wants to merge 1 commit intoJustson:androidxfrom
jim-daf:fix/security-issue-1065

Conversation

@jim-daf
Copy link
Copy Markdown

@jim-daf jim-daf commented Apr 19, 2026

Guard the SSL-error dialog against a finishing/destroyed activity

Resolves #1065 - WindowManager$BadTokenException from
DefaultUIController.onShowSslCertificateErrorDialog.

What was happening

The crash trace in the issue ends in AlertDialog$Builder.show(...) from
DefaultUIController.onShowSslCertificateErrorDialog. The reporter notes
that the surrounding methods (e.g. onLoading, onCancelLoading) already
guard against Activity#isFinishing, but onShowSslCertificateErrorDialog
did not. Because WebView delivers onReceivedSslError on the main thread
asynchronously, mActivity may have started its finish/destroy teardown
before the dialog is shown, and adding a window with a stale token throws
BadTokenException.

Fix

agentweb-core/src/main/java/com/just/agentweb/DefaultUIController.java:

  1. Before building the dialog, return early with handler.cancel() if
    mActivity is null, isFinishing(), or (API ≥17) isDestroyed().
  2. Re-run the same check immediately before AlertDialog.show() to close
    the small race between building the dialog and showing it.
  3. Wrap the show() call in a try/catch for
    WindowManager.BadTokenException and IllegalStateException so any
    residual race fails safely rather than crashing.

Failing safe means cancelling the SSL request, i.e. not silently
accepting an untrusted certificate when we can't ask the user.

…tivity (Justson#1065)

Resolves Justson#1065

The crash reported in Justson#1065 is a WindowManager$BadTokenException raised
from DefaultUIController.onShowSslCertificateErrorDialog when AlertDialog
is shown after the hosting Activity has already started its
finishing/destroyed teardown. The WebView delivers SSL error callbacks
on the main thread and there is no guarantee the cached mActivity is
still in a state where it can host a dialog.

This change short-circuits the path when the activity is null, finishing,
or destroyed, calling handler.cancel() in that case so we fail safe
rather than crash. The same check is repeated immediately before
AlertDialog.show(), and the show() call itself is wrapped in a try/catch
for the residual race where the activity transitions between our last
check and the platform call.
@jim-daf jim-daf changed the title fix: secure SSL error handling (3 files) fix(DefaultUIController): guard SSL-error dialog against finishing activity (#1065) Apr 21, 2026
@jim-daf jim-daf force-pushed the fix/security-issue-1065 branch from 302a5dc to 40aa5c0 Compare April 21, 2026 19:54
@jim-daf jim-daf marked this pull request as ready for review April 21, 2026 20:43
Copilot AI review requested due to automatic review settings April 21, 2026 20:43
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a crash (WindowManager$BadTokenException) when showing the SSL certificate error dialog after the hosting Activity has begun finishing/destroying (Issue #1065), by failing safe (cancelling the SSL request) when UI can’t be safely shown.

Changes:

  • Adds an early guard to cancel the SSL request if the Activity is null/finishing/destroyed before building the dialog.
  • Adds a second guard immediately before show() to reduce the race window.
  • Wraps AlertDialog.show() in a try/catch to safely handle residual BadTokenException / IllegalStateException cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +374 to +378
if (mActivity == null || mActivity.isFinishing()
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())) {
handler.cancel();
return;
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

Elsewhere in this class you copy this.mActivity into a local Activity mActivity before checking/using it (e.g., onLoading()), which avoids repeated field reads and makes the null/finishing/destroyed checks consistent. Here the method uses the field directly and later calls mActivity.isFinishing() again without a null check; consider adopting the same local-variable pattern (and include activity == null in the second guard) for consistency and to avoid potential NPEs if mActivity changes.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

友盟上统计了个崩溃

2 participants