Skip to content

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

Closed

Description

@amaan-0331

Steps to reproduce

Reproducible app: https://github.com/amaan-0331/hcpp-onendframe-crash-repro

Requires Android 14+ (API 34) and a Vulkan-capable device or emulator. HCPP silently no-ops on the
Impeller OpenGLES backend, so the repro sets io.flutter.embedding.android.ImpellerBackend to
vulkan alongside EnableHcpp.

  1. flutter run the repro app. Confirm it shows "HCPP supported: true" and a blue native view.
  2. Press back to finish the activity.
  3. Launch the app again, wait for the native view to render, and press back again.

Or run ./repro.sh, which drives the same loop and reports aborts.

The app registers a trivial Kotlin PlatformView (a TextView), creates it with
PlatformViewsService.initHybridAndroidView, and caches the FlutterEngine in
Application.onCreate so the engine outlives the activity. No third-party plugins are involved.

Expected results

Destroying the activity while an HCPP platform view is on screen tears down cleanly.

Actual results

The process aborts. Every teardown where the platform view had rendered crashes — 5 aborts in 10
iterations of the loop above, which is every warm teardown (each abort kills the process, so the
following launch is a cold start with no platform view yet, and does not crash).

PlatformViewsController2.onEndFrame() dereferences the result of getRootSurfaceControl() with no
null check:

// PlatformViewsController2.java:669
@RequiresApi(API_LEVELS.API_34)
public void onEndFrame() {
  SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
  for (int i = 0; i < activeTransactions.size(); i++) {
    tx = tx.merge(activeTransactions.get(i));
  }
  activeTransactions.clear();
  flutterView.invalidate();
  flutterView.getRootSurfaceControl().applyTransactionOnDraw(tx);   // <-- NPE
}

AndroidExternalViewEmbedder2::SubmitFlutterView posts onEndFrame2() from the raster thread to the
platform thread on every frame, including frames with no platform layers
(external_view_embedder_2.cc:73-91 and :168-203). By the time that task runs on the main looper
the FlutterView may no longer be attached to a window, and View.getRootSurfaceControl() is
documented to return null in that case. flutterView itself can also be null, since
detachFromView() (:269) nulls it without any corresponding guard here.

The resulting exception is not merely logged — the JNI caller ends with
FML_CHECK(fml::jni::CheckException(env)) (platform_view_android_jni_impl.cc:2370), which turns
any pending Java exception into abort(). There is no Dart-side recovery and no application-level
workaround other than not enabling HCPP.

Two related paths that this repro does not exercise:

  • createOverlaySurface() (:716) dereferences flutterView.getRootSurfaceControl() the same way.
  • FlutterJNI.endFrame2() (:1379) throws RuntimeException when platformViewsController2 is
    null, which reaches the same FML_CHECK.

This was originally reported from the field on a Xiaomi HyperOS 3 (Android 16) device running a
released app, with an identical abort signature. That app does not use a cached engine; the cached
engine in the repro makes the same race deterministic by keeping FlutterJNI attached across the
activity destroy. The equivalent window exists in an ordinary teardown, where
detachFromFlutterEngine() runs before the engine is destroyed, which would explain why it appears
in the field as a rare crash.

Code sample

Code sample

Full app: https://github.com/amaan-0331/hcpp-onendframe-crash-repro

android/app/src/main/AndroidManifest.xml:

<meta-data android:name="io.flutter.embedding.android.EnableHcpp" android:value="true" />
<meta-data android:name="io.flutter.embedding.android.ImpellerBackend" android:value="vulkan" />

lib/main.dart (platform view creation):

PlatformViewLink(
  viewType: 'hcpp_repro/box',
  surfaceFactory: (BuildContext context, PlatformViewController controller) {
    return AndroidViewSurface(
      controller: controller as AndroidViewController,
      gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
      hitTestBehavior: PlatformViewHitTestBehavior.opaque,
    );
  },
  onCreatePlatformView: (PlatformViewCreationParams params) {
    return PlatformViewsService.initHybridAndroidView(
        id: params.id,
        viewType: params.viewType,
        layoutDirection: TextDirection.ltr,
        creationParamsCodec: const StandardMessageCodec(),
        onFocus: () => params.onFocusChanged(true),
      )
      ..addOnPlatformViewCreatedListener(params.onPlatformViewCreated)
      ..create();
  },
)

MainActivity uses a cached engine created in Application.onCreate, so it outlives the activity:

class MainActivity : FlutterActivity() {
    override fun getCachedEngineId(): String = ENGINE_ID
    override fun shouldDestroyEngineWithHost(): Boolean = false
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
E flutter : [ERROR:flutter/fml/platform/android/jni_util.cc(206)] java.lang.NullPointerException: Attempt to invoke interface method 'boolean android.view.AttachedSurfaceControl.applyTransactionOnDraw(android.view.SurfaceControl$Transaction)' on a null object reference
E flutter : 	at io.flutter.plugin.platform.PlatformViewsController2.onEndFrame(PlatformViewsController2.java:676)
E flutter : 	at io.flutter.embedding.engine.FlutterJNI.endFrame2(FlutterJNI.java:1379)
E flutter : 	at android.os.MessageQueue.nativePollOnce(Native Method)
E flutter : 	at android.os.MessageQueue.nextLegacy(MessageQueue.java:913)
E flutter : 	at android.os.MessageQueue.next(MessageQueue.java:1025)
E flutter : 	at android.os.Looper.loopOnce(Looper.java:196)
E flutter : 	at android.os.Looper.loop(Looper.java:338)
E flutter : 	at android.app.ActivityThread.main(ActivityThread.java:9067)
E flutter : 	at java.lang.reflect.Method.invoke(Native Method)
E flutter : 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
E flutter : 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)
F flutter : [FATAL:flutter/shell/platform/android/platform_view_android_jni_impl.cc(2370)] Check failed: fml::jni::CheckException(env).
F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 15144 (hcpp.hcpp_repro), pid 15144 (hcpp.hcpp_repro)

The original field report, from a released app on a Xiaomi HyperOS 3 (Android 16) device, has the
same abort with no Java stack attached:

Abort message: '[FATAL:flutter/shell/platform/android/platform_view_android_jni_impl.cc(2370)] Check failed: fml::jni::CheckException(env). '
      #00 pc 0000000000072f7c  /apex/com.android.runtime/lib64/bionic/libc.so (abort+156)
      #01 pc 00000000004e9228  .../base.apk!libflutter.so
      ...
      #07 pc 0000000000035588  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+648)
      #08 pc 00000000001f1d2c  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.44.4, on macOS 26.5.2 25F84 darwin-arm64, locale en-AE) [546ms]
    • Flutter version 3.44.4 on channel stable at /Users/amaan/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ad70ec4617 (6 weeks ago), 2026-06-24 11:07:06 -0700
    • Engine revision a10d8ac38d
    • Dart version 3.12.2
    • DevTools version 2.57.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, no-enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration

[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [2.1s]
    • Android SDK at /Users/amaan/Library/Android/sdk
    • Emulator version 36.1.9.0 (build_id 13823996) (CL:N/A)
    • Platform android-36, build-tools 36.0.0
    • Java binary at: /opt/homebrew/opt/openjdk@17/bin/java
      This JDK is specified in your Flutter configuration.
      To change the current JDK, run: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment Homebrew (build 17.0.19+0)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 26.4.1) [1,146ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 17E202
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [10ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Connected device (4 available) [6.4s]
    • sdk gphone16k arm64 (mobile)              • emulator-5554             • android-arm64  • Android 16 (API 36) (emulator)
    • Argaam Testing iPhone (wireless) (mobile) • 00008130-000814683604001C • ios            • iOS 27.0 24A5390f
    • macOS (desktop)                           • macos                     • darwin-arm64   • macOS 26.5.2 25F84 darwin-arm64
    • Chrome (web)                              • chrome                    • web-javascript • Google Chrome 150.0.7871.187

[✓] Network resources [569ms]
    • All expected network resources are available.

• No issues found!

Activity

  1. added
    c: crashStack traces logged to the console
    platform-androidAndroid applications specifically
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    team-androidOwned by Android platform team
    platform-views: hcppIssues which affect the HCPP platform views backend
    engineflutter/engine related. See also e: labels.
    on Aug 5, 2026
  2. mbcorona commented on Aug 5, 2026

    @mbcorona
    Member

    Thanks for the detailed report, repro steps, and linking a PR #190612, routing to the Android team for evaluation.

  3. added
    P1High-priority issues at the top of the work list
    triaged-androidTriaged by Android platform team
    on Aug 11, 2026
  4. self-assigned this
    on Aug 11, 2026
  5. added a commit that references this issue on Aug 19, 2026
    8bcda46
  6. github-actions commented on Sep 2, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  7. locked as resolved and limited conversation to collaborators on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work listc: crashStack traces logged to the consoleengineflutter/engine related. See also e: labels.found in release: 3.44Found to occur in 3.44has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyplatform-views: hcppIssues which affect the HCPP platform views backendteam-androidOwned by Android platform teamtriaged-androidTriaged by Android platform team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions