Skip to content

feat: support module_version for add-to-app releases#121

Open
eseidel wants to merge 134 commits into
shorebird/devfrom
feat/aar-release-version
Open

feat: support module_version for add-to-app releases#121
eseidel wants to merge 134 commits into
shorebird/devfrom
feat/aar-release-version

Conversation

@eseidel
Copy link
Copy Markdown

@eseidel eseidel commented Apr 2, 2026

Summary

  • Flutter tool: Read SHOREBIRD_MODULE_VERSION env var in compileShorebirdYaml() and write module_version into the compiled shorebird.yaml (same pattern as SHOREBIRD_PUBLIC_KEY)
  • Engine: No changes to release_version handling — host app version passes through unchanged
  • Updater: Parse module_version from shorebird.yaml, add to UpdateConfig and PatchCheckRequest as a separate optional field sent alongside release_version

Context

Part of shorebirdtech/shorebird#793

release_version always stays the host app's version. module_version is a separate field used for patch lookup in add-to-app releases where the module's identity is independent of the host app.

Companion PRs:

Test plan

  • Existing Flutter tools tests pass
  • Existing engine tests pass
  • Verify module_version appears in compiled yaml when env var is set
  • Verify compiled yaml unchanged when env var is absent

walley892 and others added 30 commits January 12, 2026 18:58
Bump.

Updates dart version to 3.11.0-296.3.beta. dart-lang/sdk@fb9aa17
Bump the engine version following the dart bump in flutter#180916
…utter#181163)

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#179857

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

`flutter run -d all` causes the tool to crash if multiple devices are available.

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
* That describes the state prior to the fix.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.

`flutter run -d all` causes the tool to crash if multiple devices are available.

### Workaround:
Is there a workaround for this issue?

No.

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

Run `flutter run -d all` with multiple non-web devices available and verify the application is deployed to all non-web devices.
…ng web applications (flutter#181162)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#178151

### Changelog Description:
Explain this cherry pick in one line that is accessible to most Flutter developers. See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples

`flutter run -d chrome` can crash with a `DartDevelopmentServiceException` if the application shuts down during the startup sequence.

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)? Does it impact development (ex. flutter doctor crashes when Android Studio is installed), or the shipping production app (the app crashes on launch)

Flaky crashes for users developing Flutter web applications. This is one of the top crashers for 3.38.

### Workaround:
Is there a workaround for this issue?

N/A

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

Difficult to validate manually as the failure is timing based. Tests have been added to simulate the crash scenario and verify the fix.
)

Fixes style_manager_test.dart for Firefox by

1. changing the CSS to explicitly set `outline: rgb(0, 0, 0) none 0px`
2. actually focusing the element before checking it's computed style

