Skip to content

[tool] Fix libapp.so dropped from APK/app bundle#188119

Merged
auto-submit[bot] merged 14 commits into
flutter:masterfrom
gmackall:fix-libapp-so-jnilibs-186810
Jun 23, 2026
Merged

[tool] Fix libapp.so dropped from APK/app bundle#188119
auto-submit[bot] merged 14 commits into
flutter:masterfrom
gmackall:fix-libapp-so-jnilibs-186810

Conversation

@gmackall

@gmackall gmackall commented Jun 17, 2026

Copy link
Copy Markdown
Member

Summary

libapp.so could be silently dropped from release APKs
and app bundles, surfacing as either:

  • a runtime crash on launch — VM snapshot invalid and could not be inferred from settings — for APKs, or
  • a Release app bundle failed to strip debug symbols from native libraries
    build failure for app bundles.

Root cause

Regression from #181275, which moved libapp.so from a jar dependency onto a
Flutter Gradle Plugin source-set jniLibs directory. That delivery was fragile
in two ways, both of which dropped libapp.so from the merged native libraries
(while libflutter.so/libdartjni.so, delivered as AAR dependencies, were
unaffected — which is why the failure looked asymmetric):

  1. The source-set jniLibs srcDir was resolved eagerly (.get().asFile) at
    :app configuration time, while the copy task wrote lazily. When :app was
    evaluated before its build directory had been redirected — a combined
    subprojects { … evaluationDependsOn(":app") } block (the pre-Change project.buildDir in standalone subprojects property #91030 template
    shape) together with a plugin whose Gradle subproject name sorts before
    :app — the two disagreed on the build directory and the staged libapp.so
    was never merged. (Flutter 3.44.0: appbundle release fails with "Release app bundle failed to strip debug symbols from native libraries" #186810)
  2. The copy task wrote into a directory nested inside the Flutter task's own
    output directory, creating overlapping task outputs that undermined Gradle's
    incremental checks — e.g. a flavored project where a prior single-ABI build
    (a flutter run on one device) left the other ABIs missing libapp.so.
    (After updating to flutter 3.44.1 - release - versions of the app crash with VM snapshot failed #187388)

Fix

Stage libapp.so (and any bundled native assets) through a dedicated
CopyFlutterJniLibsTask whose output is registered on each variant via AGP's
variant API: variant.sources.jniLibs.addGeneratedSourceDirectory(...). AGP then
owns the task dependency, resolves the output path lazily (correct regardless of
project evaluation order or build-dir redirection), keeps it in its own output
directory (no overlapping outputs), and strips/extracts debug symbols from it
like any other native library. This restores the robustness of the original
jar-based inclusion while keeping libapp.so strippable.

Tests

New integration test gradle_libapp_so_packaging_test.dart covering both
triggers: the combined subprojects block + a plugin sorted before :app, and
a flavored single-ABI build preceding a multi-ABI build.

Fixes #186810
Fixes #187388
Fixes #187553

…robustness)

libapp.so could be missing from the merged native libraries - causing a
"VM snapshot invalid" crash for APKs, or a "failed to strip debug symbols"
build failure for app bundles - in two scenarios:

* A combined "subprojects { ... evaluationDependsOn(\":app\") }" block in the
  root android build.gradle together with a plugin whose Gradle subproject
  sorts before ":app". This evaluated ":app" before its build directory was
  redirected, so the source-set jniLibs srcDir (resolved eagerly via
  .get().asFile) disagreed with the destination copyJniLibs writes to
  (resolved lazily), dropping libapp.so.
  flutter#186810

* Flavored builds where a prior single-ABI build (e.g. a flutter run on one
  device) left the build up to date for only that ABI. copyJniLibs wrote into
  a directory nested inside the Flutter task's own output directory, creating
  overlapping task outputs that undermined incremental checks.
  flutter#187388

Both stem from flutter#181275 moving libapp.so from a jar dependency onto a
source-set jniLibs directory.

Register the source-set srcDir from the lazy provider (not .get().asFile) so
it resolves to the same (possibly redirected) build directory as the copy
destination, and move the staged jniLibs directory to a sibling of the
Flutter task output directory to avoid overlapping outputs. Adds integration
tests covering both scenarios.
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot added platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels. team-android Owned by Android platform team labels Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 17, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 17, 2026
- Remove the stale comment left over from the abandoned source-set approach.
- Add KDoc to CopyFlutterJniLibsTask and PathSensitivity.RELATIVE on its input
  directory for build-cache relocatability.
- Use getByType (not findByType) for AndroidComponentsExtension so a
  misconfiguration fails loudly instead of silently skipping libapp.so.
- Extract a shared flutterCompileTaskName() helper used by both the variant API
  callback and addFlutterDeps, with a comment explaining the name-based lookup
  (the callback runs before the task is registered).
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 22, 2026
@gmackall

Copy link
Copy Markdown
Member Author

Does this also fix #187553? I thought we figured it would. Can you add the test from PR #187688 and see? If so I'll close that PR if you move the test into this one.

Ah yes I forgot to add that test case. Will double check it fixes and add test

The test passed as you had written. However, the cache setup and the local engine args both seemed unnecessary so I removed them. Let me know if they were actually structurally important.

@gmackall gmackall added the CICD Run CI/CD label Jun 22, 2026
@gmackall gmackall added autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD and removed CICD Run CI/CD autosubmit Merge PR when tree becomes green via auto submit App labels Jun 23, 2026
@fluttergithubbot

Copy link
Copy Markdown
Contributor

An existing Git SHA, 086b13db3e42ba87febd7b65c76a92127b5d6fe2, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 23, 2026
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 23, 2026
@gmackall gmackall added the CICD Run CI/CD label Jun 23, 2026
@auto-submit auto-submit Bot added this pull request to the merge queue Jun 23, 2026
Merged via the queue into flutter:master with commit 6efbbad Jun 23, 2026
163 of 164 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jun 23, 2026
@gmackall gmackall added cp: beta cherry pick this pull request to beta release candidate branch cp: stable cherry pick this pull request to stable release candidate branch labels Jun 24, 2026
@walley892 walley892 added cp: beta cherry pick this pull request to beta release candidate branch and removed cp: beta cherry pick this pull request to beta release candidate branch labels Jun 25, 2026
via-guy pushed a commit to via-guy/flutter that referenced this pull request Jun 26, 2026
## Summary

`libapp.so` could be silently dropped from release APKs
and app bundles, surfacing as either:

- a runtime crash on launch — `VM snapshot invalid and could not be
inferred from
  settings` — for APKs, or
- a `Release app bundle failed to strip debug symbols from native
libraries`
  build failure for app bundles.

## Root cause

Regression from flutter#181275, which moved `libapp.so` from a jar dependency
onto a
Flutter Gradle Plugin source-set `jniLibs` directory. That delivery was
fragile
in two ways, both of which dropped `libapp.so` from the merged native
libraries
(while `libflutter.so`/`libdartjni.so`, delivered as AAR dependencies,
were
unaffected — which is why the failure looked asymmetric):

1. The source-set `jniLibs` `srcDir` was resolved eagerly
(`.get().asFile`) at
`:app` configuration time, while the copy task wrote lazily. When `:app`
was
   evaluated before its build directory had been redirected — a combined
`subprojects { … evaluationDependsOn(":app") }` block (the pre-flutter#91030
template
shape) together with a plugin whose Gradle subproject name sorts before
`:app` — the two disagreed on the build directory and the staged
`libapp.so`
   was never merged. (flutter#186810)
2. The copy task wrote into a directory nested inside the Flutter task's
own
output directory, creating overlapping task outputs that undermined
Gradle's
incremental checks — e.g. a flavored project where a prior single-ABI
build
(a `flutter run` on one device) left the other ABIs missing `libapp.so`.
   (flutter#187388)

## Fix

Stage `libapp.so` (and any bundled native assets) through a dedicated
`CopyFlutterJniLibsTask` whose output is registered on each variant via
AGP's
variant API:
[`variant.sources.jniLibs.addGeneratedSourceDirectory(...)`](https://developer.android.com/reference/tools/gradle-api/9.1/com/android/build/api/variant/SourceDirectories#addStaticSourceDirectory(kotlin.String)).
AGP then
owns the task dependency, resolves the output path lazily (correct
regardless of
project evaluation order or build-dir redirection), keeps it in its own
output
directory (no overlapping outputs), and strips/extracts debug symbols
from it
like any other native library. This restores the robustness of the
original
jar-based inclusion while keeping `libapp.so` strippable.

## Tests

New integration test `gradle_libapp_so_packaging_test.dart` covering
both
triggers: the combined `subprojects` block + a plugin sorted before
`:app`, and
a flavored single-ABI build preceding a multi-ABI build.

Fixes flutter#186810
Fixes flutter#187388
Fixes flutter#187553
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD cp: beta cherry pick this pull request to beta release candidate branch cp: stable cherry pick this pull request to stable release candidate branch platform-android Android applications specifically team-android Owned by Android platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

4 participants