Skip to content

[Android] Guard PlatformViewsController2.onEndFrame against a detached FlutterView - #190612

Merged
auto-submit[bot] merged 3 commits into
flutter:masterfrom
amaan-0331:hcpp-onendframe-null-guard
Aug 19, 2026
Merged

auto-submit[bot] merged 3 commits into
flutter:masterfrom
amaan-0331:hcpp-onendframe-null-guard

Conversation

@amaan-0331

@amaan-0331 amaan-0331 commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

PlatformViewsController2.onEndFrame() dereferenced flutterView and the result of
flutterView.getRootSurfaceControl() without checking either for null.

AndroidExternalViewEmbedder2::SubmitFlutterView() posts onEndFrame2() from the raster thread to
the platform thread on every frame, including frames with no platform layers. By the time the task
runs, the FlutterView may have been detached from the controller, in which case
detachFromView() has set flutterView to null, or detached from its window, in which case
View.getRootSurfaceControl() returns null.

The resulting NullPointerException is not merely logged. The JNI call ends with
FML_CHECK(fml::jni::CheckException(env)), which converts the pending Java exception into an
abort(). This terminates the process with no Dart-side recovery or application-level workaround
other than disabling HCPP.

This change guards both nullable values and closes the merged SurfaceControl.Transaction before
returning early so that it is not leaked. It also moves flutterView.invalidate() below the guard,
because that call was itself unsafe when flutterView was null.

The issue reproduces on every warm teardown when an HCPP platform view is visible and the
FlutterEngine outlives its activity. In a 10-launch loop, the unpatched embedding produced five
aborts because every abort killed the process and made the following launch a cold start.

Verified locally on an Android 16 emulator by compiling the patched class into the prebuilt
embedding JAR: 0 aborts across 12 teardowns. Platform-view rendering continued to work after
reattaching the engine. The reproduction app and full before-and-after logs are included in the
linked issue.

Fixes #190609

Pre-launch Checklist

…d FlutterView

onEndFrame() runs on the platform thread but is posted from the raster
thread by AndroidExternalViewEmbedder2::SubmitFlutterView, on every frame
including frames with no platform layers. By the time it runs the
FlutterView may have been detached from the controller, or detached from
its window -- and View.getRootSurfaceControl() returns null when the view
is not attached to a window. Neither case was guarded.

The resulting NullPointerException is not merely logged: the JNI caller,
onEndFrame2(), ends with FML_CHECK(fml::jni::CheckException(env)), which
turns any pending Java exception into abort(). There is no Dart-side
recovery, so this takes down the process.

Null-check both, and close the merged transaction on the early return so
it does not leak.
@amaan-0331
amaan-0331 requested a review from a team as a code owner August 5, 2026 11:11
@amaan-0331
amaan-0331 requested review from jesswrd and removed request for a team August 5, 2026 11:11
@github-actions github-actions Bot added platform-android Android applications specifically engine flutter/engine related. See also e: labels. team-android Owned by Android platform team labels Aug 5, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates PlatformViewsController2.java to prevent potential crashes during onEndFrame() when the FlutterView is detached or its root surface control is null. It introduces null checks for flutterView and its root surface control, closing the transaction and returning early if either is null. Additionally, corresponding unit tests are added in PlatformViewsController2Test.java to verify this behavior. I have no further feedback to provide.

@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 11, 2026
@gmackall gmackall added the CICD Run CI/CD label Aug 18, 2026
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 18, 2026

@gmackall gmackall left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm, thanks for the pr and investigation

@gmackall gmackall added the CICD Run CI/CD label Aug 18, 2026
@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 18, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Aug 18, 2026
Merged via the queue into flutter:master with commit 8bcda46 Aug 19, 2026
29 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 19, 2026
MylioScott pushed a commit to mylollc/flutter that referenced this pull request Oct 14, 2026
…d FlutterView (flutter#190612)

`PlatformViewsController2.onEndFrame()` dereferenced `flutterView` and
the result of `flutterView.getRootSurfaceControl()` without checking
either for null.

`AndroidExternalViewEmbedder2::SubmitFlutterView()` posts `onEndFrame2()`
from the raster thread to the platform thread on every frame, including
frames with no platform layers. By the time the task runs, the
`FlutterView` may have been detached from the controller, in which case
`detachFromView()` has set `flutterView` to null, or detached from its
window, in which case `View.getRootSurfaceControl()` returns null.

The resulting `NullPointerException` is not merely logged. The JNI call
ends with `FML_CHECK(fml::jni::CheckException(env))`, which converts the
pending Java exception into an `abort()`.

This change guards both nullable values and closes the merged
`SurfaceControl.Transaction` before returning early so that it is not
leaked. It also moves `flutterView.invalidate()` below the guard.

Fixes flutter#190609

(cherry picked from commit 8bcda46)
Cherry-pick note: the import hunk was placed by hand because this branch
does not carry flutter#184732 (rect clipping for surface views); nothing else
changed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-android Android applications specifically team-android Owned by Android platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] HCPP: PlatformViewsController2.onEndFrame() aborts the process when it runs after the FlutterView detaches

3 participants