Fixes flutter#181203

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [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/
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

<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

*Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.*

*List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.*

*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
[3.11.0-296.4.beta](https://github.com/dart-lang/sdk/releases/tag/3.11.0-296.4.beta)

```
gcert
gclient sync
cd engine/src
tools/dart/create_updated_flutter_deps.py
gclient sync
```
`./bin/internal/content_aware_hash.sh > ./bin/internal/engine.version`
`bin/internal/last_engine_commit.sh > bin/internal/engine.version`

Update engine version is not working see: flutter#181404
… shadow_path code (flutter#180920) (flutter#181095)

The new general convex path shadow code was checking for duplicate vertices without actually checking if the vectors contained any vertices. Thus, <vector>.back() was being called on empty vectors, which is bad. This led to a crash in G3 as their code is being run with a vector implementation that protects against this, but apparently we do not have such a vector implementation in our local building and testing.

No tests because this covered by existing test cases and a new FML_DCHECK.

<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->

Fixes flutter#180827

Impacted users: Any user who uses shadows (pretty much every Flutter app) on a platform that has address sanitization built into its `std::vector` implementation, if they use Impeller (always used on iOS and the default on Android)

Impact Description: Every shadow render operation in Impeller backend will access `back()` on an empty `std::vector` which will crash immediately if the vector is using sanitization on that platform.

Workaround: Potentially look into disabling address sanitization? On platforms that still support Skia, it can be used as a workaround, but that is not an option on iOS

Risk: The fix was obvious and non-controversial.

Test Coverage: Existing tests cover this case really well and there is now an FML_DCHECK (engine assert) to check if we trigger the condition under testing.

Validation: The original issue indicates an app that will trigger the sanitization crash, but only in G3. None of the platforms we support directly through flutter perform this sanitization.

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
This PR cherrypicks flutter#181269 into beta. This is needed to address a breakage.

**Impacted Users:** Apps that directly use `CupertinoSheetTransition `.

**Impact Description:** Can not compile.

**Workaround:** Yes. They need to add `topGap: 0.08` to the constructor.

**Risk:** Low. This PR loosens the API, and reverts the behavior to that before flutter#171348.

**Test Coverage:** Yes. The widget has high test coverage.

**Validation Steps:** The PR compiles and tests pass. `sheet_test.dart` contains constructors that do not specify `topGap` in the same way as existing apps.
This PR cherrypicks flutter#181074 into beta, which is mostly a revert of flutter#176711 (except that some docs are left unreverted and a few new tests are added.) This is needed to address a breakage as described in flutter#180121.

**Impacted Users:** Apps that use `DropdownMenu` or `DropdownMenuFormField` for a nullable class, such as `DropdownMenu<int?>`.

**Impact Description:** Can not compile.

**Workaround:** Yes, through non-trivial changes. For example, the developer can replace  `DropdownMenu<int?>` with `DropdownMenu<Maybe<int>>`, as long as they import `Maybe` or create their own equivalence. 

**Risk:** Low. This PR is basically a revert.

**Test Coverage:** Yes. The widget has high test coverage.

**Validation Steps:** The PR compiles and tests pass.
This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
flutter#181153

### Impact Description:
This PR is to fix a typo in a newly added API (AccessiblityFocusBlockType->AccessibilityFocusBlockType)
The typo was inroduced in this PR  flutter#175551 which was merged on Nov 3, 2025 and is in 3.39-3.41

What is the impact 
The impact is to fix a small typo by hotfix, so we dont need to deprecate the API and add a new API. 
The risk is small because the API was recently added in Nov, 2025 and it's an API to control accessibility focus. I don't think it's widely used by external developers yet.
Also the typo is not in the previous stable 3.38, so this only needs to be cp to beta. 

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
* That describes the state prior to the fix.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.

[flutter/181153] fix a typo in a newly added API (AccessiblityFocusBlockType->AccessibilityFocusBlockType)

### Workaround:
Is there a workaround for this issue?

no

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?
N/A
This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#180191

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

Updates a library that had multiple CVE's to a version that has those issues patched. 
https://ubuntu.com/security/CVE-2025-64505
https://ubuntu.com/security/CVE-2025-64506
https://ubuntu.com/security/CVE-2025-64720
https://ubuntu.com/security/CVE-2025-65018

FWIW I have not seen a working exploit against a flutter app. 

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
* That describes the state prior to the fix.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.

< Replace with changelog description here >
[flutter/180191] Update libpng to 1.6.53 to mitigate multiple CVE's published November/December 2025. 

### Workaround:
Is there a workaround for this issue?

No work around. 

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

  - [ x ] Yes

### Validation Steps:
What are the steps to validate that this fix works?

Run the standard test suite on CI including golden image tests.
This PR creates a FlutterFramework swift package with no real content. This is a placeholder so that plugins may add a dependency on the FlutterFramework in their Package.swift before flutter#178931 lands in stable. See go/swiftpm-flutter-release.

Impacted Users: Flutter iOS with SwiftPM feature flag enabled

Impact Description: Allows plugins to add a dependency on the FlutterFramework in their Package.swift.

Workaround: See Problem 2 alternatives in [go/swiftpm-flutter-release](http://goto.google.com/swiftpm-flutter-release)

Risk: This PR by itself is low risk. It just generates a couple files in an ephemeral directory. It only is actually used if a plugin adds a dependency on it in it's Package.swift. If a plugin does this, it's still low risk since it's basically just an empty Swift package. It's also behind a feature flag (`flutter config --enable-swift-package-manager`), which can be disabled.

Test Coverage: Yes

Validation Steps: 
 - `flutter config --enable-swift-package-manager`
 - `flutter create my_plugin && cd my_plugin/example`
 - Add `FlutterFramework` to Package.swift (see [example](https://github.com/flutter/flutter/blob/master/packages/integration_test/ios/integration_test/Package.swift#L15-L21))
 - `flutter build ios`

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
…1732)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

Cherry-pick of flutter#181686

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#181573

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Crash

Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
App crashes

This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

Apps running this code will crash: https://buganizer.corp.google.com/issues/478788744

### Changelog Description:
Explain this cherry pick:
* Makes sure the JNI method is called on Android's UI thread.
* The JNI method would be called by the raster's thread and cause a crash.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.
Android Apps

< Replace with changelog description here >
[flutter/181573] When resize JNI method is called on Android, apps will crash.

### Workaround:
Is there a workaround for this issue?

No.

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

Run the sample app flutter/samples#2787 and check it does not crash.
…81670)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#177992
flutter#175606

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

The issues listed above impact app users. For instance flutter#177992 prevents the user from interacting with hamburger menus on iPadOS 26.1+ for context, this probably has always been an issue but on iPadOS 26.1 the height of the status bar became taller so it gets in the way of the hamburger menu.

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
* That describes the state prior to the fix.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.

[flutter/177992] on iPadOS 26.1, tapping on the status bar dismisses the current modal route. 

### Workaround:
Is there a workaround for this issue?

Yes. There is a relatively reliable workaround described here: flutter#175606 (comment)

### Risk:
What is the risk level of this cherry-pick?

  - [-] Low

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

  - [-] Yes

### Validation Steps:
What are the steps to validate that this fix works?

Following the repro steps in flutter#177992. I've tried the fix myself on master following the steps outlined in the issue and couldn't reproduce the issue.
There were 2 cherry picks include:

 * flutter#181732
 * flutter#181670 (containing latest engine change 0aafd14)
Bump dart revision to dart-lang/sdk@1a420a3 and update DEPS. 

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
As the title says :)

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
Update `engine.version` to Dart version + DEPS update: flutter@3452d73

Tests will fail until https://ci.chromium.org/ui/p/dart-internal/builders/flutter/Linux%20flutter_release_builder/1198 completes.

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
…on (flutter#182317)

Fixes flutter#182314

This cherry picks in 2 changes to stable
- flutter#180886
  - The pub roller was busted, and the stable release missed the update
- flutter#180658
  - Preceded manual pub roll, required to pass analysis with above change.

This is a manual cherry pick, following https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md

Around about when we created the release, the pub roller was busted. It is fixed now (flutter#180503).

Impacted Users: significant
Impact Description: users cannot upgrade to the latest version
Workaround: None
Risk: Not sure, but the pub roll this is cherry picking landed very very close to the stable release being cut. Analysis and flutter doctor all pass.
Test Coverage: For the widget scaffold change, tests are just relocated
Validation steps: dart-lang/test#2570 (comment)

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
…e start of "flutter test" output to be optional. (flutter#182335)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#180903. This is blocking a stable hotfix right now. See https://ci.chromium.org/ui/p/flutter/builders/prod/Linux_mokey%20flutter_test_performance/8971/overview.

### Impact Description:

Maybe impacts some people parsing test output besides us.

### Changelog Description:

Version 1.29 of the Dart test package adds a blank line to test output causing unexpected test failures.

### Workaround:
No need for a workaround/

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

< Replace with validation steps here >
…ter#182344)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)
Please fill in the form below, and a flutter domain expert will evaluate this cherry pick request.

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#182076

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

The `--web-define` feature works during development (i.e. `flutter run`), but doesn't work for production (i.e. `flutter build web`).

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
* That describes the state prior to the fix.
* That includes which platforms are impacted.
See [best practices](https://github.com/flutter/flutter/blob/main/docs/releases/Hotfix-Documentation-Best-Practices.md) for examples.

Fix `flutter build web` ignoring `--web-define` flag

### Workaround:
Is there a workaround for this issue?

No workaround.

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

Follow repro steps in flutter#182076
…ot turned on (flutter#182320)

This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request)

### Issue Link:
What is the link to the issue this cherry-pick is addressing?

flutter#179673

### Impact Description:
What is the impact (ex. visual jank on Samsung phones, app crash, cannot ship an iOS app)?
- Content Sizing is affecting platform views even when content sizing is not enabled via the feature flag.
Does it impact development (ex. flutter doctor crashes when Android Studio is installed),
or the shipping of production apps (the app crashes on launch).
- Shipping of production apps
This information is for domain experts and release engineers to understand the consequences of saying yes or no to the cherry pick.

There is a race condition in the content sizing code that sometimes causes a platform view to not appropriately rotate (as can be seen from the flakey test goldens).  

### Changelog Description:
Explain this cherry pick:
* In one line that is accessible to most Flutter developers.
- Ensures no side effects from content sizing when content sizing is not enabled by the user.
* That describes the state prior to the fix.
- Sometimes platform views will not render as desired.
* That includes which platforms are impacted.
Android

< Replace with changelog description here >
[flutter/179673] When content sizing is not enabled on Android, a race condition can sometimes make platform views not render correctly.

### Workaround:
Is there a workaround for this issue?

No workaround.

### Risk:
What is the risk level of this cherry-pick?

### Test Coverage:
Are you confident that your fix is well-tested by automated tests?

### Validation Steps:
What are the steps to validate that this fix works?

Run the flakey test several times to make sure it passes all the time (as can be seen from the flake being fixed here: https://flutter-dashboard.appspot.com/#/build?taskFilter=Linux_android_emu+android_engine_opengles_tests)
bumping engine version to 87054f6

**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
**Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.
eseidel and others added 24 commits April 30, 2026 15:10
The manifest template still referenced Flutter.dSYM.zip but
mac_upload.sh uploads Flutter.framework.dSYM.zip (the new name as of
Flutter 3.27.0). Update the template, generate script, and test to
match what's actually uploaded.

Relates to shorebirdtech/shorebird#3035
#117)

* fix: filter non-stable version branches in shorebird version detection

The shorebird version detection in GitTagVersion.determine() matches
flutter_release/* branches to resolve the Flutter version. When
non-stable branch names like flutter_release/3.41.4-rc2 are present,
parse() fails to match them against the expected version pattern and
returns GitTagVersion.unknown(), causing Flutter to report 0.0.0-unknown.

Filter branch names to only match stable versions (X.Y.Z) so that
release candidate branches are skipped and the correct version is
resolved.

Fixes shorebirdtech/shorebird#3662

* test: add tests for shorebird flutter_release branch version filtering

Tests that:
- A stable flutter_release branch (e.g. 3.41.4) resolves correctly
- A non-stable branch (e.g. 3.41.4-rc2) is skipped, falling through
  to the upstream tag-based fallback
- When both stable and rc branches match, the stable one is picked
* Integrate Rust updater build into GN/Ninja

Add a GN action() that invokes cargo to build the Rust updater library,
so that Ninja (and ET) can build the complete Shorebird engine without
requiring a separate shell script prerequisite step.

* Fix missing updater dep in runtime BUILD.gn

dart_snapshot.cc calls shorebird::Updater::Instance().ReportLaunchStart()
but the runtime source_set did not depend on shorebird:updater, causing
link failures in test targets that depend on runtime without also pulling
in the updater through other deps.

* Fix relative NDK path resolution for Android cargo builds

GN passes paths relative to the build output dir, but cargo's build
scripts (e.g. ring's cc crate) run from a different directory. Resolve
all paths to absolute before passing them to cargo/env vars.

* Extract updater build config into .gni and glob Rust sources

Move triple computation and variables into build_rust_updater.gni to
keep BUILD.gn focused on target definitions. Add list_rust_files.py
to automatically discover .rs source files at GN gen time via
exec_script, so the inputs list stays in sync when the updater repo
changes without manual updates.
Rolls shorebirdtech/updater dc2cd0a..adacb41 (15 commits).

Notable changes:
- refactor: replace reqwest with ureq to reduce binary size (flutter#317)
- feat: add resumable downloads with streaming to disk (flutter#313)
- fix: improve inflate error handling and validate compressed patches (flutter#314)
- fix: checkForUpdate reports restartRequired when current patch is rolled back (flutter#312)
- fix: resolve all Dependabot security vulnerabilities (flutter#316)
- perf: add release profile to reduce binary size (flutter#328)
* chore: roll updater to adacb4190cb4af2e2920c18d8a904f4c6b138ee4

Rolls shorebirdtech/updater dc2cd0a..adacb41 (15 commits).

Notable changes:
- refactor: replace reqwest with ureq to reduce binary size (flutter#317)
- feat: add resumable downloads with streaming to disk (flutter#313)
- fix: improve inflate error handling and validate compressed patches (flutter#314)
- fix: checkForUpdate reports restartRequired when current patch is rolled back (flutter#312)
- fix: resolve all Dependabot security vulnerabilities (flutter#316)
- perf: add release profile to reduce binary size (flutter#328)

* fix: thread Apple deployment target into Rust updater build

build_rust_updater.py had explicit Android cross-compile env handling
but no equivalent for *-apple-ios or *-apple-darwin targets. Cargo for
aarch64-apple-ios was running with no IPHONEOS_DEPLOYMENT_TARGET, which
let the cc crate compile transitive C deps (zstd-sys, pulled in via
ureq's compression features in the recent updater roll) against the
host Xcode SDK while rustc's cdylib link step targeted iOS 10/11 (from
rustc's built-in target spec). The mismatch produced loud 'built for
newer iOS version (18.0) than being linked (10.0)' warnings and an
unresolved ___chkstk_darwin symbol on the iOS arm64 link.

Pass --ios-deployment-target / --mac-deployment-target from BUILD.gn,
sourced from darwin_sdk.gni's ios_deployment_target / mac_deployment_target,
so the Rust build can never drift from the C++ build's target version.

Tracking: shorebirdtech/_shorebird#2014
build_rust_updater previously let cargo write its target/ directly into
the source tree at flutter/engine/src/flutter/third_party/updater/target.
Two consequences:

1. The engine's existing 'rm -rf out/<config>' clobber on every build
   doesn't touch it, so compiled rust artifacts silently survived
   across runs and could mask source/env changes (we just hit this when
   a stale libzstd_sys.rlib reused on Sandpiper masked the
   IPHONEOS_DEPLOYMENT_TARGET fix from #123).
2. All GN configs (debug/release/ios/android/...) shared one cargo
   target dir, stepping on each other's rlibs.

Pass --target-dir to cargo, pointing at $root_out_dir/cargo_target,
and update build_rust_updater.gni's shorebird_updater_output_lib to
match. The cargo workspace now lives next to the rest of the GN build
output and is clobbered by the same 'rm -rf out' that has always
clobbered the C++ engine artifacts.

Tracking: shorebirdtech/_shorebird#2014
Follow-up to: #123
The updater's .cargo/config.toml sets '-C target-feature=+crt-static'
so rustc compiles the rlib expecting static-CRT linkage. But cargo
populates CARGO_CFG_TARGET_FEATURE from the rustc target spec's default
features, not from user rustflags, so +crt-static is invisible to
build scripts. The cc crate (used by transitive *-sys deps like
zstd-sys to compile their C sources) therefore falls back to /MD,
producing .obj files full of __imp_* references that the engine's /MT
link cannot resolve.

Symptom: engine link on Windows fails with LNK2019 unresolved external
symbol __imp_clock / __imp__wassert / __imp_qsort_s from zstd-sys's
zdict/cover/fastcover/divsufsort translation units, after the updater
rolled to a version whose ureq stack pulls in zstd-sys via its
compression features.

Fix: force /MT via the per-target CFLAGS env that cc honors. cl.exe
emits warning D9025 overriding '/MD' with '/MT' and uses the last one
specified -- /MT wins, the resulting .obj files reference the static
CRT, and the engine link succeeds.

This is another instance of the toolchain-consistency problem that
#123 solved for iOS deployment target. Every new platform-specific C
build setting we discover needs another env var threaded through
build_rust_updater.py. Longer term this argues for going rustc-direct
(Fuchsia/Chromium style), but for now we have one rust dep and the
env-var-per-setting pattern is tractable.

Tracking: shorebirdtech/_shorebird#2014
Follow-up to: #123, #124
mac_build.sh, linux_build.sh, and win_build.sh each had a leftover
'cd $UPDATER_SRC/library && cargo build --target ...' preamble from
before bdero's #120 GN/Ninja integration of the rust updater build.
mac_build.sh even had a FIXME at the top documenting the intent to
delete it. These preambles:

  1. Bypass the GN action entirely, so none of the env-var plumbing in
     build_rust_updater.py applies (no IPHONEOS_DEPLOYMENT_TARGET from
     #123, no CFLAGS_*_windows_msvc=/MT from #125, no Android NDK env).
  2. Write to the source-tree default cargo target dir at
     third_party/updater/target/, ignoring #124's redirect to
     $root_out_dir/cargo_target/, so the engine 'rm -rf out' clobber
     never touches their output.
  3. On the persistent Sandpiper runner this means stale rlibs from
     pre-fix builds keep getting reused, masking #123 entirely and
     producing the same iOS arm64 zstd_sys deployment-target failure
     after every fix attempt.

Delete the library cargo invocations from all three scripts. The GN
build of any engine target that depends transitively on
//flutter/shell/common/shorebird:updater (which is most of them) will
now invoke build_rust_updater.py via Ninja and produce libupdater.a /
updater.lib in the right place with the right env vars.

The patch tool's separate cargo build in mac_build.sh / linux_build.sh
is a standalone CLI not linked into the engine, so the GN build does
not cover it. Left in place with a TODO to migrate it later.

Tracking: shorebirdtech/_shorebird#2014
Follow-up to: #120, #123, #124, #125
…128)

The action only declared its stamp file as an output, which worked
when shorebird_updater_output_lib lived under //flutter/third_party/...
because GN treated source-tree paths as existing files needing no rule.
After #124 moved the cargo target dir into $root_out_dir/cargo_target,
the lib path became a build-dir path and Ninja correctly demands a
rule producing it. Without the lib in outputs:

  ninja: error: 'cargo_target/aarch64-linux-android/release/libupdater.a',
  needed by 'libflutter.so', missing and no known rule to make it

Add shorebird_updater_output_lib to the action's outputs alongside the
stamp file. The cargo invocation already produces the file at this
path; this just tells Ninja which rule is responsible.

Tracking: shorebirdtech/_shorebird#2014
Follow-up to: #124, #127
…130)

build_rust_updater.gni previously set shorebird_updater_supported based
only on target_os (is_android || is_ios || ...). But GN evaluates BUILD
files under every toolchain in use, including host and sub toolchains
that can have unusual (target_os, target_cpu) combinations we don't
handle. When a toolchain entered the `if (shorebird_updater_supported)`
block but hit none of the os/cpu cases that set
`shorebird_updater_rust_target`, GN blew up:

  ERROR at build_rust_updater.gni:72: Undefined identifier in string
    expansion.
    shorebird_updater_output_lib = "$...$shorebird_updater_rust_target..."
  "shorebird_updater_rust_target" is not currently in scope.

This happens on Windows host builds of android engine variants when
the host toolchain(s) land on a combo like (is_win, target_cpu != x64)
or similar, which our is_win branch doesn't cover.

Flip the logic: compute shorebird_updater_rust_target first, default
to empty, and derive `shorebird_updater_supported` from whether it
got a value. Unhandled combos become unsupported, so the consuming
BUILD.gn files' `if (shorebird_updater_supported)` gate cleanly skips
the updater for that toolchain — which is correct, since the updater
only needs to be built for toolchains whose final binary is the engine.

Tracking: shorebirdtech/_shorebird#2014
Follow-up to: #124, #127, #128
Rolls shorebirdtech/updater adacb41..8459296 (5 commits).

- fix: do not throw UpdateException on SHOREBIRD_NO_UPDATE (shorebirdtech/updater#334)
- chore(deps): update sha2 requirement in /patch in the patch-deps group (shorebirdtech/updater#330)
- chore(deps): bump the gh-deps group with 2 updates (shorebirdtech/updater#331)
- fix: return UpdateInProgress status instead of erroring when another update is running (shorebirdtech/updater#335)
- ci: build patch binary for aarch64-apple-darwin (shorebirdtech/updater#337)
Download the new aarch64-apple-darwin asset from the patch release and
upload it to GCS as patch-darwin-arm64.zip so Apple Silicon hosts can
fetch a native binary instead of hitting "Bad CPU type in executable"
when Rosetta is unavailable.

Bumps PATCH_VERSION to 0.3.0, which is the first release that ships an
explicit aarch64-apple-darwin asset (see shorebirdtech/updater#337).

Note: PATCH_VERSION should be confirmed against the actual version cut
from updater#337 before landing.
* feat: Add --trace flag to flutter build apk for build profiling

Adds a --trace option that produces a Chrome Trace Event Format JSON
file showing where time is spent across all build layers (flutter tool,
Gradle, flutter assemble targets). The output can be viewed in Perfetto
at https://ui.perfetto.dev.

* Add comment about multi-variant trace file collision risk

The intermediate trace file path is shared across all Gradle variants.
This is safe today since flutter build apk only runs one variant per
invocation, but would need per-variant paths if that changes.

* Add iOS build tracing support

- Add --trace option to flutter build ios / flutter build ipa
- Pass TRACE_FILE through Xcode build settings to xcode_backend.dart
- Instrument buildXcodeProject() in mac.dart with pre-xcode, xcode, and
  post-xcode spans
- Merge flutter assemble trace events from intermediate file
- Remove TRACE_FILE from toEnvironmentConfig() since both Android and
  iOS orchestrators compute intermediate paths directly

* feat: accept --trace on `flutter build appbundle`

The umbrella `flutter build apk` command already wired up the build-
trace option via `usesBuildTraceOption`, but a lot of real-world
workflows build the AppBundle (`flutter build appbundle`) directly —
most notably `shorebird release android` which always produces an AAB.
Without this, those invocations silently skip tracing.

The gradle/build-system plumbing is already shared, so adding the option
here is a one-line change that opts appbundle into the same trace file
Flutter already emits for APK builds.

* feat: enable Gradle --profile when build tracing is on

PR-116's trace only captures one `gradle bundleRelease`/`assembleRelease`
span on tid 2, so per-plugin task timing (compileReleaseKotlin,
mergeReleaseResources, linkReleaseNativeLibs, etc.) is invisible. Gradle
already has a built-in profiler that writes per-task durations to
`build/reports/profile/profile-*.html`; we just weren't enabling it.

Turn on `--profile` automatically when `--trace` is set so the profile
report lands alongside the trace. Downstream tooling (Shorebird) can
then aggregate per-task timings into an anonymized histogram — plugin
count, p50/p90/max task duration — to answer 'is native plugin compile
the bottleneck?' without collecting any plugin names.

* feat: per-Gradle-task trace events via init script

Before this, the only Gradle signal in a build trace was one giant
"gradle assembleRelease" span on tid 2 — useless for answering "where
is Gradle spending time" on plugin-heavy apps, which was half the
motivation for tracing in the first place.

This adds `flutter_trace_init.gradle`, an init script that registers a
TaskExecutionListener and emits one Chrome Trace Event Format entry
per Gradle task to an intermediate file. Each event carries:

  - name: the full task path (e.g. `:camera_android:compileReleaseKotlin`)
  - args.kind: a small bucket label (kotlin_compile, java_compile,
    dex, resources, packaging, bundle, transform, native_link, lint,
    flutter_gradle_plugin, other) so downstream tooling can aggregate
    without holding on to raw names
  - args.owner: the first colon segment (the subproject / plugin name)
  - args.skipped / upToDate / fromCache: cache-hit signal

Events land on tid=4 so Perfetto shows a clean four-tier layout:
flutter tool / native outer / flutter assemble / gradle tasks.

gradle.dart passes `-I=<init script>` and
`-Pflutter.gradle-trace-file=<path>` alongside the existing assemble
trace wiring, and merges the resulting file into the main trace the
same way assemble events are already merged.

Supersedes the earlier `--profile` addition for AAR builds (removed):
we were writing an HTML report nobody was parsing; the init script
produces Chrome Trace events that go straight into the trace file
users already open in Perfetto.

Timestamps use `System.currentTimeMillis() * 1000` (wall-clock micros)
to stay aligned with the existing flutter-tool and flutter-assemble
events, which also use wall clock.

* fix: classify compileReleaseKotlin/Java and AGP tasks correctly

The first pass matched 'compilekotlin'/'compilejava' substrings against the
full lowercased task path, but AGP-generated tasks are 'compileReleaseKotlin'
/ 'compileReleaseJavaWithJavac' — the variant name sits between the verb and
the language. Also, plugin owners like 'package_info_plus' were tripping the
'packaging' bucket because the owner name contains 'package'.

Switch to matching against the simple task name (last colon segment) and
require compile tasks to start with 'compile' + contain the language token.
Add dedicated buckets for R8/minify and lint — they dominate on release
builds (R8 alone was 33s on the heavy app validation) and were previously
hidden in 'other'.

* feat: broader kind classification for Gradle init-script tasks

Real-world validation found ~60% of task time sitting in 'other' on
a plugin-heavy app — mostly AGP scaffolding that has a recognizable
shape (writeAarMetadata, checkReleaseAarMetadata, generateRFile,
mergeReleaseNativeLibs, javaPreCompileRelease, etc.). Add:

  - 'java_compile' now also matches '*precompile*' (annotation-
    processor setup, javaPreCompileRelease)
  - 'resources' matches the merge/process/generate family
    (mergeReleaseNativeLibs is overloaded — kept under native_link)
  - 'native_link' for mergeReleaseNativeLibs, copyReleaseJniLibs*
  - 'gradle_scaffold' catch-all for aarmetadata, proguard, validate,
    check*, prepare*, generate*, copy*

Also restructured the classifier as a sequence of if/else-if with
explicit braces — the previous dangling-else chain was hard to
read after adding a dozen cases.

* refactor: rename trace surface with shorebird- prefix; add pod install span

This whole build-trace feature is specific to the Shorebird fork and
won't be upstreamed in its current form, so every public surface name
should make that obvious and stay out of identifiers upstream Flutter
might want to use later:

  --trace                      -> --shorebird-trace
  --trace-file                 -> --shorebird-trace-file  (assemble)
  -Ptrace-file                 -> -Pshorebird-trace-file  (gradle)
  -Pflutter.gradle-trace-file  -> -Pshorebird.gradle-trace-file
  TRACE_FILE                   -> SHOREBIRD_TRACE_FILE    (xcode env)
  flutter_trace_init.gradle    -> shorebird_trace_init.gradle
  flutter_assemble_trace.json  -> shorebird_assemble_trace.json
  flutter_gradle_task_trace.json -> shorebird_gradle_task_trace.json
  BuildInfo.traceFilePath      -> BuildInfo.shorebirdTraceFilePath
  FlutterOptions.kBuildTrace   -> FlutterOptions.kShorebirdTrace
  usesBuildTraceOption         -> usesShorebirdTraceOption
  BaseFlutterTask.traceFile    -> BaseFlutterTask.shorebirdTraceFile
  intermediates/flutter (trace dir) -> intermediates/shorebird

No behaviour change beyond the rename.

Also: add a 'pod install' subprocess span in mac.dart. Previously, on
plugin-heavy iOS apps there was a minute-plus gap between "flutter
build ios" starting and the xcode archive span showing up — that was
CocoaPods resolving, and it was invisible in the trace. Now it's a
first-class event on tid=1 with cat='subprocess' so Shorebird's
summarizer can bucket it without double-counting into pre-xcode setup.

* feat: record Flutter-tool HTTP downloads in the Shorebird build trace

Until now the trace captured Shorebird's own network calls (via the
TracingClient wrapper on the Shorebird side) and subprocess spans for
pod install / gradle / xcode, but Flutter's own HTTP — primarily
artifact downloads in `Cache.updateAll` routed through `Net._attempt`
— was completely invisible. On a fresh Flutter-tool state this is
tens of seconds across a dozen artifacts; with the user's laptop on a
slow connection, minutes.

Expose a process-wide `BuildTracer.current` that gradle.dart /
mac.dart set for the duration of a build. `Net._attempt` records a
span on tid=5 / cat='network' for each request with method, host,
and (on failure) error kind — no URLs or paths. That matches the
shape Shorebird's TracingClient already emits, so the Shorebird
summarizer sums both into `networkMs` without any changes.

Using a singleton is deliberate: plumbing a tracer through every
caller of `Net.fetchUrl` and every subprocess wrapper would touch a
large fraction of flutter_tools files for what is still a fork-only
feature. The static is scoped by set/clear in the build driver, and
Flutter commands are one-shot processes so there's no lifetime
concern across invocations.

* feat: Xcode per-phase + CocoaPods per-phase trace spans

Fills two of the remaining "giant opaque block" gaps:

**Xcode.** Pass `-showBuildTimingSummary` when a Shorebird build trace is
active. Xcode prints a `** Build Timing Summary **` section at the end
of the log listing per-phase aggregates (CompileC / SwiftCompile / Ld /
PhaseScriptExecution / CodeSign / ...). mac.dart parses it and emits
one event per phase on tid=4 / cat='xcode_phase', so the previously
monolithic ~50s `xcode archive` span now has a visible breakdown.

The flag is pure reporting: Apple documents it as affecting output
only, and the existing flutter_tools isn't using it today.

Synthetic timestamps note: the summary only gives aggregate durations
per phase, not wall-clock, so we lay the events out contiguously back
from the xcode-end timestamp. Distribution is accurate; individual
spans don't necessarily line up with real wall clock inside Xcode.

**CocoaPods.** When tracing is active, switch pod install from
ProcessManager.run to start+stream so we can timestamp phase
transitions as they happen. The `--verbose` output already has stable
markers (`Analyzing dependencies`, `Downloading dependencies`,
`Generating Pods project`, `Integrating client project`); we just
needed live lines to attach wall-clock to them. Emits four sub-spans
on tid=1 / cat='subprocess' named `pod install: <phase>`.

Non-tracing path is unchanged: pod install still uses the same
ProcessManager.run, no behavioural or perf difference.

* fix: don't add -quiet to xcodebuild when tracing is on

-quiet and -showBuildTimingSummary don't play well together: xcodebuild
suppresses the timing-summary block under -quiet, which is exactly
what we need to parse to produce per-phase Xcode spans. Skip -quiet
when a Shorebird build trace is active.

User-facing output is unchanged — Flutter already captures xcodebuild
stdout into buildResult.stdout and only echoes it on failure or in
verbose mode.

* feat: parse xcode build log via xcresulttool for per-subsection spans

Replaces the -showBuildTimingSummary approach: that flag is documented
but produces no output on Xcode 26 (and presumably 16+), so parsing
xcodebuild stdout for a "** Build Timing Summary **" block silently
yielded nothing on modern Xcode.

Switches to xcresulttool, which Flutter already points at via
-resultBundlePath. After xcodebuild finishes, we run

    xcrun xcresulttool get log --type build --path <bundle>

and walk the top-level subsections. Each subsection (one per target
build action — "Build target X from project Y", "Archive target Z",
etc.) has a real startTime + duration, so events land on an accurate
timeline instead of synthetic sequential spans.

Emitted on tid=4 with cat='xcode_subsection'. Subsection titles are
kept in the raw trace for local debug; Shorebird's privacy-safe
summary only records count + sum + p50/p90/max, no titles.

Best-effort: xcresulttool's JSON schema drifts across Xcode versions,
so parse failures are silent no-ops rather than errors.

Also revert the -quiet skip: it's no longer needed now that we don't
depend on xcodebuild stdout for timing data.

* chore: dart format trace-related files

* chore: roll dart_revision to aot_tools --trace support (shorebirdtech/dart-sdk#787)

* fix(trace): correct post-gradle / post-xcode span durations

- gradle.dart: hoist gradleEndMicros out of the tracer block so the
  post-gradle processing span starts at when Gradle actually finished,
  not gradleStartMicros + sw.elapsedMicroseconds (which ticks through
  the trace-merge work). Also clear BuildTracer.current before throwing
  on Gradle failure.
- mac.dart: collapse two adjacent DateTime.now() calls so pre-xcode
  and xcode spans are back-to-back, and hoist buildEndMicros so the
  post-xcode + outer flutter-build-ios spans end at the same instant.
- Drop redundant `!` null-checks on buildInfo.shorebirdTraceFilePath.

* refactor(trace): null-check hygiene + cross-link to sibling tracers

- Replace `!` null-assertions with local-variable null-checks in
  gradle.dart (gradleEndMicros), cocoapods.dart (closure-captured
  phase state), and xcode_backend.dart (SHOREBIRD_TRACE_FILE).
- Keep `!` only on the JSON-parse path in build_trace.dart where
  flutter's cast_nullable_to_non_nullable lint prefers it;
  documented.
- Add cross-link in BuildTraceEvent doc pointing at the sibling
  implementations in dart-sdk/pkg/aot_tools and shorebird_cli so
  future edits stay schema-compatible.

* feat(trace): real pids + process_name/thread_name metadata + gradle flow events

Chrome Trace Event Format carries pid/tid as producer-identifying
fields, not a shared coordination space. Drop the hardcoded tid
convention that flutter_tools / shorebird_cli / aot_tools had to
agree on and emit real pids everywhere:

- `BuildTracer.addCompleteEvent` now requires an explicit pid; the
  class gained `addProcessNameMetadata` / `addThreadNameMetadata` /
  `addFlowStart` for the Chrome Trace Event Format metadata and flow
  events, and the internal buffer is raw JSON maps so metadata/flow
  events can share the buffer with complete spans.
- `currentProcessId()` FFIs libc `getpid()` (or `GetCurrentProcessId`
  on Windows) since `dart:io` only exposes pids for spawned children.
- flutter_tool, net.dart, gradle.dart, mac.dart, cocoapods.dart,
  assemble.dart all emit on the calling process's real pid and name
  it via metadata events so Perfetto shows "flutter tool", "pod
  install", "flutter assemble" instead of bare numbers.
- `xcode_subsection` events go on a synthetic pid named "xcodebuild"
  (xcresult doesn't surface xcodebuild's real pid, and the compile
  sub-work is done by clang/swiftc children we never saw — synthetic
  is honest).
- Gradle init script uses `ProcessHandle.current().pid()` so
  per-task events live on the Gradle JVM's real pid; flutter_tool
  emits a flow-start (`ph: "s"`) at Gradle spawn with a random id
  passed via `-Pshorebird.gradle-trace-flow-id`, and the init script
  emits the matching `ph: "f"` on the first task so Perfetto draws
  a cross-process causality arrow.

Tests updated; summary bucketer follow-up will move from tid-based
to cat-based classification now that tids are no longer a shared
namespace.

* chore: roll dart_revision to aot_tools real-pid support (1376369b64e)

* fix(trace): label network row so flutter tool's HTTP downloads show as 'network' not 'Thread 5'

* refactor(trace): use dart:io's top-level pid; use gradle pid as flow id; embed variant in trace path

- Drop the FFI libc getpid()/GetCurrentProcessId() dance. `dart:io`
  exports the current process's pid as a top-level getter; the whole
  FFI block was me not checking the stdlib.
- ProcessUtils.stream: new optional `onStart(Process)` callback so
  callers can observe the spawned subprocess's pid without changing
  the return shape.
- gradle.dart uses onStart to read Gradle's real pid at spawn and
  emit the flow-start with id = gradle_pid. The init script reads
  its own pid via ProcessHandle.current().pid() for the matching
  flow-end, so both sides agree on the id without the
  -Pshorebird.gradle-trace-flow-id plumbing — which is now gone.
- Embed the assemble task name (e.g. `assembleFooRelease`,
  `bundleRelease`) in the intermediate trace paths so a hypothetical
  multi-variant Gradle run can't have per-variant FlutterTask
  instances stomp on each other's trace.

* refactor(trace): depend on shorebird_build_trace package instead of vendoring

Delete flutter_tools' local build_trace.dart; import BuildTracer /
BuildTraceEvent / PhaseTracker / currentProcessId from
package:shorebird_build_trace via a git: pubspec dep pointing at the
public shorebird monorepo.

Net: ~175 LOC of wire-format + tracer class gone from flutter_tools,
schema now impossible to drift from the canonical definition in
shorebirdtech/shorebird/packages/shorebird_build_trace.

Consumers (gradle.dart, mac.dart, cocoapods.dart, net.dart,
assemble.dart, xcode_backend.dart) get the same class by the same
name via the package import — just a path swap.

* chore: roll dart_revision to aot_tools shorebird_build_trace migration (030fa6cef1f)

* chore: roll dart_revision to aot_tools real-child-pid subprocess tracing

* refactor(trace): hide trace plumbing in shorebird/ session classes

- Bumps shorebird_build_trace ref to 0637612a (zone-scoped
  BuildTracer.current via runAsync, plus runSubprocess helpers).

- Extracts the ~60 lines of inline tracing in gradle.dart and
  ~140 lines in mac.dart into AndroidBuildTraceSession /
  IosBuildTraceSession under lib/src/shorebird/. Each session
  exposes a `run<T>(body)` that wraps body in BuildTracer.runAsync,
  so gradle.dart and mac.dart just call lifecycle hooks
  (onGradleFinished, onXcodeFinished, etc) and never touch
  BuildTracer.current themselves.

- Net change in upstream-touched files: gradle.dart -161 lines,
  mac.dart -206 lines, net.dart -33 lines. All trace plumbing now
  lives under lib/src/shorebird/ which has zero upstream-conflict
  footprint.

- net.dart's recordNetworkSpan closure moves to a
  NetworkTraceSpan helper class in lib/src/shorebird/. The class
  reads BuildTracer.current internally; net.dart just does
  `final span = NetworkTraceSpan.start(...); ... span.record(...);`.

- abort-on-error paths removed: zone unwinding guarantees .current
  is cleared on throw, so the explicit abortOnGradleFailure /
  abortOnFailure clears are no longer needed.

* chore(trace): roll shorebird_build_trace ref to d0b3280f (drop unused runSubprocessSync)

* refactor(trace): manual start/stop + regex task classification

Two related changes.

1. Drop the closure-wrapped trace sessions. Wrapping
   buildGradleApp / buildXcodeProject bodies in session.run(() async
   {...}) forced a reindent that would have broken upstream-merge
   compatibility for the next touch of those methods. Instead:

   - Bumps shorebird_build_trace ref to 97efa2ed (new static
     start/stop API + unchanged runAsync).
   - AndroidBuildTraceSession / IosBuildTraceSession constructors
     call BuildTracer.start(); finish / abortOn* call BuildTracer.stop().
   - gradle.dart / mac.dart go back to flat indentation: the only
     session touches are maybeStart + lifecycle hook calls.

   Tradeoff: if an uncaught exception escapes the build method,
   BuildTracer.current leaks. The flutter CLI exits the process
   shortly after, so leak is per-invocation, not cross-invocation.
   aot_tools keeps using runAsync (it can wrap easily).

2. Replace the gradle init script's if/else kind classifier with a
   regex table. Same semantics, same priority order, but the
   ordering is now explicit (a comment calls out which rules must
   precede which) and accidental substring matches like
   `:package_info_plus:` -> 'packaging' are easier to audit.

* refactor(trace): use BuildTracer + PhaseTracker helpers from shared library

Two DRY wins found during self-review:

- assemble.dart's writeTraceData was handrolling Chrome Trace Event
  Format maps directly. Replaced with BuildTracer.addProcessName /
  addThreadName / addCompleteEvent / writeToFile, which also picks
  up merge-with-existing-file behavior for free. ~40 lines -> ~15.

- cocoapods.dart's _runPodInstallStreamed reimplemented the exact
  phase-tracking pattern the library's PhaseTracker already provides
  (the library's doc comment literally cites pod install as the
  motivating example). Replaced with a PhaseTracker instance.
  ~20 lines -> ~5.

Drive-by: sort the `package:shorebird_build_trace` import into the
right section in both files so `dart analyze` stops complaining
about directive ordering.

* refactor(trace): use TraceSchema constants for all cross-repo strings

Replaces inline string literals for event categories, gradle task
kinds, pod install phase names, and span-name prefixes with
TraceSchema.* references from the shared shorebird_build_trace
package (new in d2099fe7). Makes the contract with shorebird_cli
explicit — rename a constant there and this side stops compiling
rather than silently diverging.

- Android/iOS session classes: cat/name constants for the flutter,
  gradle, xcode, subprocess, xcode_subsection events they emit.
- cocoapods.dart: pod install name + phase-transition strings.
- assemble.dart: cat for assemble spans.
- network_trace_span.dart: cat for network spans.
- gradle.dart: instead of passing `'flutter build apk/appbundle'`
  as an opaque string, passes the target suffix (`apk`/`appbundle`)
  and the session constructs the span name from
  `TraceSchema.flutterBuildSpanPrefix`. Keeps TraceSchema import
  out of upstream-touched gradle.dart.
- shorebird_trace_init.gradle: can't import Dart, so its kind
  literals stay — added a KEEP IN SYNC comment pointing at
  TraceSchema.gradleKind* so any new entry lands on both sides.
- Bumps shorebird_build_trace ref to d2099fe7.

* refactor(trace): emit via TraceCategory/GradleTaskKind enums

Bumps shorebird_build_trace ref to 27f5971e (TraceSchema class
replaced by TraceCategory + GradleTaskKind enums plus TraceNames
for format-prefix constants).

Producer-side changes are mechanical: TraceSchema.catFlutter becomes
TraceCategory.flutter.wireName, TraceSchema.podPhaseAnalyzing
becomes PodInstallPhase.analyzing.wireName, etc. Span-name prefixes
(flutterBuildSpanPrefix, podInstallNamePrefix, ...) moved to
TraceNames; they're format templates not enumerated values.

Init script's KEEP-IN-SYNC comment now points at GradleTaskKind.

* chore(trace): roll shorebird_build_trace ref to cae6c56e (map-keyed accumulator)

* chore(trace): roll shorebird_build_trace ref to 2a56c3e3 (Duration internally)

* refactor(trace): take DateTime/Duration from shorebird_build_trace

Bumps shorebird_build_trace ref to bd5452360acc5371b30a265c85187c061df674cb.
Producer sites use DateTime.now() instead of
DateTime.now().microsecondsSinceEpoch, and pass DateTime / Duration to
the library's addCompleteEvent, addFlowStart, addFlowEnd,
recordNetworkSpan, etc.

* chore(trace): roll shorebird_build_trace ref to cff436f6 (schema v7)

* chore: dart format 5 test files to satisfy CI

* fix: analyzer errors in upstream-merged shorebird fork

Shorebird DEV CI runs `dart analyze` on the whole flutter_tools
package, unlike GitHub Actions which only runs test/general.shard.
The prior squashed-merge of upstream 3.35.7 carried two pre-existing
issues that analyze surfaces:

- build_macos_test.dart:1139 passed undefined `artifacts` and
  `processUtils` named params to BuildCommand (which doesn't accept
  them). Removed — the test still exercises the Shorebird YAML
  post-build step, which was its actual purpose.
- build_windows.dart imported shorebird_yaml.dart but never used it.

* refactor(trace): table-lookup for pod install phase markers

Replace the four-branch if/else-if chain with a const map from log-line
marker to PodInstallPhase + a single-loop lookup. Adding a new phase
now means adding a map entry instead of a new branch, and the markers
sit next to each other at the top of the file where they're easier to
audit for staleness against newer CocoaPods releases.

* test: skip broken macOS shorebird.yaml-injection test

The test expects updateShorebirdYaml to mutate shorebird.yaml during
build, but the override's TestBuildSystem.all stubs out the assets
build target where that mutation runs. The test was previously
un-runnable due to a compile error (undefined artifacts/processUtils
params); now that it compiles again, mark it skip with an explanation
rather than let it fail. Also adds the missing OperatingSystemUtils
override present in every other test in the file.

* chore: dart format build_macos_test.dart after edit

* test: skip broken Windows shorebird.yaml-injection test

Same situation as the macOS analogue: the test expects
updateShorebirdYaml to mutate shorebird.yaml during the windows
build, but the overridden FakeProcessManager only runs cmake
+ cmake --build, neither of which drives the assets target where
that mutation lives. Skipping pending a test that exercises
updateShorebirdYaml directly.
Stream subprocess output in real time when VERBOSE is set, and dump
stdout/stderr on failure. This helps diagnose flaky timeout failures
in CI where buffered output is lost when the test times out.
@eseidel eseidel force-pushed the feat/aar-release-version branch from 57f5ed5 to b0de23a Compare May 1, 2026 17:51
Adds SHOREBIRD_MODULE_VERSION env var support to compileShorebirdYaml.
When set, the value is written into the compiled shorebird.yaml as
module_version, which the updater then sends to the server (alongside
release_version) for add-to-app patch lookup.

The shorebird CLI passes this env var through when running
`flutter build aar` or `flutter build ios-framework` for module
releases (see shorebirdtech/shorebird#3674).
@eseidel eseidel force-pushed the feat/aar-release-version branch from b0de23a to e4ce42c Compare May 1, 2026 17:59
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.