Skip to content

Android Embedder Migration to Embedder API - #24

Open
mboetger wants to merge 43 commits into
flutter:mainfrom
mboetger:rfc-410-android-embedder-c-api
Open

mboetger wants to merge 43 commits into
flutter:mainfrom
mboetger:rfc-410-android-embedder-c-api

Conversation

@mboetger

@mboetger mboetger commented Sep 22, 2026 •

Copy link
Copy Markdown

Android Embedder Migration RFC

Tracking issue: flutter/flutter#193309

Pre-launch Checklist

  • I read [RFC 000.0001: Taxonomy] and followed the file and path naming and metadata standards.
  • I read [RFC 000.0002: Process] and confirmed this proposal meets the threshold for a full RFC.
  • I read and agree to the [Code of Conduct].
  • I signed the [CLA].
  • I have linked an issue from flutter/flutter with the label design doc.
  • All existing and new tests are passing.
  • I have enabled "Allow edits from maintainers" on this PR so the bot can automatically assign an RFC number (or I will run dart run bin/assign_rfc_number.dart locally when instructed).

@mboetger mboetger changed the title Android Embedder Migration Android Embedder Migration to Embedder API Sep 24, 2026
@mboetger
mboetger requested a review from gaaclarke September 24, 2026 21:22
@mboetger

mboetger commented Oct 21, 2026 •

Copy link
Copy Markdown
Author

@gaaclarke - I took a massive hatchet to the context provided on how things work and why and left only what was necessary. I think this makes the doc more manageable. PTAL.

