From d5149d4457ed1de16b80e4aec40a125134e953de Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 1 Feb 2018 15:14:48 -0800 Subject: [PATCH] Toolchain support for Android ARM64 targets (#14394) --- packages/flutter_tools/gradle/flutter.gradle | 22 ++++++++++++++++--- .../lib/src/android/android_device.dart | 14 ++++++++++-- .../flutter_tools/lib/src/android/gradle.dart | 2 ++ .../lib/src/application_package.dart | 2 ++ packages/flutter_tools/lib/src/artifacts.dart | 2 ++ .../flutter_tools/lib/src/build_info.dart | 20 ++++++++++++++++- packages/flutter_tools/lib/src/cache.dart | 5 +++++ .../lib/src/commands/build_aot.dart | 18 ++++++++++----- .../lib/src/commands/build_apk.dart | 5 ++++- .../lib/src/resident_runner.dart | 1 + .../lib/src/runner/flutter_command.dart | 5 ++++- 11 files changed, 82 insertions(+), 14 deletions(-) diff --git a/packages/flutter_tools/gradle/flutter.gradle b/packages/flutter_tools/gradle/flutter.gradle index 55c0380d1e7..5c655f8a94c 100644 --- a/packages/flutter_tools/gradle/flutter.gradle +++ b/packages/flutter_tools/gradle/flutter.gradle @@ -115,9 +115,14 @@ class FlutterPlugin implements Plugin { } } else { Path baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine") - debugFlutterJar = baseEnginePath.resolve("android-arm").resolve("flutter.jar").toFile() - profileFlutterJar = baseEnginePath.resolve("android-arm-profile").resolve("flutter.jar").toFile() - releaseFlutterJar = baseEnginePath.resolve("android-arm-release").resolve("flutter.jar").toFile() + String targetArch = 'arm' + if (project.hasProperty('target-platform') && + project.property('target-platform') == 'android-arm64') { + targetArch = 'arm64' + } + debugFlutterJar = baseEnginePath.resolve("android-${targetArch}").resolve("flutter.jar").toFile() + profileFlutterJar = baseEnginePath.resolve("android-${targetArch}-profile").resolve("flutter.jar").toFile() + releaseFlutterJar = baseEnginePath.resolve("android-${targetArch}-release").resolve("flutter.jar").toFile() if (!debugFlutterJar.isFile()) { project.exec { executable flutterExecutable.absolutePath @@ -273,6 +278,10 @@ class FlutterPlugin implements Plugin { if (project.hasProperty('prefer-shared-library')) { preferSharedLibraryValue = project.property('prefer-shared-library') } + String targetPlatformValue = null + if (project.hasProperty('target-platform')) { + targetPlatformValue = project.property('target-platform') + } project.android.applicationVariants.all { variant -> String flutterBuildMode = buildModeFor(variant.buildType) @@ -297,6 +306,7 @@ class FlutterPlugin implements Plugin { previewDart2 previewDart2Value strongMode strongModeValue preferSharedLibrary preferSharedLibraryValue + targetPlatform targetPlatformValue sourceDir project.file(project.flutter.source) intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}") } @@ -312,6 +322,7 @@ class FlutterPlugin implements Plugin { previewDart2 previewDart2Value strongMode strongModeValue preferSharedLibrary preferSharedLibraryValue + targetPlatform targetPlatformValue sourceDir project.file(project.flutter.source) intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}") extraFrontEndOptions extraFrontEndOptionsValue @@ -349,6 +360,8 @@ abstract class BaseFlutterTask extends DefaultTask { Boolean strongMode @Optional @Input Boolean preferSharedLibrary + @Optional @Input + String targetPlatform File sourceDir File intermediateDir @Optional @Input @@ -400,6 +413,9 @@ abstract class BaseFlutterTask extends DefaultTask { if (preferSharedLibrary) { args "--prefer-shared-library" } + if (targetPlatform != null) { + args "--target-platform", "${targetPlatform}" + } args "--${buildMode}" } } diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart index 9c9cac60a2f..aef36790a82 100644 --- a/packages/flutter_tools/lib/src/android/android_device.dart +++ b/packages/flutter_tools/lib/src/android/android_device.dart @@ -126,6 +126,9 @@ class AndroidDevice extends Device { if (_platform == null) { // http://developer.android.com/ndk/guides/abis.html (x86, armeabi-v7a, ...) switch (await _getProperty('ro.product.cpu.abi')) { + case 'arm64-v8a': + _platform = TargetPlatform.android_arm64; + break; case 'x86_64': _platform = TargetPlatform.android_x64; break; @@ -355,16 +358,23 @@ class AndroidDevice extends Device { if (!await _checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion()) return new LaunchResult.failed(); - if (await targetPlatform != TargetPlatform.android_arm && !debuggingOptions.buildInfo.isDebug) { + final TargetPlatform devicePlatform = await targetPlatform; + if (!(devicePlatform == TargetPlatform.android_arm || + devicePlatform == TargetPlatform.android_arm64) && + !debuggingOptions.buildInfo.isDebug) { printError('Profile and release builds are only supported on ARM targets.'); return new LaunchResult.failed(); } + BuildInfo buildInfo = debuggingOptions.buildInfo; + if (devicePlatform == TargetPlatform.android_arm64) + buildInfo = buildInfo.withTargetPlatform(TargetPlatform.android_arm64); + if (!prebuiltApplication) { printTrace('Building APK'); await buildApk( target: mainPath, - buildInfo: debuggingOptions.buildInfo, + buildInfo: buildInfo, ); // Package has been built, so we can get the updated application ID and // activity name from the .apk. diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index 8d8957a4431..e22bc8b5d45 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -301,6 +301,8 @@ Future _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String ta if (buildInfo.preferSharedLibrary && androidSdk.ndkCompiler != null) { command.add('-Pprefer-shared-library=true'); } + if (buildInfo.targetPlatform == TargetPlatform.android_arm64) + command.add('-Ptarget-platform=android-arm64'); command.add(assembleTask); final int exitCode = await runCommandAndStreamOutput( diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart index 14c031030f8..f734d7a9025 100644 --- a/packages/flutter_tools/lib/src/application_package.dart +++ b/packages/flutter_tools/lib/src/application_package.dart @@ -259,6 +259,7 @@ Future getApplicationPackageForPlatform(TargetPlatform platf }) async { switch (platform) { case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: return applicationBinary == null @@ -287,6 +288,7 @@ class ApplicationPackageStore { Future getPackageForPlatform(TargetPlatform platform) async { switch (platform) { case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: android ??= await AndroidApk.fromCurrentDirectory(); diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 3c4bfa3b388..bfe8963eb73 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -97,6 +97,7 @@ class CachedArtifacts extends Artifacts { platform ??= _currentHostPlatform; switch (platform) { case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: return _getAndroidArtifactPath(artifact, platform, mode); @@ -195,6 +196,7 @@ class CachedArtifacts extends Artifacts { return fs.path.join(engineDir, platformName); case TargetPlatform.ios: case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: assert(mode != null, 'Need to specify a build mode for platform $platform.'); diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 63bf145a3d2..8ed2b77fe6c 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -15,7 +15,8 @@ class BuildInfo { this.strongMode, this.extraFrontEndOptions, this.extraGenSnapshotOptions, - this.preferSharedLibrary}); + this.preferSharedLibrary, + this.targetPlatform}); final BuildMode mode; /// Represents a custom Android product flavor or an Xcode scheme, null for @@ -41,6 +42,9 @@ class BuildInfo { // Whether to prefer AOT compiling to a *so file. final bool preferSharedLibrary; + /// Target platform for the build (e.g. android_arm versus android_arm64). + final TargetPlatform targetPlatform; + static const BuildInfo debug = const BuildInfo(BuildMode.debug, null); static const BuildInfo profile = const BuildInfo(BuildMode.profile, null); static const BuildInfo release = const BuildInfo(BuildMode.release, null); @@ -64,6 +68,15 @@ class BuildInfo { bool get supportsEmulator => isEmulatorBuildMode(mode); bool get supportsSimulator => isEmulatorBuildMode(mode); String get modeName => getModeName(mode); + + BuildInfo withTargetPlatform(TargetPlatform targetPlatform) => + new BuildInfo(mode, flavor, + previewDart2: previewDart2, + strongMode: strongMode, + extraFrontEndOptions: extraFrontEndOptions, + extraGenSnapshotOptions: extraGenSnapshotOptions, + preferSharedLibrary: preferSharedLibrary, + targetPlatform: targetPlatform); } /// The type of build - `debug`, `profile`, or `release`. @@ -114,6 +127,7 @@ String getNameForHostPlatform(HostPlatform platform) { enum TargetPlatform { android_arm, + android_arm64, android_x64, android_x86, ios, @@ -127,6 +141,8 @@ String getNameForTargetPlatform(TargetPlatform platform) { switch (platform) { case TargetPlatform.android_arm: return 'android-arm'; + case TargetPlatform.android_arm64: + return 'android-arm64'; case TargetPlatform.android_x64: return 'android-x64'; case TargetPlatform.android_x86: @@ -150,6 +166,8 @@ TargetPlatform getTargetPlatformForName(String platform) { switch (platform) { case 'android-arm': return TargetPlatform.android_arm; + case 'android-arm64': + return TargetPlatform.android_arm64; case 'android-x64': return TargetPlatform.android_x64; case 'android-x86': diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index ba657bf08b1..62083ac1fb5 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -394,6 +394,8 @@ class FlutterEngine extends CachedArtifact { ['linux-x64', 'dart-sdk-linux-x64.zip'], ['android-arm-profile/linux-x64', 'android-arm-profile/linux-x64.zip'], ['android-arm-release/linux-x64', 'android-arm-release/linux-x64.zip'], + ['android-arm64-profile/linux-x64', 'android-arm64-profile/linux-x64.zip'], + ['android-arm64-release/linux-x64', 'android-arm64-release/linux-x64.zip'], ]; List> get _windowsBinaryDirs => >[ @@ -409,6 +411,9 @@ class FlutterEngine extends CachedArtifact { ['android-arm', 'android-arm/artifacts.zip'], ['android-arm-profile', 'android-arm-profile/artifacts.zip'], ['android-arm-release', 'android-arm-release/artifacts.zip'], + ['android-arm64', 'android-arm64/artifacts.zip'], + ['android-arm64-profile', 'android-arm64-profile/artifacts.zip'], + ['android-arm64-release', 'android-arm64-release/artifacts.zip'], ]; List> get _iosBinaryDirs => >[ diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart index 9233bbfabe0..dd60d4da7d3 100644 --- a/packages/flutter_tools/lib/src/commands/build_aot.dart +++ b/packages/flutter_tools/lib/src/commands/build_aot.dart @@ -35,7 +35,7 @@ class BuildAotCommand extends BuildSubCommand { ..addOption('output-dir', defaultsTo: getAotBuildDirectory()) ..addOption('target-platform', defaultsTo: 'android-arm', - allowed: ['android-arm', 'ios'] + allowed: ['android-arm', 'android-arm64', 'ios'] ) ..addFlag('interpreter') ..addFlag('quiet', defaultsTo: false) @@ -159,7 +159,9 @@ Future _buildAotSnapshot( return null; } - if (platform != TargetPlatform.android_arm && platform != TargetPlatform.ios) { + if (!(platform == TargetPlatform.android_arm || + platform == TargetPlatform.android_arm64 || + platform == TargetPlatform.ios)) { printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.'); return null; } @@ -217,6 +219,7 @@ Future _buildAotSnapshot( switch (platform) { case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: if (compileToSharedLibrary) { @@ -287,6 +290,7 @@ Future _buildAotSnapshot( switch (platform) { case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: if (compileToSharedLibrary) { @@ -300,10 +304,12 @@ Future _buildAotSnapshot( '--isolate_snapshot_instructions=$isolateSnapshotInstructions', ]); } - genSnapshotCmd.addAll([ - '--no-sim-use-hardfp', // Android uses the softfloat ABI. - '--no-use-integer-division', // Not supported by the Pixel in 32-bit mode. - ]); + if (platform == TargetPlatform.android_arm) { + genSnapshotCmd.addAll([ + '--no-sim-use-hardfp', // Android uses the softfloat ABI. + '--no-use-integer-division', // Not supported by the Pixel in 32-bit mode. + ]); + } break; case TargetPlatform.ios: if (interpreter) { diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart index 4636e4859e5..67d8a18b99f 100644 --- a/packages/flutter_tools/lib/src/commands/build_apk.dart +++ b/packages/flutter_tools/lib/src/commands/build_apk.dart @@ -18,7 +18,10 @@ class BuildApkCommand extends BuildSubCommand { ..addFlag('preview-dart-2', negatable: false, hide: !verboseHelp) ..addFlag('strong', negatable: false, hide: !verboseHelp) ..addFlag('prefer-shared-library', negatable: false, - help: 'Whether to prefer compiling to a *.so file (android only).'); + help: 'Whether to prefer compiling to a *.so file (android only).') + ..addOption('target-platform', + defaultsTo: 'android-arm', + allowed: ['android-arm', 'android-arm64']); } @override diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index a7c520ae278..db64ccd956c 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -886,6 +886,7 @@ String findMainDartFile([String target]) { String getMissingPackageHintForPlatform(TargetPlatform platform) { switch (platform) { case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: case TargetPlatform.android_x64: case TargetPlatform.android_x86: String manifest = 'android/AndroidManifest.xml'; diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index f8962b33451..39075996f74 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -185,7 +185,10 @@ abstract class FlutterCommand extends Command { : null, preferSharedLibrary: argParser.options.containsKey('prefer-shared-library') ? argResults['prefer-shared-library'] - : false); + : false, + targetPlatform: argParser.options.containsKey('target-platform') + ? getTargetPlatformForName(argResults['target-platform']) + : null); } void setupApplicationPackages() {