Skip to content

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

Open
ik020 wants to merge 2 commits into
flutter:masterfrom
ik020:fix/android-cli-license-detection
Open

Fix Android license detection for cmdline-tools 23.0+#191554
ik020 wants to merge 2 commits into
flutter:masterfrom
ik020:fix/android-cli-license-detection

Conversation

@ik020

@ik020 ik020 commented Aug 23, 2026

Copy link
Copy Markdown

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

1 participant