> - **Embedder API additions (`embedder.h`)**: Adds `kDeferred` (`FlutterDeferredRendererConfig`) and `FlutterRendererConfigResolveCallback` to [`FlutterRendererConfig`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/embedder/embedder.h#L1055).
> - **Behavioral changes**:
> - [`PlatformViewEmbedder`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/embedder/platform_view_embedder.h#L36), [`EmbedderSurfaceVulkanImpeller`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h), and [`EmbedderSurfaceGLImpeller`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.h) move [`impeller::Context`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/impeller/renderer/context.h#L70) creation from their UI-thread constructors into `PlatformViewEmbedder::SetupImpellerContext()` on the raster thread, and `PlatformViewEmbedder::NotifyCreated()` queues surface creation on the FIFO raster task runner instead of blocking the UI thread on a latch.
> - `AndroidSurfaceControl` performs all Android Vulkan eligibility checks inside `resolve_callback` before creating a `VkDevice` and returns either `kVulkan` or `kOpenGL` in a single call. To make those checks available without depending on `//flutter/impeller`, the Android GPU blocklist in [`DriverInfoVK::IsKnownBadDriver()`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/impeller/renderer/backend/vulkan/driver_info_vk.cc#L379-L431) and the required Android Vulkan capability checks in [`CapabilitiesVK`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc#L98-L529) are moved into `AndroidSurfaceControl` alongside the existing Android system-property and SoC checks from [`android_context_dynamic_impeller.cc`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc#L23-L119).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is AndroidSurfaceControl the best place for the bad driver checks when considering other embedders?

The checks look mostly android-focused, but some of the checks refer to hardware like PowerVR and Adreno, which can exist on non-Android embedded systems. It would be unfortunate if a new custom embedder had to start from scratch or duplicate the checks because we moved them to an android embedder specific location.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I've gone back and forth a couple times with @loic-sharma and @gaaclarke about this - it simplifies the Embedder API such that we don't need to add a "Driver Check" API. But I agree other embedders will lose out. Perhaps moving it to the common library makes more sense.


**What the Android callback does.** It runs the checks Android runs today in [`GetActualRenderingAPIForImpeller`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc#L79-L120): known emulators, Huawei devices (`ro.com.google.clientidbase`), MediaTek devices with `ro.vendor.build.version.sdk < 32`, and the `ro.product.board` deny-list ([`IsKnownBadSOC`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc#L68-L77)). If one matches, it returns `kOpenGL` without loading Vulkan. Otherwise it loads `libvulkan.so`, creates the `VkInstance`, `VkDevice` and `VkQueue`, and returns `kVulkan`. `AndroidContextDynamicImpeller` does the same work on the raster thread today, so the UI thread never waits for it, and nothing has to start earlier on a `FlutterLoader` executor. A process-wide singleton (`VulkanDeviceOwner`) holds the device, so the callbacks of later [`FlutterEngine`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java#L90) instances return the same handles without probing again.

**When the engine rejects a configuration.** Android falls back to OpenGL ES today when Vulkan context creation fails or the driver is on Impeller's known-bad list ([`AndroidContextVKImpeller`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/android/android_context_vk_impeller.cc#L65-L69)). In the embedder path, [`impeller::ContextVK::Create`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/impeller/renderer/backend/vulkan/context_vk.cc#L176-L188) still checks the embedder's device, but a failure leaves the engine without a renderer. For a `kDeferred` configuration the engine keeps Android's fallback:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Wait, I don't think we want the engine to error out if Android picks Vulkan but then fails to create a context. We want it to fall back to openGLES in that case, right? Vulkan context creation can fail for reasons that are hard to predict ahead of time, like a bad driver update or something.

/// An embedder may return the view's on-screen render target (for example,
/// the next swapchain image or default framebuffer) when this is true. The
/// engine's backing store cache ignores this field, so such an embedder must
/// set `FlutterCompositor.avoid_backing_store_cache` to true.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Are we conflating a caching policy with information about topology here? It's weird to me that a field called is_root_layer would ever be false for the root layer. Do we need a different channel to communicate whether a backingstore should be cached or not? Maybe an is_cacheable field on FlutterBackingStore, or swapchain info

/// When true, the engine coalesces all non-root Flutter slices composited
/// above platform views into a single top-most overlay `FlutterBackingStore`
/// per view per frame, clipping out the bounding rectangles of any higher-Z
/// platform views using `DlClipOp::kDifference`.

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.

DlClipOp is engine internals. I assume any higher-Z platform views would have FlutterPlatformViewMutations?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This happens in the engine internals - embedder_external_view_embedder.cc.

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.

Sure, but the embedder API is externally-facing. The embedder API's docs should prefer the external names for concepts over the internal names.

/// render threads (`FlutterCustomTaskRunners.platform_task_runner` and
/// `render_task_runner` must be NULL so the engine binds `fml::MessageLoop`
/// to the calling platform thread and creates the raster thread).
bool merge_raster_thread_on_platform_views;

@loic-sharma loic-sharma Oct 22, 2026 •

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.

I wonder if we should make this an engine flag instead, similar other engine flags like --enable-hcpp-and-surface-control.

This would let us remove raster thread merging from the embedder API if/when we remove HC or we update HC to use latches instead of thread merging.

///
/// Requires engine-managed message loop task queues for the platform and
/// render threads (`FlutterCustomTaskRunners.platform_task_runner` and
/// `render_task_runner` must be NULL so the engine binds `fml::MessageLoop`

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.

I believe to opt-in to merged threads you need to pass a non-NULL FlutterCustomTaskRunners.platform_task_runner (which matches the ui_task_runner). If so, can we remove this requirement?

@knopp

knopp commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Is raster thread merging absolutely necessary? This is one of the most convoluted parts of the engine and it's only used by the android embedder right now. "traditionally" platform views were mutated in preroll, so the thread merging was in a way necessary, but the embedder api records mutations so we only need to synchronize platform and raster thread at a single spot (schedule mutation on platform thread and latch the raster thread). Both macOS and iOS embedders do this. Does this not work for android embedder? I'd very much like to not expose dynamic thread merging in the embedder API.

@gaaclarke gaaclarke 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.

Thanks Matt, the doc is looking way better layout in the presentation. Here are a few questions that came to my mind during it:

1) What about SDFs?

I recommend we try to ignore this as long as possible. Ideally in the future, everyone just uses the SDF rendering. If a customer asks for it we can consider engine flags.

2) What about vulkan validation layers?

What does the user story look like for the embedder that wants to enable vulkan validation layers? Do we care to support that?

3) What about kMergeAfterLaunch?

How do we want to surface its in the embedder, if at all? Right now flutter engine groups don't work with it. So we need to probably opt out of it, or allow it to be selectable if we want to expose flutter engine group apis.

> - [`PlatformViewEmbedder`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/embedder/platform_view_embedder.h#L36), [`EmbedderSurfaceVulkanImpeller`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/embedder/embedder_surface_vulkan_impeller.h), and [`EmbedderSurfaceGLImpeller`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/embedder/embedder_surface_gl_impeller.h) move [`impeller::Context`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/impeller/renderer/context.h#L70) creation from their UI-thread constructors into `PlatformViewEmbedder::SetupImpellerContext()` on the raster thread.
> - `PlatformViewEmbedder::NotifyCreated()` queues surface creation on the FIFO raster task runner instead of blocking the UI thread on a latch.
> - `AndroidSurfaceControl` performs all Android Vulkan eligibility checks inside `resolve_callback` before creating a `VkDevice` to return `kVulkan` or `kOpenGL` in a single call.
> - The `VkPhysicalDeviceProperties` GPU parser and known-bad-driver check in [`DriverInfoVK::IsKnownBadDriver()`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/impeller/renderer/backend/vulkan/driver_info_vk.cc#L379-L431) move into [`//flutter/common`](https://github.com/flutter/flutter/tree/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/common) (so `//flutter/impeller`, `AndroidSurfaceControl`, and other embedders share a single implementation), while the required Android Vulkan capability checks in [`CapabilitiesVK`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc#L98-L529) move into `AndroidSurfaceControl` alongside the Android system-property and SoC checks from [`android_context_dynamic_impeller.cc`](https://github.com/flutter/flutter/blob/4762dec4fc9072cd9269814ef36364f35a9a66dc/engine/src/flutter/shell/platform/android/android_context_dynamic_impeller.cc#L23-L119).

@loic-sharma loic-sharma Oct 22, 2026 •

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.

Could we put this in //flutter/shell/platform/common? That's where we generally put code that's shared across embedders, instead of //flutter/common.

knasher added a commit to knasher/flutter-embedded-linux that referenced this pull request Oct 27, 2026
Report the display cut-outs as view padding (needs 0009).

0009 sends the cut-out padding on flutter-sfos/display_cutouts, and apps had to add it to MediaQuery themselves (flutter_sailfish's SailfishCutouts.builder), because the embedder API had no view padding. With the engine's view padding patch (patches/<ver>/engine/0001-view-padding.patch), the padding goes in the window metrics instead, so MediaQuery.padding, SafeArea and app bars avoid the cut-out in every app.

The embedder's FlutterWindowMetricsEvent gains the engine's size constraint fields (sent as no constraints) and physical_padding, a FlutterEdgeInsets as proposed upstream for the Android embedder (flutter/rfc#24), in the engine's order; engines without the patch ignore it. Metrics are sent again when only the content orientation changes, since turning upside down moves the cut-out without resizing. When built with FLUTTER_SFOS_VIEW_PADDING (the runtime spec sets it if the engine's flutter_embedder.h has physical_padding), the cut-out message says "in_metrics": true, so SailfishCutouts.builder doesn't add the padding a second time.
knasher added a commit to knasher/flutter-sailfish that referenced this pull request Oct 27, 2026
The engine patch added four physical_view_padding_* fields to FlutterWindowMetricsEvent. Flutter's RFC for moving the Android embedder to the embedder API (flutter/rfc#24) proposes the same thing as FlutterEdgeInsets physical_padding, and its draft prototype (flutter/flutter#195336) adds it in the same place. The engine patch and embedder patch 0014 now use that layout, read and checked as the prototype does, so our patch can be dropped once Flutter ships it. The runtime spec looks for the new field.

Tested on Jolla Phone 2026, Sailfish 5.2.0.20, in a sandboxed copy of an app
int entrypoint_argc;
void* user_data;
const FlutterCompositor* compositor;
} FlutterEngineSpawnInfo;

@loic-sharma loic-sharma Nov 3, 2026 •

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.

Each engine instance needs a unique ID. FlutterEngineSpawnInfo should also accept a engine_id that mirrors FlutterProjectArgs.engine_id.

This becomes PlatformDispatcher.engineId. See: flutter/flutter#195881

bkonyi pushed a commit to bkonyi/flutter that referenced this pull request Nov 13, 2026
…Android (flutter#196342)

... and also make `PlatformViewAndroid::NotifyChanged` non-blocking at
the same time.

On Android,
[`surfaceCreated`](https://github.com/flutter/flutter/blob/e6b33e67d8cf6b53e1798438580e16453e4cc78d/engine/src/flutter/shell/platform/android/platform_view_android.cc#L189-L200)
and
[`surfaceChanged`](https://github.com/flutter/flutter/blob/e6b33e67d8cf6b53e1798438580e16453e4cc78d/engine/src/flutter/shell/platform/android/platform_view_android.cc#L240-L247)
currently block the main thread until the raster thread has finished any
queued `SetupImpellerContext()` work, created the swapchain, and set up
the rasterizer. Because this runs inside the first view traversal, both
the `Activity`'s first native draw and Dart's first frame wait behind it
(~80–110 ms on mid/low-tier Android devices with Impeller Vulkan, e.g.
~70 ms faster non-debuggable cold-start time-to-first-frame on a Moto
G05 once unblocked).

Per Android's `SurfaceHolder.Callback` contract, only `surfaceDestroyed`
is required to block until the render thread stops accessing the
`Surface`; `surfaceCreated` and `surfaceChanged` can forward surface
work asynchronously while `fml::RefPtr<AndroidNativeWindow>`
(`ANativeWindow_fromSurface`) keeps the native window reference alive
until teardown (see flutter#196180 for
more details)

### Changes

**`shell/common`:**
- Adds `PlatformView::NotifyCreatedDeferred` and
`PlatformView::Delegate::OnPlatformViewCreatedDeferred`, used only by
Android in this PR. The platform passes a `SurfaceFactory` callback;
`Shell` posts surface creation + `Rasterizer::Setup` directly to the
raster task runner (preserving FIFO ordering with subsequent
resize/teardown tasks on the raster queue), posts
`CreateResourceContext` to the IO task runner once a valid `Surface` is
created, and schedules a UI frame without waiting.
- Every other platform keeps calling `PlatformView::NotifyCreated`,
which is unchanged.
- Because `Rasterizer::Setup` can now run concurrently with
platform-thread calls that disable or read the raster thread merger,
protects merger access with `raster_thread_merger_mutex_`, starts a
lazily created merger disabled if `DisableThreadMergerIfNeeded()` was
called while setup was in flight, and resolves a spawned shell's parent
merger lazily on the raster thread.

**Android (`shell/platform/android`):**
- Updates `PlatformViewAndroid::NotifyCreated` and
`PlatformViewAndroid::NotifyChanged` to post to the raster thread and
return immediately. An atomic generation counter (`surface_generation_`)
skips queued setup/resize tasks from a surface that has since been
destroyed or replaced.
- Keeps `NotifyDestroyed` (and `NotifySurfaceWindowChanged` for
`FlutterImageView` resize) synchronous, and preserves existing
attempt-and-validate failure handling when surface creation fails.

Perfetto cold-start traces on Moto G05 (Impeller Vulkan):
[before](https://ui.perfetto.dev/#!/?s=c08b978984e818175e489d5bed5eb68c2e587ab7)
vs.
[after](https://ui.perfetto.dev/#!/?s=9225a8152d4e94a21d4a3e70e2b4c0de7cf3c578).

Fixes flutter#196180, and is part of
flutter/rfc#24

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [x] If this PR introduces a new feature or capability, I created and
linked a website documentation issue or PR in [flutter/website] (or
verified none is needed).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[flutter/website]: https://github.com/flutter/website
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rfc-ready RFC is ready for review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants