Skip to content

Fix Android license detection for cmdline-tools 23.0+ - #191554

Merged
auto-submit[bot] merged 5 commits into
flutter:masterfrom
ik020:fix/android-cli-license-detection
Aug 29, 2026
Merged

auto-submit[bot] merged 5 commits into
flutter:masterfrom
ik020:fix/android-cli-license-detection

Conversation

@ik020

@ik020 ik020 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #191487

Android SDK cmdline-tools 23.0 deprecated sdkmanager --licenses in favor of the new android CLI. Running sdkmanager --licenses now only prints a deprecation warning instead of the parseable license summary Flutter previously relied on:

WARNING: The SDK Manager CLI tool (sdkmanager) is deprecated. Android CLI will be used instead.
The 'android' binary can also be found in the cmdline-tools directory, and 'android sdk' is the replacement for 'sdkmanager'.
To learn more about the Android CLI and how to use it, see the documentation (https://d.android.com/tools/agents/android-cli)
Warning: The --licenses option is no longer needed.

None of the existing regexes in licensesAccepted match this output, so flutter doctor incorrectly reports Android license status unknown even when licenses are actually accepted.

Approach

I initially considered treating the new deprecation message as LicensesAccepted.all, but testing against a real cmdline-tools 23.0 install showed this message prints identically whether or not the licenses directory exists — so it can't be trusted as a signal of actual license state. I verified this by temporarily renaming my <sdk>/licenses directory and re-running sdkmanager --licenses; the output was byte-for-byte identical either way.

I also checked the new android CLI's --help output (sdk, sdk install, info) — there's no license-status subcommand or flag exposed in this version, so there's no better structured signal to query instead.

Since the SDK's actual license acceptance state is still tracked on disk under <sdk>/licenses/ (this is presumably what Gradle checks directly, since Gradle builds still succeed after this cmdline-tools update), this PR adds a narrow, additive fallback:

  • When sdkmanager's output matches the specific new-CLI deprecation message (and only then — not for arbitrary unparseable/garbage output), licensesAccepted checks the licenses/ directory on disk directly instead of trusting stdout.
  • All existing regex-based parsing for older sdkmanager versions is untouched.

Known limitation

This fallback can only distinguish "some license files are present and non-empty" (→ all) from "no license files at all" (→ none). It cannot reproduce the previous LicensesAccepted.some state for the new CLI, since that information is no longer exposed by the tool in any form I could find. Happy to adjust the approach if maintainers have a preference here.

Tests

Added two regression tests reproducing the exact real-world output captured from a Windows machine running cmdline-tools 23.0:

  • licensesAccepted falls back to the licenses directory when sdkmanager output is unparseable (new Android CLI, licenses present)
  • licensesAccepted falls back to none when sdkmanager output is unparseable and no licenses are present (new Android CLI, licenses missing)

All existing tests in android_workflow_test.dart continue to pass (35/35).

Also manually verified end-to-end: flutter doctor -v on the affected machine now correctly reports All Android licenses accepted. instead of Android license status unknown.

Android SDK cmdline-tools 23.0 deprecated 'sdkmanager --licenses' in favor of the new 'android' CLI. Running 'sdkmanager --licenses' now only prints a deprecation warning ('Warning: The --licenses option is no longer needed.') instead of the parseable license summary Flutter previously relied on, so none of the existing regexes match and flutter doctor incorrectly reports Android license status as unknown.

This adds a narrow fallback: when sdkmanager's output is recognized as this specific new-CLI deprecation message (and only then, not for arbitrary unparseable output), licensesAccepted checks the SDK's licenses directory on disk directly instead. This was verified against a real cmdline-tools 23.0 install, including confirming that the deprecation warning is printed identically regardless of whether licenses are actually accepted, which is why the fallback checks the licenses directory rather than trusting the warning text itself.

Note: this fallback can only distinguish 'some license files are present' from 'no license files at all', so it cannot reproduce the previous LicensesAccepted.some state for the new CLI.

Fixes flutter#191487
@ik020
ik020 requested a review from a team as a code owner August 23, 2026 11:28
@ik020
ik020 requested review from reidbaker and removed request for a team August 23, 2026 11:28
@google-cla

google-cla Bot commented Aug 23, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added tool Affects the "flutter" command-line tool. See also t: labels. team-android Owned by Android platform team labels Aug 23, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a fallback mechanism for checking Android SDK licenses when the sdkmanager --licenses output is unparseable due to deprecation warnings in newer Android CLI tools. If the warning is detected, the validator checks the licenses directory on disk to determine if licenses have been accepted. Tests have been added to verify this fallback behavior. Feedback was provided to handle potential FileSystemException errors when calling listSync() on the licenses directory to prevent crashes.

Comment on lines +518 to +522
final Directory licensesDir = _androidSdk.directory.childDirectory('licenses');
final bool hasAcceptedLicense = licensesDir.listSync().whereType<File>().any(
(File file) => file.lengthSync() > 0,
);
return hasAcceptedLicense ? LicensesAccepted.all : LicensesAccepted.none;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Calling listSync() on a directory can throw a FileSystemException if the directory does not exist, is actually a file, or if there are permission issues. To prevent potential crashes in flutter doctor, we should check if the directory exists and handle any FileSystemException gracefully.

    final Directory licensesDir = _androidSdk.directory.childDirectory('licenses');
    if (!licensesDir.existsSync()) {
      return LicensesAccepted.none;
    }
    try {
      final bool hasAcceptedLicense = licensesDir.listSync().whereType<File>().any(
        (File file) => file.lengthSync() > 0,
      );
      return hasAcceptedLicense ? LicensesAccepted.all : LicensesAccepted.none;
    } on FileSystemException {
      return LicensesAccepted.none;
    }

Addresses review feedback: listSync() on the licenses directory can throw a FileSystemException if the directory doesn't exist, is actually a file, or there are permission issues (e.g. a race between the licensesAvailable check and use). Wrap the disk check in a try/on FileSystemException and return LicensesAccepted.unknown in that case instead of letting flutter doctor crash.

Added a regression test simulating this scenario.
@mboetger mboetger closed this Aug 25, 2026
@jmagman

jmagman commented Aug 25, 2026

Copy link
Copy Markdown
Member

Whoops we closed this a little fast, that's addressed in the description:

I also checked the new android CLI's --help output (sdk, sdk install, info) — there's no license-status subcommand or flag exposed in this version, so there's no better structured signal to query instead.

Huh that's really unfortunate.

@jmagman jmagman reopened this Aug 25, 2026
@fluttergithubbot

Copy link
Copy Markdown
Contributor

An existing Git SHA, 10a5b71fb0681dee2f39f85d8bafbfcd625ff472, 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.

@jmagman
jmagman requested review from gmackall and removed request for reidbaker August 25, 2026 21:19
@gmackall gmackall added the CICD Run CI/CD label Aug 28, 2026
gmackall
gmackall previously approved these changes Aug 28, 2026
Comment thread packages/flutter_tools/lib/src/android/android_workflow.dart Outdated
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 28, 2026
@gmackall gmackall added the CICD Run CI/CD label Aug 28, 2026
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 28, 2026
@gmackall gmackall added the CICD Run CI/CD label Aug 28, 2026
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Aug 28, 2026
Comment thread packages/flutter_tools/lib/src/android/android_workflow.dart
@gmackall gmackall added the CICD Run CI/CD label Aug 28, 2026
@gmackall gmackall added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 29, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Aug 29, 2026
Merged via the queue into flutter:master with commit 9d0f24e Aug 29, 2026
27 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 29, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Aug 30, 2026
flutter/flutter@8d8c1aa...c978386

2026-08-30 [email protected] Roll Skia from ce359c7fbfe6 to 588b550a4dd8 (1 revision) (flutter/flutter#192040)
2026-08-30 [email protected] Roll Skia from 3ae8e3d1e335 to ce359c7fbfe6 (1 revision) (flutter/flutter#192037)
2026-08-30 [email protected] Roll Fuchsia Linux SDK from J123CwfDPYyVDpkMl... to o9DikEfRoFyVK3LKD... (flutter/flutter#192031)
2026-08-29 [email protected] Make the AbsorbPointer sample show the difference from IgnorePointer (flutter/flutter#188940)
2026-08-29 [email protected] Roll Dart SDK from 391ff83cd1d3 to 76abdf94faa8 (1 revision) (flutter/flutter#192021)
2026-08-29 [email protected] Roll Skia from b392fb672d13 to 3ae8e3d1e335 (1 revision) (flutter/flutter#192020)
2026-08-29 [email protected] Roll Skia from 0b4249b26b38 to b392fb672d13 (6 revisions) (flutter/flutter#192016)
2026-08-29 [email protected] Fixes for texture-backed gradients (flutter/flutter#191925)
2026-08-29 [email protected] Roll Dart SDK from ae63a6eca3f1 to 391ff83cd1d3 (3 revisions) (flutter/flutter#192010)
2026-08-29 [email protected] Fix Android license detection for cmdline-tools 23.0+ (flutter/flutter#191554)
2026-08-29 [email protected] [flutter_tools] Pause web server requests until initial compilation finishes (flutter/flutter#191990)
2026-08-28 [email protected] fix(workflow): Mac Verify Binaries needs `Linux mac_android_aot_engine` (flutter/flutter#191999)
2026-08-28 [email protected] Roll Fuchsia Linux SDK from dDxH8G5cDBP602eyG... to J123CwfDPYyVDpkMl... (flutter/flutter#191984)
2026-08-28 [email protected] Update scheduled workflow for more tasks, add goldctl update (flutter/flutter#191991)
2026-08-28 [email protected] Update no-main-prs to leave a comment (flutter/flutter#191973)
2026-08-28 [email protected] [AGP 9.1.0 Migration #4] Replace plugin build-type copy with initWith on public DSL (flutter/flutter#191606)
2026-08-28 [email protected] Roll Skia from fe0b9a5261f9 to 0b4249b26b38 (1 revision) (flutter/flutter#191974)
2026-08-28 [email protected] [UIScene] Migrate dev/benchmarks/macrobenchmarks to UIScene lifecycle (flutter/flutter#191648)
2026-08-28 [email protected] Uiscene migrate remaining apps (flutter/flutter#191652)
2026-08-28 [email protected] [tool] Migrate SymbolizeCommand to modular dependency injection (flutter/flutter#190744)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
@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 Sep 1, 2026
victorsanni pushed a commit to victorsanni/packages that referenced this pull request Sep 9, 2026
…r#12693)

flutter/flutter@8d8c1aa...c978386

2026-08-30 [email protected] Roll Skia from ce359c7fbfe6 to 588b550a4dd8 (1 revision) (flutter/flutter#192040)
2026-08-30 [email protected] Roll Skia from 3ae8e3d1e335 to ce359c7fbfe6 (1 revision) (flutter/flutter#192037)
2026-08-30 [email protected] Roll Fuchsia Linux SDK from J123CwfDPYyVDpkMl... to o9DikEfRoFyVK3LKD... (flutter/flutter#192031)
2026-08-29 [email protected] Make the AbsorbPointer sample show the difference from IgnorePointer (flutter/flutter#188940)
2026-08-29 [email protected] Roll Dart SDK from 391ff83cd1d3 to 76abdf94faa8 (1 revision) (flutter/flutter#192021)
2026-08-29 [email protected] Roll Skia from b392fb672d13 to 3ae8e3d1e335 (1 revision) (flutter/flutter#192020)
2026-08-29 [email protected] Roll Skia from 0b4249b26b38 to b392fb672d13 (6 revisions) (flutter/flutter#192016)
2026-08-29 [email protected] Fixes for texture-backed gradients (flutter/flutter#191925)
2026-08-29 [email protected] Roll Dart SDK from ae63a6eca3f1 to 391ff83cd1d3 (3 revisions) (flutter/flutter#192010)
2026-08-29 [email protected] Fix Android license detection for cmdline-tools 23.0+ (flutter/flutter#191554)
2026-08-29 [email protected] [flutter_tools] Pause web server requests until initial compilation finishes (flutter/flutter#191990)
2026-08-28 [email protected] fix(workflow): Mac Verify Binaries needs `Linux mac_android_aot_engine` (flutter/flutter#191999)
2026-08-28 [email protected] Roll Fuchsia Linux SDK from dDxH8G5cDBP602eyG... to J123CwfDPYyVDpkMl... (flutter/flutter#191984)
2026-08-28 [email protected] Update scheduled workflow for more tasks, add goldctl update (flutter/flutter#191991)
2026-08-28 [email protected] Update no-main-prs to leave a comment (flutter/flutter#191973)
2026-08-28 [email protected] [AGP 9.1.0 Migration flutter#4] Replace plugin build-type copy with initWith on public DSL (flutter/flutter#191606)
2026-08-28 [email protected] Roll Skia from fe0b9a5261f9 to 0b4249b26b38 (1 revision) (flutter/flutter#191974)
2026-08-28 [email protected] [UIScene] Migrate dev/benchmarks/macrobenchmarks to UIScene lifecycle (flutter/flutter#191648)
2026-08-28 [email protected] Uiscene migrate remaining apps (flutter/flutter#191652)
2026-08-28 [email protected] [tool] Migrate SymbolizeCommand to modular dependency injection (flutter/flutter#190744)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
victorsanni pushed a commit to victorsanni/packages that referenced this pull request Sep 9, 2026
…r#12693)

flutter/flutter@8d8c1aa...c978386

2026-08-30 [email protected] Roll Skia from ce359c7fbfe6 to 588b550a4dd8 (1 revision) (flutter/flutter#192040)
2026-08-30 [email protected] Roll Skia from 3ae8e3d1e335 to ce359c7fbfe6 (1 revision) (flutter/flutter#192037)
2026-08-30 [email protected] Roll Fuchsia Linux SDK from J123CwfDPYyVDpkMl... to o9DikEfRoFyVK3LKD... (flutter/flutter#192031)
2026-08-29 [email protected] Make the AbsorbPointer sample show the difference from IgnorePointer (flutter/flutter#188940)
2026-08-29 [email protected] Roll Dart SDK from 391ff83cd1d3 to 76abdf94faa8 (1 revision) (flutter/flutter#192021)
2026-08-29 [email protected] Roll Skia from b392fb672d13 to 3ae8e3d1e335 (1 revision) (flutter/flutter#192020)
2026-08-29 [email protected] Roll Skia from 0b4249b26b38 to b392fb672d13 (6 revisions) (flutter/flutter#192016)
2026-08-29 [email protected] Fixes for texture-backed gradients (flutter/flutter#191925)
2026-08-29 [email protected] Roll Dart SDK from ae63a6eca3f1 to 391ff83cd1d3 (3 revisions) (flutter/flutter#192010)
2026-08-29 [email protected] Fix Android license detection for cmdline-tools 23.0+ (flutter/flutter#191554)
2026-08-29 [email protected] [flutter_tools] Pause web server requests until initial compilation finishes (flutter/flutter#191990)
2026-08-28 [email protected] fix(workflow): Mac Verify Binaries needs `Linux mac_android_aot_engine` (flutter/flutter#191999)
2026-08-28 [email protected] Roll Fuchsia Linux SDK from dDxH8G5cDBP602eyG... to J123CwfDPYyVDpkMl... (flutter/flutter#191984)
2026-08-28 [email protected] Update scheduled workflow for more tasks, add goldctl update (flutter/flutter#191991)
2026-08-28 [email protected] Update no-main-prs to leave a comment (flutter/flutter#191973)
2026-08-28 [email protected] [AGP 9.1.0 Migration flutter#4] Replace plugin build-type copy with initWith on public DSL (flutter/flutter#191606)
2026-08-28 [email protected] Roll Skia from fe0b9a5261f9 to 0b4249b26b38 (1 revision) (flutter/flutter#191974)
2026-08-28 [email protected] [UIScene] Migrate dev/benchmarks/macrobenchmarks to UIScene lifecycle (flutter/flutter#191648)
2026-08-28 [email protected] Uiscene migrate remaining apps (flutter/flutter#191652)
2026-08-28 [email protected] [tool] Migrate SymbolizeCommand to modular dependency injection (flutter/flutter#190744)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
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 team-android Owned by Android platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

flutter doctor reports Android license status unknown with Android SDK Command-line Tools 23.0

5 participants