blob: 2ccbd75fd46e3acaa81f5d7b3aa892d1b3d64677 [file] [log] [blame] [view]
# How a Flutter component works
For a very detailed overview of Flutter architecture on all platforms,
see [this doc](https://docs.flutter.dev/resources/architectural-overview).
A Flutter component for Fuchsia is an [ELF binary](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
that is built and run using Fuchsia's [Bazel SDK](https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0139_bazel_sdk).
The component is launched by
[Fuchsia's ELF runner](https://fuchsia.dev/fuchsia-src/concepts/components/v2/elf_runner)
(there is no longer a separate Flutter runner or Dart runner).
Building and running an example Flutter component is done by:
1. Compiling the Flutter application to get a folder of compiled assets
([snapshot](https://mrale.ph/dartvm/#how-does-dart-vm-run-your-code), fonts, images).
This is currently done with the Flutter CLI using `flutter build bundle`.
This only supports JIT compilation. To support AOT compilation, we should switch to
using the Dart SDK's tools instead (see
[this doc](https://github.com/flutter/flutter/wiki/Custom-Flutter-Engine-Embedding-in-AOT-Mode#the-hard-way)
for reference).
2. [Packaging](https://fuchsia.dev/fuchsia-src/concepts/packages/package)
these assets together with the embedder executable and shared libraries.
See [_"Package layout"_](#package-layout) for details.
3. Running the embedder executable with the ELF runner. This is handled
by the Bazel SDK.
We pass the path to the compiled assets as an argument
[here](https://fuchsia.googlesource.com/flutter-embedder/+/refs/heads/main/src/embedder/meta/embedder.cml#18).
Running the application using the assets is handled by `libflutter_engine.so`,
a shared library from the [Flutter Engine repository](https://github.com/flutter/engine).
We interact with `libflutter_engine.so` using
[`embedder.h`](https://fuchsia.googlesource.com/flutter-embedder/+/refs/heads/main/src/embedder/engine/embedder.h).
![embedder architecture diagram](images/embedder_architecture.png)
## Package layout
The compiled Flutter component's package has three main folders:
- **`bin/embedder`**: The executable.
- **`data/flutter_assets/`**: The compiled assets of the Flutter app that should
be run by the executable.
- **`lib/`**: Shared libraries that are used by `bin/embedder`.
Notably, `lib/libflutter_engine.so` is the Flutter Engine code that
`bin/embedder` uses to run the Flutter app.
When building and running a Flutter example, the full package contents are printed
for debugging.
## Threading model
The easiest way to understand how threading works in Flutter
is to
[attach a debugger in VS Code](https://fuchsia.googlesource.com/flutter-embedder/+/refs/heads/main/docs/debugging.md#attaching-a-debugger-from-vscode)
and break on a function that you're interested in. VS Code will tell
you what thread the code is running on.
![threads in VS Code](images/vscode_thread_model.png)
Some notable threads:
- Platform thread (`initial-thread`): The thread that `main()` runs on.
- We connect to all
[FIDL services](https://fuchsia.dev/fuchsia-src/concepts/fidl/overview)
on this thread and
[platform messages](https://docs.flutter.dev/development/platform-integration/platform-channels)
are sent on this thread.
- Async requests and responses to FIDL services are handled by an async loop that is started by `FlutterEngineRun`.
- Raster thread (`io.flutter.raster`): Handles rendering logic for Flutter.
- Callbacks for rendering are called on this thread.