Skip to content

Commit 0a63cd7

Browse files
authored
[tool] Move Java functions to their own file (#126086)
This is the first step in unifying Java-finding logic across the tool. If curious, see #126029 for an example of what all the changes will probably entail. Moves java-related functionality like `AndroidSdk.findJavaHome` to a new class, `Java`. See tracking issue flutter/flutter#126126 for more.
1 parent a308666 commit 0a63cd7

21 files changed

+706
-567
lines changed

packages/flutter_tools/lib/src/android/android_sdk.dart

Lines changed: 7 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'package:meta/meta.dart';
6-
75
import '../base/common.dart';
86
import '../base/file_system.dart';
9-
import '../base/os.dart';
10-
import '../base/platform.dart';
117
import '../base/process.dart';
128
import '../base/version.dart';
139
import '../convert.dart';
1410
import '../globals.dart' as globals;
15-
import 'android_studio.dart';
11+
import 'java.dart';
1612

1713
// ANDROID_HOME is deprecated.
1814
// See https://developer.android.com/studio/command-line/variables.html#envar
@@ -36,16 +32,18 @@ final RegExp _sdkVersionRe = RegExp(r'^ro.build.version.sdk=([0-9]+)$');
3632
// $ANDROID_SDK_ROOT/platforms/android-23/android.jar
3733
// $ANDROID_SDK_ROOT/platforms/android-N/android.jar
3834
class AndroidSdk {
39-
AndroidSdk(this.directory) {
35+
AndroidSdk(this.directory, {
36+
Java? java,
37+
}): _java = java {
4038
reinitialize();
4139
}
4240

4341
static const String javaHomeEnvironmentVariable = 'JAVA_HOME';
44-
static const String _javaExecutable = 'java';
45-
4642
/// The Android SDK root directory.
4743
final Directory directory;
4844

45+
final Java? _java;
46+
4947
List<AndroidSdkVersion> _sdkVersions = <AndroidSdkVersion>[];
5048
AndroidSdkVersion? _latestVersion;
5149

@@ -411,162 +409,6 @@ class AndroidSdk {
411409
return null;
412410
}
413411

414-
/// Returns the version of java in the format \d(.\d)+(.\d)+
415-
/// Returns null if version not found.
416-
String? getJavaVersion({
417-
required AndroidStudio? androidStudio,
418-
required FileSystem fileSystem,
419-
required OperatingSystemUtils operatingSystemUtils,
420-
required Platform platform,
421-
required ProcessUtils processUtils,
422-
}) {
423-
final String? javaBinary = findJavaBinary(
424-
androidStudio: androidStudio,
425-
fileSystem: fileSystem,
426-
operatingSystemUtils: operatingSystemUtils,
427-
platform: platform,
428-
);
429-
if (javaBinary == null) {
430-
globals.printTrace('Could not find java binary to get version.');
431-
return null;
432-
}
433-
final RunResult result = processUtils.runSync(
434-
<String>[javaBinary, '--version'],
435-
environment: sdkManagerEnv,
436-
);
437-
if (result.exitCode != 0) {
438-
globals.printTrace(
439-
'java --version failed: exitCode: ${result.exitCode} stdout: ${result.stdout} stderr: ${result.stderr}');
440-
return null;
441-
}
442-
return parseJavaVersion(result.stdout);
443-
}
444-
445-
/// Extracts JDK version from the output of java --version.
446-
@visibleForTesting
447-
static String? parseJavaVersion(String rawVersionOutput) {
448-
// The contents that matter come in the format '11.0.18' or '1.8.0_202'.
449-
final RegExp jdkVersionRegex = RegExp(r'\d+\.\d+(\.\d+(?:_\d+)?)?');
450-
final Iterable<RegExpMatch> matches =
451-
jdkVersionRegex.allMatches(rawVersionOutput);
452-
if (matches.isEmpty) {
453-
globals.logger.printWarning(_formatJavaVersionWarning(rawVersionOutput));
454-
return null;
455-
}
456-
final String? versionString = matches.first.group(0);
457-
if (versionString == null || versionString.split('_').isEmpty) {
458-
globals.logger.printWarning(_formatJavaVersionWarning(rawVersionOutput));
459-
return null;
460-
}
461-
// Trim away _d+ from versions 1.8 and below.
462-
return versionString.split('_').first;
463-
}
464-
465-
/// A value that would be appropriate to use as JAVA_HOME.
466-
///
467-
/// This method considers jdk in the following order:
468-
/// * the JDK bundled with Android Studio, if one is found;
469-
/// * the JAVA_HOME in the ambient environment, if set;
470-
String? get javaHome {
471-
return findJavaHome(
472-
androidStudio: globals.androidStudio,
473-
fileSystem: globals.fs,
474-
operatingSystemUtils: globals.os,
475-
platform: globals.platform,
476-
);
477-
}
478-
479-
480-
static String? findJavaHome({
481-
required AndroidStudio? androidStudio,
482-
required FileSystem fileSystem,
483-
required OperatingSystemUtils operatingSystemUtils,
484-
required Platform platform,
485-
}) {
486-
if (androidStudio?.javaPath != null) {
487-
globals.printTrace("Using Android Studio's java.");
488-
return androidStudio!.javaPath!;
489-
}
490-
491-
final String? javaHomeEnv = platform.environment[javaHomeEnvironmentVariable];
492-
if (javaHomeEnv != null) {
493-
globals.printTrace('Using JAVA_HOME from environment valuables.');
494-
return javaHomeEnv;
495-
}
496-
return null;
497-
}
498-
499-
/// Finds the java binary that is used for all operations across the tool.
500-
///
501-
/// This comes from [findJavaHome] if that method returns non-null;
502-
/// otherwise, it gets from searching PATH.
503-
// TODO(andrewkolos): To prevent confusion when debugging Android-related
504-
// issues (see https://github.com/flutter/flutter/issues/122609 for an example),
505-
// this logic should be consistently followed by any Java-dependent operation
506-
// across the the tool (building Android apps, interacting with the Android SDK, etc.).
507-
// Currently, this consistency is fragile since the logic used for building
508-
// Android apps exists independently of this method.
509-
// See https://github.com/flutter/flutter/issues/124252.
510-
static String? findJavaBinary({
511-
required AndroidStudio? androidStudio,
512-
required FileSystem fileSystem,
513-
required OperatingSystemUtils operatingSystemUtils,
514-
required Platform platform,
515-
}) {
516-
final String? javaHome = findJavaHome(
517-
androidStudio: androidStudio,
518-
fileSystem: fileSystem,
519-
operatingSystemUtils: operatingSystemUtils,
520-
platform: platform,
521-
);
522-
523-
if (javaHome != null) {
524-
return fileSystem.path.join(javaHome, 'bin', 'java');
525-
}
526-
527-
// Fallback to PATH based lookup.
528-
final String? pathJava = operatingSystemUtils.which(_javaExecutable)?.path;
529-
if (pathJava != null) {
530-
globals.printTrace('Using java from PATH.');
531-
} else {
532-
globals.printTrace('Could not find java path.');
533-
}
534-
return pathJava;
535-
}
536-
537-
// Returns a user visible String that says the tool failed to parse
538-
// the version of java along with the output.
539-
static String _formatJavaVersionWarning(String javaVersionRaw) {
540-
return 'Could not parse java version from: \n'
541-
'$javaVersionRaw \n'
542-
'If there is a version please look for an existing bug '
543-
'https://github.com/flutter/flutter/issues/'
544-
' and if one does not exist file a new issue.';
545-
}
546-
547-
Map<String, String>? _sdkManagerEnv;
548-
549-
/// Returns an environment with the Java folder added to PATH for use in calling
550-
/// Java-based Android SDK commands such as sdkmanager and avdmanager.
551-
Map<String, String> get sdkManagerEnv {
552-
if (_sdkManagerEnv == null) {
553-
// If we can locate Java, then add it to the path used to run the Android SDK manager.
554-
_sdkManagerEnv = <String, String>{};
555-
final String? javaBinary = findJavaBinary(
556-
androidStudio: globals.androidStudio,
557-
fileSystem: globals.fs,
558-
operatingSystemUtils: globals.os,
559-
platform: globals.platform,
560-
);
561-
if (javaBinary != null && globals.platform.environment['PATH'] != null) {
562-
_sdkManagerEnv!['PATH'] = globals.fs.path.dirname(javaBinary) +
563-
globals.os.pathVarSeparator +
564-
globals.platform.environment['PATH']!;
565-
}
566-
}
567-
return _sdkManagerEnv!;
568-
}
569-
570412
/// Returns the version of the Android SDK manager tool or null if not found.
571413
String? get sdkManagerVersion {
572414
if (sdkManagerPath == null || !globals.processManager.canRun(sdkManagerPath)) {
@@ -577,7 +419,7 @@ class AndroidSdk {
577419
}
578420
final RunResult result = globals.processUtils.runSync(
579421
<String>[sdkManagerPath!, '--version'],
580-
environment: sdkManagerEnv,
422+
environment: _java?.environment,
581423
);
582424
if (result.exitCode != 0) {
583425
globals.printTrace('sdkmanager --version failed: exitCode: ${result.exitCode} stdout: ${result.stdout} stderr: ${result.stderr}');

packages/flutter_tools/lib/src/android/android_workflow.dart

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import '../base/context.dart';
1111
import '../base/file_system.dart';
1212
import '../base/io.dart';
1313
import '../base/logger.dart';
14-
import '../base/os.dart';
1514
import '../base/platform.dart';
1615
import '../base/user_messages.dart' hide userMessages;
1716
import '../base/version.dart';
@@ -20,6 +19,7 @@ import '../doctor_validator.dart';
2019
import '../features.dart';
2120
import 'android_sdk.dart';
2221
import 'android_studio.dart';
22+
import 'java.dart';
2323

2424
const int kAndroidSdkMinVersion = 29;
2525
final Version kAndroidJavaMinVersion = Version(1, 8, 0);
@@ -86,12 +86,6 @@ class AndroidValidator extends DoctorValidator {
8686
_androidStudio = androidStudio,
8787
_fileSystem = fileSystem,
8888
_logger = logger,
89-
_operatingSystemUtils = OperatingSystemUtils(
90-
fileSystem: fileSystem,
91-
logger: logger,
92-
platform: platform,
93-
processManager: processManager,
94-
),
9589
_platform = platform,
9690
_processManager = processManager,
9791
_userMessages = userMessages,
@@ -101,7 +95,6 @@ class AndroidValidator extends DoctorValidator {
10195
final AndroidStudio? _androidStudio;
10296
final FileSystem _fileSystem;
10397
final Logger _logger;
104-
final OperatingSystemUtils _operatingSystemUtils;
10598
final Platform _platform;
10699
final ProcessManager _processManager;
107100
final UserMessages _userMessages;
@@ -138,6 +131,8 @@ class AndroidValidator extends DoctorValidator {
138131
}
139132
String? javaVersionText;
140133
try {
134+
// TODO(andrewkolos): Use Java class to find version instead of using duplicate
135+
// code. See https://github.com/flutter/flutter/issues/124252.
141136
_logger.printTrace('java -version');
142137
final ProcessResult result = await _processManager.run(<String>[javaBinary, '-version']);
143138
if (result.exitCode == 0) {
@@ -240,12 +235,13 @@ class AndroidValidator extends DoctorValidator {
240235

241236
_task = 'Finding Java binary';
242237
// Now check for the JDK.
243-
final String? javaBinary = AndroidSdk.findJavaBinary(
238+
final String? javaBinary = Java.find(
239+
logger: _logger,
244240
androidStudio: _androidStudio,
245241
fileSystem: _fileSystem,
246-
operatingSystemUtils: _operatingSystemUtils,
247242
platform: _platform,
248-
);
243+
processManager: _processManager,
244+
)?.binaryPath;
249245
if (javaBinary == null) {
250246
messages.add(ValidationMessage.error(_userMessages.androidMissingJdk));
251247
return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText);
@@ -266,18 +262,18 @@ class AndroidValidator extends DoctorValidator {
266262
/// SDK have been accepted.
267263
class AndroidLicenseValidator extends DoctorValidator {
268264
AndroidLicenseValidator({
265+
required Java? java,
269266
required AndroidSdk? androidSdk,
270267
required Platform platform,
271-
required OperatingSystemUtils operatingSystemUtils,
272268
required FileSystem fileSystem,
273269
required ProcessManager processManager,
274270
required Logger logger,
275271
required AndroidStudio? androidStudio,
276272
required Stdio stdio,
277273
required UserMessages userMessages,
278-
}) : _androidSdk = androidSdk,
274+
}) : _java = java,
275+
_androidSdk = androidSdk,
279276
_platform = platform,
280-
_operatingSystemUtils = operatingSystemUtils,
281277
_fileSystem = fileSystem,
282278
_processManager = processManager,
283279
_logger = logger,
@@ -286,10 +282,10 @@ class AndroidLicenseValidator extends DoctorValidator {
286282
_userMessages = userMessages,
287283
super('Android license subvalidator');
288284

285+
final Java? _java;
289286
final AndroidSdk? _androidSdk;
290287
final AndroidStudio? _androidStudio;
291288
final Stdio _stdio;
292-
final OperatingSystemUtils _operatingSystemUtils;
293289
final Platform _platform;
294290
final FileSystem _fileSystem;
295291
final ProcessManager _processManager;
@@ -330,12 +326,13 @@ class AndroidLicenseValidator extends DoctorValidator {
330326
}
331327

332328
Future<bool> _checkJavaVersionNoOutput() async {
333-
final String? javaBinary = AndroidSdk.findJavaBinary(
329+
final String? javaBinary = Java.find(
330+
logger: _logger,
334331
androidStudio: _androidStudio,
335332
fileSystem: _fileSystem,
336-
operatingSystemUtils: _operatingSystemUtils,
337333
platform: _platform,
338-
);
334+
processManager: _processManager,
335+
)?.binaryPath;
339336
if (javaBinary == null) {
340337
return false;
341338
}
@@ -387,7 +384,7 @@ class AndroidLicenseValidator extends DoctorValidator {
387384
try {
388385
final Process process = await _processManager.start(
389386
<String>[_androidSdk!.sdkManagerPath!, '--licenses'],
390-
environment: _androidSdk!.sdkManagerEnv,
387+
environment: _java?.environment,
391388
);
392389
process.stdin.write('n\n');
393390
// We expect logcat streams to occasionally contain invalid utf-8,
@@ -427,7 +424,7 @@ class AndroidLicenseValidator extends DoctorValidator {
427424
try {
428425
final Process process = await _processManager.start(
429426
<String>[_androidSdk!.sdkManagerPath!, '--licenses'],
430-
environment: _androidSdk!.sdkManagerEnv,
427+
environment: _java?.environment,
431428
);
432429

433430
// The real stdin will never finish streaming. Pipe until the child process

0 commit comments

Comments
 (0)