From 4954a46ff098967ece29c29994beee677e1f0feb Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 19 Aug 2020 14:44:56 -0700 Subject: [PATCH] [flutter_tools] shrink API surface of Android SDK (#63867) Attempt to simplify the Android SDK interface ahead of refactoring it. The locateAndroidSdk static method is called at startup to locate the android SDK, returning null if it cannot be found. These helper methods attempted to first look up the AndroidSDK if it was already null - which could only cover the case where someone installed the Android SDK while flutter was running (possibly through an IDE) --- .../lib/src/android/android_emulator.dart | 6 +- .../lib/src/android/android_sdk.dart | 117 +++++++----------- .../lib/src/android/android_workflow.dart | 2 +- packages/flutter_tools/lib/src/emulator.dart | 6 +- .../android/android_emulator_test.dart | 4 - 5 files changed, 53 insertions(+), 82 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/android_emulator.dart b/packages/flutter_tools/lib/src/android/android_emulator.dart index 2c387ee144c..43a0edda000 100644 --- a/packages/flutter_tools/lib/src/android/android_emulator.dart +++ b/packages/flutter_tools/lib/src/android/android_emulator.dart @@ -56,7 +56,7 @@ class AndroidEmulators extends EmulatorDiscovery { /// Return the list of available emulator AVDs. Future> _getEmulatorAvds() async { - final String emulatorPath = getEmulatorPath(_androidSdk); + final String emulatorPath = _androidSdk.emulatorPath; if (emulatorPath == null) { return []; } @@ -81,7 +81,7 @@ class AndroidEmulators extends EmulatorDiscovery { AndroidEmulator _loadEmulatorInfo(String id) { id = id.trim(); - final String avdPath = getAvdPath(); + final String avdPath = _androidSdk.getAvdPath(); final AndroidEmulator androidEmulatorWithoutProperties = AndroidEmulator( id, processManager: _processManager, @@ -150,7 +150,7 @@ class AndroidEmulator extends Emulator { @override Future launch() async { final Process process = await _processUtils.start( - [getEmulatorPath(_androidSdk), '-avd', id], + [_androidSdk.emulatorPath, '-avd', id], ); // Record output from the emulator process. diff --git a/packages/flutter_tools/lib/src/android/android_sdk.dart b/packages/flutter_tools/lib/src/android/android_sdk.dart index 1179eba66a0..a48801a197e 100644 --- a/packages/flutter_tools/lib/src/android/android_sdk.dart +++ b/packages/flutter_tools/lib/src/android/android_sdk.dart @@ -19,6 +19,26 @@ import 'android_studio.dart'; const String kAndroidHome = 'ANDROID_HOME'; const String kAndroidSdkRoot = 'ANDROID_SDK_ROOT'; +final RegExp _numberedAndroidPlatformRe = RegExp(r'^android-([0-9]+)$'); +final RegExp _sdkVersionRe = RegExp(r'^ro.build.version.sdk=([0-9]+)$'); + +/// The minimum Android SDK version we support. +const int minimumAndroidSdkVersion = 25; + +/// Locate ADB. Prefer to use one from an Android SDK, if we can locate that. +/// This should be used over accessing androidSdk.adbPath directly because it +/// will work for those users who have Android Platform Tools installed but +/// not the full SDK. +String getAdbPath(AndroidSdk existingSdk) { + if (existingSdk?.adbPath != null) { + return existingSdk.adbPath; + } + if (existingSdk?.latestVersion == null) { + return globals.os.which('adb')?.path; + } + return existingSdk?.adbPath; +} + // Android SDK layout: // $ANDROID_SDK_ROOT/platform-tools/adb @@ -32,77 +52,6 @@ const String kAndroidSdkRoot = 'ANDROID_SDK_ROOT'; // $ANDROID_SDK_ROOT/platforms/android-22/android.jar // $ANDROID_SDK_ROOT/platforms/android-23/android.jar // $ANDROID_SDK_ROOT/platforms/android-N/android.jar - -final RegExp _numberedAndroidPlatformRe = RegExp(r'^android-([0-9]+)$'); -final RegExp _sdkVersionRe = RegExp(r'^ro.build.version.sdk=([0-9]+)$'); - -/// The minimum Android SDK version we support. -const int minimumAndroidSdkVersion = 25; - -/// Locate ADB. Prefer to use one from an Android SDK, if we can locate that. -/// This should be used over accessing androidSdk.adbPath directly because it -/// will work for those users who have Android Platform Tools installed but -/// not the full SDK. -String getAdbPath([ AndroidSdk existingSdk ]) { - if (existingSdk?.adbPath != null) { - return existingSdk.adbPath; - } - - final AndroidSdk sdk = AndroidSdk.locateAndroidSdk(); - - if (sdk?.latestVersion == null) { - return globals.os.which('adb')?.path; - } else { - return sdk?.adbPath; - } -} - -/// Locate 'emulator'. Prefer to use one from an Android SDK, if we can locate that. -/// This should be used over accessing androidSdk.emulatorPath directly because it -/// will work for those users who have Android Tools installed but -/// not the full SDK. -String getEmulatorPath([ AndroidSdk existingSdk ]) { - return existingSdk?.emulatorPath ?? - AndroidSdk.locateAndroidSdk()?.emulatorPath; -} - -/// Locate the path for storing AVD emulator images. Returns null if none found. -String getAvdPath() { - - final List searchPaths = [ - globals.platform.environment['ANDROID_AVD_HOME'], - if (globals.platform.environment['HOME'] != null) - globals.fs.path.join(globals.platform.environment['HOME'], '.android', 'avd'), - ]; - - - if (globals.platform.isWindows) { - final String homeDrive = globals.platform.environment['HOMEDRIVE']; - final String homePath = globals.platform.environment['HOMEPATH']; - - if (homeDrive != null && homePath != null) { - // Can't use path.join for HOMEDRIVE/HOMEPATH - // https://github.com/dart-lang/path/issues/37 - final String home = homeDrive + homePath; - searchPaths.add(globals.fs.path.join(home, '.android', 'avd')); - } - } - - return searchPaths.where((String p) => p != null).firstWhere( - (String p) => globals.fs.directory(p).existsSync(), - orElse: () => null, - ); -} - -/// Locate 'avdmanager'. Prefer to use one from an Android SDK, if we can locate that. -/// This should be used over accessing androidSdk.avdManagerPath directly because it -/// will work for those users who have Android Tools installed but -/// not the full SDK. -String getAvdManagerPath([ AndroidSdk existingSdk ]) { - return existingSdk?.avdManagerPath ?? - AndroidSdk.locateAndroidSdk()?.avdManagerPath; -} - class AndroidSdk { AndroidSdk(this.directory) { reinitialize(); @@ -240,6 +189,32 @@ class AndroidSdk { String get avdManagerPath => getAvdManagerPath(); + /// Locate the path for storing AVD emulator images. Returns null if none found. + String getAvdPath() { + final List searchPaths = [ + globals.platform.environment['ANDROID_AVD_HOME'], + if (globals.platform.environment['HOME'] != null) + globals.fs.path.join(globals.platform.environment['HOME'], '.android', 'avd'), + ]; + + if (globals.platform.isWindows) { + final String homeDrive = globals.platform.environment['HOMEDRIVE']; + final String homePath = globals.platform.environment['HOMEPATH']; + + if (homeDrive != null && homePath != null) { + // Can't use path.join for HOMEDRIVE/HOMEPATH + // https://github.com/dart-lang/path/issues/37 + final String home = homeDrive + homePath; + searchPaths.add(globals.fs.path.join(home, '.android', 'avd')); + } + } + + return searchPaths.where((String p) => p != null).firstWhere( + (String p) => globals.fs.directory(p).existsSync(), + orElse: () => null, + ); + } + Directory get _platformsDir => globals.fs.directory(globals.fs.path.join(directory, 'platforms')); Iterable get _platforms { diff --git a/packages/flutter_tools/lib/src/android/android_workflow.dart b/packages/flutter_tools/lib/src/android/android_workflow.dart index 556ab2c5f0b..5c2e1af82c1 100644 --- a/packages/flutter_tools/lib/src/android/android_workflow.dart +++ b/packages/flutter_tools/lib/src/android/android_workflow.dart @@ -64,7 +64,7 @@ class AndroidWorkflow implements Workflow { bool get canLaunchDevices => _androidSdk != null && _androidSdk.validateSdkWellFormed().isEmpty; @override - bool get canListEmulators => getEmulatorPath(_androidSdk) != null; + bool get canListEmulators => _androidSdk.emulatorPath != null; } class AndroidValidator extends DoctorValidator { diff --git a/packages/flutter_tools/lib/src/emulator.dart b/packages/flutter_tools/lib/src/emulator.dart index c788dc72c3c..d560a65adcb 100644 --- a/packages/flutter_tools/lib/src/emulator.dart +++ b/packages/flutter_tools/lib/src/emulator.dart @@ -140,7 +140,7 @@ class EmulatorManager { .trim(); } final RunResult runResult = await _processUtils.run([ - getAvdManagerPath(_androidSdk), + _androidSdk?.avdManagerPath, 'create', 'avd', '-n', name, @@ -163,7 +163,7 @@ class EmulatorManager { Future _getPreferredAvailableDevice() async { final List args = [ - getAvdManagerPath(_androidSdk), + _androidSdk?.avdManagerPath, 'list', 'device', '-c', @@ -191,7 +191,7 @@ class EmulatorManager { // It seems that to get the available list of images, we need to send a // request to create without the image and it'll provide us a list :-( final List args = [ - getAvdManagerPath(_androidSdk), + _androidSdk?.avdManagerPath, 'create', 'avd', '-n', 'temp', diff --git a/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart b/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart index a89788d6c68..82a1b108c46 100644 --- a/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_emulator_test.dart @@ -4,8 +4,6 @@ import 'dart:async'; -import 'package:flutter_tools/src/android/android_sdk.dart' - show getEmulatorPath; import 'package:flutter_tools/src/android/android_emulator.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/logger.dart'; @@ -144,8 +142,6 @@ void main() { logger: BufferLogger.test(), ); - expect(getEmulatorPath(mockSdk), mockSdk.emulatorPath); - final Completer completer = Completer(); FakeAsync().run((FakeAsync time) { unawaited(emulator.launch().whenComplete(completer.complete));