Skip to content

The logic used to find a JDK in various tool operations is unclear and confusing #124252

Closed

Description

@andrewkolos

Investigation into #122609 revealed that the logic used to to find a java binary for Java-dependent activites was inconsistent across those activities. For more about that logic and how it was inconsistent, see this comment from #122600. While this issue was fixed by making the implementations of Java-finding logic consistent across the tool, this consistency is fragile; because these implementations exist independently of each other. This also isn't the first time this has been noticed (see #9429).

The tool code should be refactored to 1) make JDK-finding logic as explicit as possible1 and 2) make JDK-finding logic as consistent as possible. This should reduce the chance of future confusion and/or introduction of bugs.

Tangentially related: #121501, #106416

Footnotes

  1. For example, gradlew and Android SDK tools (such as avdmanager and sdkmanager) look for Java by first consulting JAVA_HOME on the environment and then java on the path. When invoking those tools, the flutter tool will set JAVA_HOME to the path of the Android Studio-bundled JDK if it exists. This means that the order in which we look for the JDK for these operations is 1) the Android-Studio bundled JDK, 2) JAVA_HOME, and then 3) java on PATH (which java). However, the existence of 2 and 3 is not obvious to those reading only the flutter tool code. ↩

Activity

  1. added
    toolAffects the "flutter" command-line tool. See also t: labels.
    c: tech-debtTechnical debt, code quality, testing, etc.
    on Apr 5, 2023
  2. self-assigned this
    on Apr 5, 2023
  3. andrewkolos commented on Apr 5, 2023

    @andrewkolos
    ContributorAuthor

    Replaced placeholder text.

  4. added
    t: flutter doctorProblem related to the "flutter doctor" tool
    platform-androidAndroid applications specifically
    P2Important issues not at the top of the work list
    P3Issues that are less important to the Flutter project
    and removed
    P2Important issues not at the top of the work list
    P3Issues that are less important to the Flutter project
    on Apr 5, 2023
  5. gnprice commented on Apr 7, 2023

    @gnprice
    Member

    Thanks for filing this!

    I think one of the things that's made this a bit tricky, and led to the existing situation where we don't simply use the same logic everywhere, is that there are a couple of different kinds of ways that we invoke a JDK:

    • In some places (1a and 2 in your list), we run a java executable directly. These are a good fit for the existing findJavaBinary method, which provides the path of a java executable to run.
    • In other places (1b, 3, 4), we run a wrapper script that finds and runs java. (Either the Gradle wrapper gradlew, or the Android SDK command-line tools like avdmanager and sdkmanager.) We can't directly tell these what JDK to use in the form of a path to the java executable, so findJavaBinary doesn't directly help.

    We can and should tell those wrapper scripts how to find the exact same JDK we use elsewhere. But the way we tell them will just have to be a bit more subtle.

    The key is that all of those wrapper scripts have the same logic for how they find what JDK to use. They have verbatim the same code for it, in fact (#122609 (comment)) — but even if they didn't, the core logic has I think been standard in the Java world for a long time. That logic is:

    • Look for the environment variable JAVA_HOME. If there's an executable at "$JAVA_HOME"/bin/java, then use that as the java command to run.
    • Else fall back to looking for a java command on the PATH.

    So to get those wrapper scripts to use the JDK we want them to, we just have to set JAVA_HOME and/or PATH appropriately.


    There are several possible ways to do that, but I think the cleanest approach is:

    • Observe that our findJavaBinary method already has the same structure:
      • First it looks for a directory that could be used as a JAVA_HOME: a directory that should have a subfolder bin with a file java that is a suitable java command. (Its first choice for this is androidStudio?.javaPath, i.e. a JDK folder found within Android Studio.)
      • If that fails, it looks for a java command on the PATH.
    • So, refactor findJavaBinary to make that structure explicit: there's a findJavaHome that returns a directory that could be used as a JAVA_HOME. Then the implementation of findJavaBinary reduces to
      return findJavaHome(/* … */) ?? operatingSystemUtils.which(_javaExecutable)?.path;
      except it's a few lines longer than that in order to retain the printTrace calls.
    • Then, when running any Java-world wrapper script, including Gradle or the Android SDK command-line tools, do so with a call like:
      final String? javaHome = findJavaHome(/* … */);
      await _processUtils.run(
        args,
        environment: { 'JAVA_HOME': javaHome ?? '' }, // let PATH pass through from the tool's own environment
      );
      (Probably encapsulate that into a helper that lives next to findJavaHome and findJavaBinary, so that the call actually looks more like await _processUtils.run(args, environment: findJavaEnvironment(/* … */));.)
    • This will cause the wrapper script to use exactly the same java executable as findJavaBinary would return: if findJavaHome finds something, it will use that, and if not then it will find java on the PATH.
  6. removed their assignment
    on Apr 7, 2023
  7. abarke commented on Apr 25, 2023

    @abarke

    +1 I ran into this today... real pain #106416 (comment)

    As a flutter noob with first impressions, this doesn't feel good and doesn't provide me with much confidence.

  8. added a commit that references this issue on Jun 1, 2023
    06e2b18
  9. github-actions commented on Jun 15, 2023

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  10. locked as resolved and limited conversation to collaborators on Jun 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: tech-debtTechnical debt, code quality, testing, etc.platform-androidAndroid applications specificallyt: flutter doctorProblem related to the "flutter doctor" tooltoolAffects the "flutter" command-line tool. See also t: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions