diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index acfef676d..9544a18f7 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -61,7 +61,7 @@ enum Artifact { // Fuchsia artifacts from the engine prebuilts. fuchsiaKernelCompiler, - fuchsiaFlutterJitRunner, + fuchsiaFlutterRunner, } String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMode mode ]) { @@ -136,11 +136,10 @@ String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMo return 'flutter_ddc_sdk.dill'; case Artifact.fuchsiaKernelCompiler: return 'kernel_compiler.snapshot'; - case Artifact.fuchsiaFlutterJitRunner: - if (mode == BuildMode.debug || mode == BuildMode.profile) { - return 'flutter_jit_runner-0.far'; - } - return 'flutter_jit_product_runner-0.far'; + case Artifact.fuchsiaFlutterRunner: + final String jitOrAot = mode.isJit ? '_jit' : '_aot'; + final String productOrNo = mode.isRelease ? '_product' : ''; + return 'flutter$jitOrAot${productOrNo}_runner-0.far'; } assert(false, 'Invalid artifact $artifact.'); return null; @@ -278,21 +277,25 @@ class CachedArtifacts extends Artifacts { cache.getArtifactDirectory('flutter_runner').path, 'flutter', fuchsiaArchForTargetPlatform(platform), - getNameForBuildMode(mode), + mode.isRelease ? 'release' : mode.toString(), ); + final String runtime = mode.isJit ? 'jit' : 'aot'; switch (artifact) { + case Artifact.genSnapshot: + final String genSnapshot = mode.isRelease ? 'gen_snapshot_product' : 'gen_snapshot'; + return fs.path.join(root, runtime, 'dart_binaries', genSnapshot); case Artifact.flutterPatchedSdkPath: const String artifactFileName = 'flutter_runner_patched_sdk'; - return fs.path.join(root, 'jit', artifactFileName); + return fs.path.join(root, runtime, artifactFileName); case Artifact.platformKernelDill: final String artifactFileName = _artifactToFileName(artifact, platform, mode); - return fs.path.join(root, 'jit', 'flutter_runner_patched_sdk', artifactFileName); + return fs.path.join(root, runtime, 'flutter_runner_patched_sdk', artifactFileName); case Artifact.fuchsiaKernelCompiler: final String artifactFileName = _artifactToFileName(artifact, platform, mode); - return fs.path.join(root, 'jit', 'dart_binaries', artifactFileName); - case Artifact.fuchsiaFlutterJitRunner: + return fs.path.join(root, runtime, 'dart_binaries', artifactFileName); + case Artifact.fuchsiaFlutterRunner: final String artifactFileName = _artifactToFileName(artifact, platform, mode); - return fs.path.join(root, 'jit', artifactFileName); + return fs.path.join(root, runtime, artifactFileName); default: return _getHostArtifactPath(artifact, platform, mode); } @@ -413,7 +416,7 @@ class LocalEngineArtifacts extends Artifacts { @override String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) { platform ??= _currentHostPlatform; - final String artifactFileName = _artifactToFileName(artifact, platform); + final String artifactFileName = _artifactToFileName(artifact, platform, mode); switch (artifact) { case Artifact.snapshotDart: return fs.path.join(_engineSrcPath, 'flutter', 'lib', 'snapshot', artifactFileName); @@ -482,13 +485,13 @@ class LocalEngineArtifacts extends Artifacts { return fs.path.join(_getFlutterWebSdkPath(), 'kernel', _artifactToFileName(artifact)); case Artifact.fuchsiaKernelCompiler: final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform()); - final String dartBinaries = 'dart_binaries-$mode-$hostPlatform'; + final String modeName = mode.isRelease ? 'release' : mode.toString(); + final String dartBinaries = 'dart_binaries-$modeName-$hostPlatform'; return fs.path.join(engineOutPath, 'host_bundle', dartBinaries, 'kernel_compiler.dart.snapshot'); - case Artifact.fuchsiaFlutterJitRunner: - if (mode == BuildMode.debug || mode == BuildMode.profile) { - return fs.path.join(engineOutPath, 'flutter_jit_runner-0.far'); - } - return fs.path.join(engineOutPath, 'flutter_jit_product_runner-0.far'); + case Artifact.fuchsiaFlutterRunner: + final String jitOrAot = mode.isJit ? '_jit' : '_aot'; + final String productOrNo = mode.isRelease ? '_product' : ''; + return fs.path.join(engineOutPath, 'flutter$jitOrAot${productOrNo}_runner-0.far'); } assert(false, 'Invalid artifact $artifact.'); return null; diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index d7977c76c..690a9c83a 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -59,6 +59,7 @@ class BuildInfo { static const BuildInfo debug = BuildInfo(BuildMode.debug, null); static const BuildInfo profile = BuildInfo(BuildMode.profile, null); + static const BuildInfo jitRelease = BuildInfo(BuildMode.jitRelease, null); static const BuildInfo release = BuildInfo(BuildMode.release, null); /// Returns whether a debug build is requested. @@ -68,14 +69,22 @@ class BuildInfo { /// Returns whether a profile build is requested. /// - /// Exactly one of [isDebug], [isProfile], or [isRelease] is true. + /// Exactly one of [isDebug], [isProfile], [isJitRelease], + /// or [isRelease] is true. bool get isProfile => mode == BuildMode.profile; /// Returns whether a release build is requested. /// - /// Exactly one of [isDebug], [isProfile], or [isRelease] is true. + /// Exactly one of [isDebug], [isProfile], [isJitRelease], + /// or [isRelease] is true. bool get isRelease => mode == BuildMode.release; + /// Returns whether a JIT release build is requested. + /// + /// Exactly one of [isDebug], [isProfile], [isJitRelease], + /// or [isRelease] is true. + bool get isJitRelease => mode == BuildMode.jitRelease; + bool get usesAot => isAotBuildMode(mode); bool get supportsEmulator => isEmulatorBuildMode(mode); bool get supportsSimulator => isEmulatorBuildMode(mode); diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index c82a2bd30..88b56776d 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -214,7 +214,7 @@ class AttachCommand extends FlutterCommand { if (module == null) { throwToolExit('\'--module\' is required for attaching to a Fuchsia device'); } - usesIpv6 = device.ipv6; + usesIpv6 = await device.ipv6; FuchsiaIsolateDiscoveryProtocol isolateDiscoveryProtocol; try { isolateDiscoveryProtocol = device.getIsolateDiscoveryProtocol(module); diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart index 55f52ef7d..a17f1b897 100644 --- a/packages/flutter_tools/lib/src/commands/build.dart +++ b/packages/flutter_tools/lib/src/commands/build.dart @@ -29,7 +29,7 @@ class BuildCommand extends FlutterCommand { addSubcommand(BuildIOSFrameworkCommand()); addSubcommand(BuildBundleCommand(verboseHelp: verboseHelp)); addSubcommand(BuildWebCommand()); - addSubcommand(BuildMacosCommand(verboseHelp: verboseHelp)); + addSubcommand(BuildMacosCommand()); addSubcommand(BuildLinuxCommand()); addSubcommand(BuildWindowsCommand()); addSubcommand(BuildFuchsiaCommand(verboseHelp: verboseHelp)); diff --git a/packages/flutter_tools/lib/src/commands/build_fuchsia.dart b/packages/flutter_tools/lib/src/commands/build_fuchsia.dart index 18b93e1a6..d26482544 100644 --- a/packages/flutter_tools/lib/src/commands/build_fuchsia.dart +++ b/packages/flutter_tools/lib/src/commands/build_fuchsia.dart @@ -31,6 +31,11 @@ class BuildFuchsiaCommand extends BuildSubCommand { ], defaultsTo: FuchsiaPackageServer.toolHost, ); + argParser.addOption('target-platform', + defaultsTo: 'fuchsia-x64', + allowed: ['fuchsia-arm64', 'fuchsia-x64'], + help: 'The target platform for which the app is compiled.', + ); } @override @@ -69,6 +74,7 @@ class BuildFuchsiaCommand extends BuildSubCommand { await buildFuchsia( fuchsiaProject: flutterProject.fuchsia, target: targetFile, + targetPlatform: getTargetPlatformForName(argResults['target-platform']), buildInfo: buildInfo, runnerPackageSource: stringArg('runner-source'), ); diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 4a1ed9d9a..7794f5f50 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart @@ -19,24 +19,13 @@ import 'build.dart'; /// .ipas, see https://flutter.dev/docs/deployment/ios. class BuildIOSCommand extends BuildSubCommand { BuildIOSCommand() { + addBuildModeFlags(defaultToRelease: false); usesTargetOption(); usesFlavorOption(); usesPubOption(); usesBuildNumberOption(); usesBuildNameOption(); argParser - ..addFlag('debug', - negatable: false, - help: 'Build a debug version of your app (default mode for iOS simulator builds).', - ) - ..addFlag('profile', - negatable: false, - help: 'Build a version of your app specialized for performance profiling.', - ) - ..addFlag('release', - negatable: false, - help: 'Build a release version of your app (default mode for device builds).', - ) ..addFlag('simulator', help: 'Build for the iOS simulator instead of the device.', ) diff --git a/packages/flutter_tools/lib/src/commands/build_linux.dart b/packages/flutter_tools/lib/src/commands/build_linux.dart index 63851ee74..1f07d4c8e 100644 --- a/packages/flutter_tools/lib/src/commands/build_linux.dart +++ b/packages/flutter_tools/lib/src/commands/build_linux.dart @@ -17,19 +17,8 @@ import 'build.dart'; /// A command to build a linux desktop target through a build shell script. class BuildLinuxCommand extends BuildSubCommand { BuildLinuxCommand() { + addBuildModeFlags(); usesTargetOption(); - argParser.addFlag('debug', - negatable: false, - help: 'Build a debug version of your app.', - ); - argParser.addFlag('profile', - negatable: false, - help: 'Build a version of your app specialized for performance profiling.', - ); - argParser.addFlag('release', - negatable: false, - help: 'Build a version of your app specialized for performance profiling.', - ); } @override diff --git a/packages/flutter_tools/lib/src/commands/build_macos.dart b/packages/flutter_tools/lib/src/commands/build_macos.dart index 86b4041b0..fe3cf29cf 100644 --- a/packages/flutter_tools/lib/src/commands/build_macos.dart +++ b/packages/flutter_tools/lib/src/commands/build_macos.dart @@ -16,9 +16,9 @@ import 'build.dart'; /// A command to build a macOS desktop target through a build shell script. class BuildMacosCommand extends BuildSubCommand { - BuildMacosCommand({bool verboseHelp}) { + BuildMacosCommand() { usesTargetOption(); - addBuildModeFlags(verboseHelp: verboseHelp); + addBuildModeFlags(); } @override diff --git a/packages/flutter_tools/lib/src/commands/build_windows.dart b/packages/flutter_tools/lib/src/commands/build_windows.dart index a48dd88d2..a9103ace8 100644 --- a/packages/flutter_tools/lib/src/commands/build_windows.dart +++ b/packages/flutter_tools/lib/src/commands/build_windows.dart @@ -17,19 +17,8 @@ import 'build.dart'; /// A command to build a windows desktop target through a build shell script. class BuildWindowsCommand extends BuildSubCommand { BuildWindowsCommand() { + addBuildModeFlags(); usesTargetOption(); - argParser.addFlag('debug', - negatable: false, - help: 'Build a debug version of your app.', - ); - argParser.addFlag('profile', - negatable: false, - help: 'Build a version of your app specialized for performance profiling.', - ); - argParser.addFlag('release', - negatable: false, - help: 'Build a version of your app specialized for performance profiling.', - ); } @override diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 6f40434f9..c41709a71 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -295,7 +295,7 @@ class RunCommand extends RunCommandBase { DebuggingOptions _createDebuggingOptions() { final BuildInfo buildInfo = getBuildInfo(); - if (buildInfo.isRelease) { + if (buildInfo.mode.isRelease) { return DebuggingOptions.disabled( buildInfo, initializePlatform: boolArg('web-initialize-platform'), diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart index 32c0bb85f..96ea6e723 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_build.dart @@ -6,10 +6,13 @@ import 'dart:async'; import 'package:meta/meta.dart'; +import '../artifacts.dart'; import '../asset.dart'; import '../base/common.dart'; import '../base/file_system.dart'; import '../base/io.dart'; +import '../base/logger.dart'; +import '../base/process.dart'; import '../base/utils.dart'; import '../build_info.dart'; import '../bundle.dart'; @@ -37,6 +40,7 @@ Future _timedBuildStep(String name, Future Function() action) async // Fuchsia package. Future buildFuchsia({ @required FuchsiaProject fuchsiaProject, + @required TargetPlatform targetPlatform, @required String target, // E.g., lib/main.dart BuildInfo buildInfo = BuildInfo.debug, String runnerPackageSource = FuchsiaPackageServer.toolHost, @@ -49,12 +53,66 @@ Future buildFuchsia({ await _timedBuildStep('fuchsia-kernel-compile', () => fuchsiaSdk.fuchsiaKernelCompiler.build( fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo)); + + if (buildInfo.usesAot) { + await _timedBuildStep('fuchsia-gen-snapshot', + () => _genSnapshot(fuchsiaProject, target, buildInfo, targetPlatform)); + } + await _timedBuildStep('fuchsia-build-assets', () => _buildAssets(fuchsiaProject, target, buildInfo)); await _timedBuildStep('fuchsia-build-package', () => _buildPackage(fuchsiaProject, target, buildInfo, runnerPackageSource)); } +Future _genSnapshot( + FuchsiaProject fuchsiaProject, + String target, // lib/main.dart + BuildInfo buildInfo, + TargetPlatform targetPlatform, +) async { + final String outDir = getFuchsiaBuildDirectory(); + final String appName = fuchsiaProject.project.manifest.appName; + final String dilPath = fs.path.join(outDir, '$appName.dil'); + + final String vmSnapshotData = fs.path.join(outDir, 'vm_data.aotsnapshot'); + final String vmSnapshotInstructions = fs.path.join(outDir, 'vm_instructions.aotsnapshot'); + final String snapshotData = fs.path.join(outDir, 'data.aotsnapshot'); + final String snapshotInstructions = fs.path.join(outDir, 'instructions.aotsnapshot'); + + final String genSnapshot = artifacts.getArtifactPath( + Artifact.genSnapshot, + platform: targetPlatform, + mode: buildInfo.mode, + ); + + final List command = [ + genSnapshot, + '--no_causal_async_stacks', + '--deterministic', + '--snapshot_kind=app-aot-blobs', + '--vm_snapshot_data=$vmSnapshotData', + '--vm_snapshot_instructions=$vmSnapshotInstructions', + '--isolate_snapshot_data=$snapshotData', + '--isolate_snapshot_instructions=$snapshotInstructions', + if (buildInfo.isDebug) '--enable-asserts', + dilPath, + ]; + int result; + final Status status = logger.startProgress( + 'Compiling Fuchsia application to native code...', + timeout: null, + ); + try { + result = await processUtils.stream(command, trace: true); + } finally { + status.cancel(); + } + if (result != 0) { + throwToolExit('Build process failed'); + } +} + Future _buildAssets( FuchsiaProject fuchsiaProject, String target, // lib/main.dart @@ -98,12 +156,17 @@ void _rewriteCmx(BuildMode mode, String runnerPackageSource, File src, File dst) String runner; switch (mode) { case BuildMode.debug: - case BuildMode.profile: runner = 'flutter_jit_runner'; break; - case BuildMode.release: + case BuildMode.profile: + runner = 'flutter_aot_runner'; + break; + case BuildMode.jitRelease: runner = 'flutter_jit_product_runner'; break; + case BuildMode.release: + runner = 'flutter_aot_product_runner'; + break; default: throwToolExit('Fuchsia does not support build mode "$mode"'); break; @@ -122,7 +185,6 @@ Future _buildPackage( final String outDir = getFuchsiaBuildDirectory(); final String pkgDir = fs.path.join(outDir, 'pkg'); final String appName = fuchsiaProject.project.manifest.appName; - final String dilpmanifest = fs.path.join(outDir, '$appName.dilpmanifest'); final String pkgassets = fs.path.join(outDir, '${appName}_pkgassets'); final String packageManifest = fs.path.join(pkgDir, 'package_manifest'); final String devKeyPath = fs.path.join(pkgDir, 'development.key'); @@ -137,9 +199,29 @@ Future _buildPackage( final File dstCmx = fs.file(fs.path.join(outDir, '$appName.cmx')); _rewriteCmx(buildInfo.mode, runnerPackageSource, srcCmx, dstCmx); - // Concatenate dilpmanifest and pkgassets into package_manifest. final File manifestFile = fs.file(packageManifest); - manifestFile.writeAsStringSync(fs.file(dilpmanifest).readAsStringSync()); + + if (buildInfo.usesAot) { + final String vmSnapshotData = fs.path.join(outDir, 'vm_data.aotsnapshot'); + final String vmSnapshotInstructions = fs.path.join(outDir, 'vm_instructions.aotsnapshot'); + final String snapshotData = fs.path.join(outDir, 'data.aotsnapshot'); + final String snapshotInstructions = fs.path.join(outDir, 'instructions.aotsnapshot'); + manifestFile.writeAsStringSync( + 'data/$appName/vm_snapshot_data.bin=$vmSnapshotData\n'); + manifestFile.writeAsStringSync( + 'data/$appName/vm_snapshot_instructions.bin=$vmSnapshotInstructions\n', + mode: FileMode.append); + manifestFile.writeAsStringSync( + 'data/$appName/isolate_snapshot_data.bin=$snapshotData\n', + mode: FileMode.append); + manifestFile.writeAsStringSync( + 'data/$appName/isolate_snapshot_instructions.bin=$snapshotInstructions\n', + mode: FileMode.append); + } else { + final String dilpmanifest = fs.path.join(outDir, '$appName.dilpmanifest'); + manifestFile.writeAsStringSync(fs.file(dilpmanifest).readAsStringSync()); + } + manifestFile.writeAsStringSync(fs.file(pkgassets).readAsStringSync(), mode: FileMode.append); manifestFile.writeAsStringSync('meta/$appName.cmx=${dstCmx.path}\n', diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_dev_finder.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_dev_finder.dart index ba3d877d6..b7b749e23 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_dev_finder.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_dev_finder.dart @@ -40,12 +40,14 @@ class FuchsiaDevFinder { return result.stdout.split('\n'); } - /// Returns the host address by which the device [deviceName] should use for - /// the host. + /// Returns the address of the named device. + /// + /// If local is true, then gives the address by which the device reaches the + /// host. /// /// The string [deviceName] should be the name of the device from the /// 'list' command, e.g. 'scare-cable-skip-joy'. - Future resolve(String deviceName) async { + Future resolve(String deviceName, {bool local = false}) async { if (fuchsiaArtifacts.devFinder == null || !fuchsiaArtifacts.devFinder.existsSync()) { throwToolExit('Fuchsia dev_finder tool not found.'); @@ -53,7 +55,7 @@ class FuchsiaDevFinder { final List command = [ fuchsiaArtifacts.devFinder.path, 'resolve', - '-local', + if (local) '-local', '-device-limit', '1', deviceName, ]; diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart index 381145f72..29bee795f 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart @@ -230,13 +230,17 @@ class FuchsiaDevice extends Device { }) async { if (!prebuiltApplication) { await buildFuchsia(fuchsiaProject: FlutterProject.current().fuchsia, + targetPlatform: await targetPlatform, target: mainPath, buildInfo: debuggingOptions.buildInfo); } // Stop the app if it's currently running. await stopApp(package); // Find out who the device thinks we are. - final String host = await fuchsiaSdk.fuchsiaDevFinder.resolve(name); + final String host = await fuchsiaSdk.fuchsiaDevFinder.resolve( + name, + local: true, + ); if (host == null) { printError('Failed to resolve host for Fuchsia device'); return LaunchResult.failed(); @@ -301,7 +305,7 @@ class FuchsiaDevice extends Device { // Serve the flutter_runner. final File flutterRunnerArchive = fs.file(artifacts.getArtifactPath( - Artifact.fuchsiaFlutterJitRunner, + Artifact.fuchsiaFlutterRunner, platform: await targetPlatform, mode: debuggingOptions.buildInfo.mode, )); @@ -318,10 +322,19 @@ class FuchsiaDevice extends Device { serverRegistered = true; // Tell the package controller to prefetch the flutter_runner. - String flutterRunnerName = 'flutter_jit_runner'; - if (!debuggingOptions.buildInfo.isDebug && - !debuggingOptions.buildInfo.isProfile) { - flutterRunnerName = 'flutter_jit_product_runner'; + String flutterRunnerName; + if (debuggingOptions.buildInfo.usesAot) { + if (debuggingOptions.buildInfo.mode.isRelease) { + flutterRunnerName = 'flutter_aot_product_runner'; + } else { + flutterRunnerName = 'flutter_aot_runner'; + } + } else { + if (debuggingOptions.buildInfo.mode.isRelease) { + flutterRunnerName = 'flutter_jit_product_runner'; + } else { + flutterRunnerName = 'flutter_jit_runner'; + } } if (!await fuchsiaDeviceTools.amberCtl.pkgCtlResolve( this, fuchsiaPackageServer, flutterRunnerName)) { @@ -367,14 +380,15 @@ class FuchsiaDevice extends Device { status.cancel(); } - if (!debuggingOptions.buildInfo.isDebug && - !debuggingOptions.buildInfo.isProfile) { + if (debuggingOptions.buildInfo.mode.isRelease) { + printTrace('App succesfully started in a release mode.'); return LaunchResult.succeeded(); } + printTrace('App started in a non-release mode. Setting up vmservice connection.'); // In a debug or profile build, try to find the observatory uri. final FuchsiaIsolateDiscoveryProtocol discovery = - getIsolateDiscoveryProtocol(appName); + getIsolateDiscoveryProtocol(appName); try { final Uri observatoryUri = await discovery.uri; return LaunchResult.succeeded(observatoryUri: observatoryUri); @@ -452,9 +466,9 @@ class FuchsiaDevice extends Device { @override bool get supportsScreenshot => false; - bool get ipv6 { + Future get ipv6 async { // Workaround for https://github.com/dart-lang/sdk/issues/29456 - final String fragment = id.split('%').first; + final String fragment = (await _resolvedIp).split('%').first; try { Uri.parseIPv6Address(fragment); return true; @@ -468,7 +482,7 @@ class FuchsiaDevice extends Device { const String findCommand = 'find /hub -name vmservice-port'; final RunResult findResult = await shell(findCommand); if (findResult.exitCode != 0) { - throwToolExit("'$findCommand' on device $id failed. stderr: '${findResult.stderr}'"); + throwToolExit("'$findCommand' on device $name failed. stderr: '${findResult.stderr}'"); return null; } final String findOutput = findResult.stdout; @@ -485,7 +499,7 @@ class FuchsiaDevice extends Device { final String lsCommand = 'ls $path'; final RunResult lsResult = await shell(lsCommand); if (lsResult.exitCode != 0) { - throwToolExit("'$lsCommand' on device $id failed"); + throwToolExit("'$lsCommand' on device $name failed"); return null; } final String lsOutput = lsResult.stdout; @@ -502,6 +516,15 @@ class FuchsiaDevice extends Device { return ports; } + String _cachedResolvedIp; + + Future get _resolvedIp async { + return _cachedResolvedIp ??= await fuchsiaSdk.fuchsiaDevFinder.resolve( + name, + local: false, + ); + } + /// Run `command` on the Fuchsia device shell. Future shell(String command) async { if (fuchsiaArtifacts.sshConfig == null) { @@ -512,7 +535,7 @@ class FuchsiaDevice extends Device { 'ssh', '-F', fuchsiaArtifacts.sshConfig.absolute.path, - id, + await _resolvedIp, command, ]); } @@ -633,7 +656,7 @@ class FuchsiaIsolateDiscoveryProtocol { } final Uri address = flutterView.owner.vmService.httpAddress; if (flutterView.uiIsolate.name.contains(_isolateName)) { - _foundUri.complete(_device.ipv6 + _foundUri.complete(await _device.ipv6 ? Uri.parse('http://[$_ipv6Loopback]:${address.port}/') : Uri.parse('http://$_ipv4Loopback:${address.port}/')); _status.stop(); @@ -674,7 +697,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { '-f', '-L', '$hostPort:$_ipv4Loopback:$devicePort', - device.id, + await device._resolvedIp, 'true', ]; final Process process = await processManager.start(command); @@ -706,7 +729,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder { '-vvv', '-L', '${forwardedPort.hostPort}:$_ipv4Loopback:${forwardedPort.devicePort}', - device.id, + await device._resolvedIp, ]; final ProcessResult result = await processManager.run(command); if (result.exitCode != 0) { diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart index b99180331..b0572e6ed 100644 --- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart +++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_kernel_compiler.dart @@ -7,11 +7,9 @@ import 'package:meta/meta.dart'; import '../artifacts.dart'; import '../base/common.dart'; import '../base/file_system.dart'; -import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; import '../build_info.dart'; -import '../convert.dart'; import '../globals.dart'; import '../project.dart'; @@ -58,35 +56,31 @@ class FuchsiaKernelCompiler { '--filesystem-root', fsRoot, '--packages', '$multiRootScheme:///$relativePackagesFile', '--output', fs.path.join(outDir, '$appName.dil'), - // TODO(zra): Add back when this is supported again. - // See: https://github.com/flutter/flutter/issues/44925 - // '--no-link-platform', - '--split-output-by-packages', - '--manifest', manifestPath, '--component-name', appName, - ]; - if (buildInfo.isDebug) { - flags += [ - '--embed-sources', - ]; - } else if (buildInfo.isProfile) { - flags += [ - '--no-embed-sources', - '-Ddart.vm.profile=true', + // AOT/JIT: + if (buildInfo.usesAot) ...['--aot', '--tfa'] + else ...[ + // TODO(zra): Add back when this is supported again. + // See: https://github.com/flutter/flutter/issues/44925 + // '--no-link-platform', + '--split-output-by-packages', + '--manifest', manifestPath + ], + + // debug, profile, jit release, release: + if (buildInfo.isDebug) '--embed-sources' + else '--no-embed-sources', + + if (buildInfo.isProfile) '-Ddart.vm.profile=true', + if (buildInfo.mode.isRelease) '-Ddart.vm.release=true', + + // Use bytecode and drop the ast in JIT release mode. + if (buildInfo.isJitRelease) ...[ '--gen-bytecode', '--drop-ast', - ]; - } else if (buildInfo.isRelease) { - flags += [ - '--no-embed-sources', - '-Ddart.vm.release=true', - '--gen-bytecode', - '--drop-ast', - ]; - } else { - throwToolExit('Expected build type to be debug, profile, or release'); - } + ], + ]; flags += [ '$multiRootScheme:///$target', @@ -97,22 +91,13 @@ class FuchsiaKernelCompiler { kernelCompiler, ...flags, ]; - final Process process = await processUtils.start(command); final Status status = logger.startProgress( 'Building Fuchsia application...', timeout: null, ); int result; try { - process.stderr - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(printError); - process.stdout - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen(printTrace); - result = await process.exitCode; + result = await processUtils.stream(command, trace: true); } finally { status.cancel(); } diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 3686e045d..e08eb7288 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -337,6 +337,10 @@ abstract class FlutterCommand extends Command { argParser.addFlag('release', negatable: false, help: 'Build a release version of your app${defaultToRelease ? ' (default mode)' : ''}.'); + argParser.addFlag('jit-release', + negatable: false, + hide: !verboseHelp, + help: 'Build a JIT release version of your app${defaultToRelease ? ' (default mode)' : ''}.'); } void addShrinkingFlag() { @@ -374,10 +378,18 @@ abstract class FlutterCommand extends Command { } BuildMode getBuildMode() { + // No debug when _excludeDebug is true. + // If debug is not excluded, then take the command line flag. final bool debugResult = !_excludeDebug && boolArg('debug'); - final List modeFlags = [debugResult, boolArg('profile'), boolArg('release')]; + final List modeFlags = [ + debugResult, + boolArg('jit-release'), + boolArg('profile'), + boolArg('release'), + ]; if (modeFlags.where((bool flag) => flag).length > 1) { - throw UsageException('Only one of --debug, --profile, or --release can be specified.', null); + throw UsageException('Only one of --debug, --profile, --jit-release, ' + 'or --release can be specified.', null); } if (debugResult) { return BuildMode.debug; @@ -388,6 +400,9 @@ abstract class FlutterCommand extends Command { if (boolArg('release')) { return BuildMode.release; } + if (boolArg('jit-release')) { + return BuildMode.jitRelease; + } return _defaultBuildMode; } diff --git a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart index 65803ed14..22ce941a2 100644 --- a/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart +++ b/packages/flutter_tools/test/general.shard/fuchsia/fuchsia_device_test.dart @@ -25,6 +25,7 @@ import 'package:flutter_tools/src/fuchsia/fuchsia_kernel_compiler.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_pm.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'; import 'package:flutter_tools/src/fuchsia/tiles_ctl.dart'; +import 'package:flutter_tools/src/globals.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/vmservice.dart'; import 'package:meta/meta.dart'; @@ -111,6 +112,7 @@ void main() { expect(await device.targetPlatform, TargetPlatform.fuchsia_arm64); }, overrides: { FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), + FuchsiaSdk: () => MockFuchsiaSdk(), ProcessUtils: () => mockProcessUtils, }); @@ -122,6 +124,7 @@ void main() { expect(await device.targetPlatform, TargetPlatform.fuchsia_x64); }, overrides: { FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), + FuchsiaSdk: () => MockFuchsiaSdk(), ProcessUtils: () => mockProcessUtils, }); }); @@ -180,6 +183,7 @@ void main() { sshConfig: mockFile, devFinder: mockFile, ), + FuchsiaSdk: () => MockFuchsiaSdk(), }); group('device logs', () { @@ -378,7 +382,38 @@ void main() { }); }); - group('fuchsia app start and stop: ', () { + testUsingContext('Correct flutter runner', () async { + expect(artifacts.getArtifactPath( + Artifact.fuchsiaFlutterRunner, + platform: TargetPlatform.fuchsia_x64, + mode: BuildMode.debug, + ), + contains('flutter_jit_runner'), + ); + expect(artifacts.getArtifactPath( + Artifact.fuchsiaFlutterRunner, + platform: TargetPlatform.fuchsia_x64, + mode: BuildMode.profile, + ), + contains('flutter_aot_runner'), + ); + expect(artifacts.getArtifactPath( + Artifact.fuchsiaFlutterRunner, + platform: TargetPlatform.fuchsia_x64, + mode: BuildMode.release, + ), + contains('flutter_aot_product_runner'), + ); + expect(artifacts.getArtifactPath( + Artifact.fuchsiaFlutterRunner, + platform: TargetPlatform.fuchsia_x64, + mode: BuildMode.jitRelease, + ), + contains('flutter_jit_product_runner'), + ); + }); + + group('Fuchsia app start and stop: ', () { MemoryFileSystem memoryFileSystem; FakeOperatingSystemUtils osUtils; FakeFuchsiaDeviceTools fuchsiaDeviceTools; @@ -420,7 +455,7 @@ void main() { mode: anyNamed('mode'), )).thenReturn(patchedSdk.path); when(mockArtifacts.getArtifactPath( - Artifact.fuchsiaFlutterJitRunner, + Artifact.fuchsiaFlutterRunner, platform: anyNamed('platform'), mode: anyNamed('mode'), )).thenReturn(runner.path); @@ -650,6 +685,7 @@ void main() { }, overrides: { ProcessManager: () => mockSuccessProcessManager, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), + FuchsiaSdk: () => MockFuchsiaSdk(), }); testUsingContext('returns "Fuchsia" when device command fails', () async { @@ -658,6 +694,7 @@ void main() { }, overrides: { ProcessManager: () => mockFailureProcessManager, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), + FuchsiaSdk: () => MockFuchsiaSdk(), }); testUsingContext('returns "Fuchsia" when device gives an empty result', () async { @@ -666,6 +703,7 @@ void main() { }, overrides: { ProcessManager: () => emptyStdoutProcessManager, FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), + FuchsiaSdk: () => MockFuchsiaSdk(), }); }); } @@ -722,12 +760,16 @@ Process _createMockProcess({ } class MockFuchsiaDevice extends Mock implements FuchsiaDevice { - MockFuchsiaDevice(this.id, this.portForwarder, this.ipv6); + MockFuchsiaDevice(this.id, this.portForwarder, this._ipv6); + + final bool _ipv6; @override - final bool ipv6; + Future get ipv6 async => _ipv6; + @override final String id; + @override final DevicePortForwarder portForwarder; @@ -1073,7 +1115,7 @@ class FakeFuchsiaDevFinder implements FuchsiaDevFinder { } @override - Future resolve(String deviceName) async { + Future resolve(String deviceName, {bool local = false}) async { return '192.168.42.10'; } } @@ -1085,7 +1127,7 @@ class FailingDevFinder implements FuchsiaDevFinder { } @override - Future resolve(String deviceName) async { + Future resolve(String deviceName, {bool local = false}) async { return null; } }