[flutter_tool] Fuchsia AOT builds (#45187)

This commit is contained in:
Zachary Anderson 2019-11-21 08:32:58 -08:00 committed by GitHub
parent 43a8a1902e
commit a57dddd217
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 264 additions and 130 deletions

View file

@ -61,7 +61,7 @@ enum Artifact {
// Fuchsia artifacts from the engine prebuilts. // Fuchsia artifacts from the engine prebuilts.
fuchsiaKernelCompiler, fuchsiaKernelCompiler,
fuchsiaFlutterJitRunner, fuchsiaFlutterRunner,
} }
String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMode mode ]) { String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMode mode ]) {
@ -136,11 +136,10 @@ String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMo
return 'flutter_ddc_sdk.dill'; return 'flutter_ddc_sdk.dill';
case Artifact.fuchsiaKernelCompiler: case Artifact.fuchsiaKernelCompiler:
return 'kernel_compiler.snapshot'; return 'kernel_compiler.snapshot';
case Artifact.fuchsiaFlutterJitRunner: case Artifact.fuchsiaFlutterRunner:
if (mode == BuildMode.debug || mode == BuildMode.profile) { final String jitOrAot = mode.isJit ? '_jit' : '_aot';
return 'flutter_jit_runner-0.far'; final String productOrNo = mode.isRelease ? '_product' : '';
} return 'flutter$jitOrAot${productOrNo}_runner-0.far';
return 'flutter_jit_product_runner-0.far';
} }
assert(false, 'Invalid artifact $artifact.'); assert(false, 'Invalid artifact $artifact.');
return null; return null;
@ -278,21 +277,25 @@ class CachedArtifacts extends Artifacts {
cache.getArtifactDirectory('flutter_runner').path, cache.getArtifactDirectory('flutter_runner').path,
'flutter', 'flutter',
fuchsiaArchForTargetPlatform(platform), fuchsiaArchForTargetPlatform(platform),
getNameForBuildMode(mode), mode.isRelease ? 'release' : mode.toString(),
); );
final String runtime = mode.isJit ? 'jit' : 'aot';
switch (artifact) { 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: case Artifact.flutterPatchedSdkPath:
const String artifactFileName = 'flutter_runner_patched_sdk'; const String artifactFileName = 'flutter_runner_patched_sdk';
return fs.path.join(root, 'jit', artifactFileName); return fs.path.join(root, runtime, artifactFileName);
case Artifact.platformKernelDill: case Artifact.platformKernelDill:
final String artifactFileName = _artifactToFileName(artifact, platform, mode); 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: case Artifact.fuchsiaKernelCompiler:
final String artifactFileName = _artifactToFileName(artifact, platform, mode); final String artifactFileName = _artifactToFileName(artifact, platform, mode);
return fs.path.join(root, 'jit', 'dart_binaries', artifactFileName); return fs.path.join(root, runtime, 'dart_binaries', artifactFileName);
case Artifact.fuchsiaFlutterJitRunner: case Artifact.fuchsiaFlutterRunner:
final String artifactFileName = _artifactToFileName(artifact, platform, mode); final String artifactFileName = _artifactToFileName(artifact, platform, mode);
return fs.path.join(root, 'jit', artifactFileName); return fs.path.join(root, runtime, artifactFileName);
default: default:
return _getHostArtifactPath(artifact, platform, mode); return _getHostArtifactPath(artifact, platform, mode);
} }
@ -413,7 +416,7 @@ class LocalEngineArtifacts extends Artifacts {
@override @override
String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) { String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) {
platform ??= _currentHostPlatform; platform ??= _currentHostPlatform;
final String artifactFileName = _artifactToFileName(artifact, platform); final String artifactFileName = _artifactToFileName(artifact, platform, mode);
switch (artifact) { switch (artifact) {
case Artifact.snapshotDart: case Artifact.snapshotDart:
return fs.path.join(_engineSrcPath, 'flutter', 'lib', 'snapshot', artifactFileName); 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)); return fs.path.join(_getFlutterWebSdkPath(), 'kernel', _artifactToFileName(artifact));
case Artifact.fuchsiaKernelCompiler: case Artifact.fuchsiaKernelCompiler:
final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform()); 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'); return fs.path.join(engineOutPath, 'host_bundle', dartBinaries, 'kernel_compiler.dart.snapshot');
case Artifact.fuchsiaFlutterJitRunner: case Artifact.fuchsiaFlutterRunner:
if (mode == BuildMode.debug || mode == BuildMode.profile) { final String jitOrAot = mode.isJit ? '_jit' : '_aot';
return fs.path.join(engineOutPath, 'flutter_jit_runner-0.far'); final String productOrNo = mode.isRelease ? '_product' : '';
} return fs.path.join(engineOutPath, 'flutter$jitOrAot${productOrNo}_runner-0.far');
return fs.path.join(engineOutPath, 'flutter_jit_product_runner-0.far');
} }
assert(false, 'Invalid artifact $artifact.'); assert(false, 'Invalid artifact $artifact.');
return null; return null;

View file

@ -59,6 +59,7 @@ class BuildInfo {
static const BuildInfo debug = BuildInfo(BuildMode.debug, null); static const BuildInfo debug = BuildInfo(BuildMode.debug, null);
static const BuildInfo profile = BuildInfo(BuildMode.profile, 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); static const BuildInfo release = BuildInfo(BuildMode.release, null);
/// Returns whether a debug build is requested. /// Returns whether a debug build is requested.
@ -68,14 +69,22 @@ class BuildInfo {
/// Returns whether a profile build is requested. /// 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; bool get isProfile => mode == BuildMode.profile;
/// Returns whether a release build is requested. /// 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; 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 usesAot => isAotBuildMode(mode);
bool get supportsEmulator => isEmulatorBuildMode(mode); bool get supportsEmulator => isEmulatorBuildMode(mode);
bool get supportsSimulator => isEmulatorBuildMode(mode); bool get supportsSimulator => isEmulatorBuildMode(mode);

View file

@ -214,7 +214,7 @@ class AttachCommand extends FlutterCommand {
if (module == null) { if (module == null) {
throwToolExit('\'--module\' is required for attaching to a Fuchsia device'); throwToolExit('\'--module\' is required for attaching to a Fuchsia device');
} }
usesIpv6 = device.ipv6; usesIpv6 = await device.ipv6;
FuchsiaIsolateDiscoveryProtocol isolateDiscoveryProtocol; FuchsiaIsolateDiscoveryProtocol isolateDiscoveryProtocol;
try { try {
isolateDiscoveryProtocol = device.getIsolateDiscoveryProtocol(module); isolateDiscoveryProtocol = device.getIsolateDiscoveryProtocol(module);

View file

@ -31,6 +31,11 @@ class BuildFuchsiaCommand extends BuildSubCommand {
], ],
defaultsTo: FuchsiaPackageServer.toolHost, defaultsTo: FuchsiaPackageServer.toolHost,
); );
argParser.addOption('target-platform',
defaultsTo: 'fuchsia-x64',
allowed: <String>['fuchsia-arm64', 'fuchsia-x64'],
help: 'The target platform for which the app is compiled.',
);
} }
@override @override
@ -69,6 +74,7 @@ class BuildFuchsiaCommand extends BuildSubCommand {
await buildFuchsia( await buildFuchsia(
fuchsiaProject: flutterProject.fuchsia, fuchsiaProject: flutterProject.fuchsia,
target: targetFile, target: targetFile,
targetPlatform: getTargetPlatformForName(argResults['target-platform']),
buildInfo: buildInfo, buildInfo: buildInfo,
runnerPackageSource: stringArg('runner-source'), runnerPackageSource: stringArg('runner-source'),
); );

View file

@ -19,24 +19,13 @@ import 'build.dart';
/// .ipas, see https://flutter.dev/docs/deployment/ios. /// .ipas, see https://flutter.dev/docs/deployment/ios.
class BuildIOSCommand extends BuildSubCommand { class BuildIOSCommand extends BuildSubCommand {
BuildIOSCommand() { BuildIOSCommand() {
addBuildModeFlags(defaultToRelease: false);
usesTargetOption(); usesTargetOption();
usesFlavorOption(); usesFlavorOption();
usesPubOption(); usesPubOption();
usesBuildNumberOption(); usesBuildNumberOption();
usesBuildNameOption(); usesBuildNameOption();
argParser 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', ..addFlag('simulator',
help: 'Build for the iOS simulator instead of the device.', help: 'Build for the iOS simulator instead of the device.',
) )

View file

@ -17,19 +17,8 @@ import 'build.dart';
/// A command to build a linux desktop target through a build shell script. /// A command to build a linux desktop target through a build shell script.
class BuildLinuxCommand extends BuildSubCommand { class BuildLinuxCommand extends BuildSubCommand {
BuildLinuxCommand() { BuildLinuxCommand() {
addBuildModeFlags(defaultToRelease: false);
usesTargetOption(); 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 @override

View file

@ -17,19 +17,8 @@ import 'build.dart';
/// A command to build a windows desktop target through a build shell script. /// A command to build a windows desktop target through a build shell script.
class BuildWindowsCommand extends BuildSubCommand { class BuildWindowsCommand extends BuildSubCommand {
BuildWindowsCommand() { BuildWindowsCommand() {
addBuildModeFlags(defaultToRelease: false);
usesTargetOption(); 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 @override

View file

@ -295,7 +295,7 @@ class RunCommand extends RunCommandBase {
DebuggingOptions _createDebuggingOptions() { DebuggingOptions _createDebuggingOptions() {
final BuildInfo buildInfo = getBuildInfo(); final BuildInfo buildInfo = getBuildInfo();
if (buildInfo.isRelease) { if (buildInfo.mode.isRelease) {
return DebuggingOptions.disabled( return DebuggingOptions.disabled(
buildInfo, buildInfo,
initializePlatform: boolArg('web-initialize-platform'), initializePlatform: boolArg('web-initialize-platform'),

View file

@ -6,10 +6,13 @@ import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../artifacts.dart';
import '../asset.dart'; import '../asset.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart';
import '../base/process.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../bundle.dart'; import '../bundle.dart';
@ -37,6 +40,7 @@ Future<void> _timedBuildStep(String name, Future<void> Function() action) async
// Fuchsia package. // Fuchsia package.
Future<void> buildFuchsia({ Future<void> buildFuchsia({
@required FuchsiaProject fuchsiaProject, @required FuchsiaProject fuchsiaProject,
@required TargetPlatform targetPlatform,
@required String target, // E.g., lib/main.dart @required String target, // E.g., lib/main.dart
BuildInfo buildInfo = BuildInfo.debug, BuildInfo buildInfo = BuildInfo.debug,
String runnerPackageSource = FuchsiaPackageServer.toolHost, String runnerPackageSource = FuchsiaPackageServer.toolHost,
@ -49,12 +53,66 @@ Future<void> buildFuchsia({
await _timedBuildStep('fuchsia-kernel-compile', await _timedBuildStep('fuchsia-kernel-compile',
() => fuchsiaSdk.fuchsiaKernelCompiler.build( () => fuchsiaSdk.fuchsiaKernelCompiler.build(
fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo)); fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo));
if (buildInfo.usesAot) {
await _timedBuildStep('fuchsia-gen-snapshot',
() => _genSnapshot(fuchsiaProject, target, buildInfo, targetPlatform));
}
await _timedBuildStep('fuchsia-build-assets', await _timedBuildStep('fuchsia-build-assets',
() => _buildAssets(fuchsiaProject, target, buildInfo)); () => _buildAssets(fuchsiaProject, target, buildInfo));
await _timedBuildStep('fuchsia-build-package', await _timedBuildStep('fuchsia-build-package',
() => _buildPackage(fuchsiaProject, target, buildInfo, runnerPackageSource)); () => _buildPackage(fuchsiaProject, target, buildInfo, runnerPackageSource));
} }
Future<void> _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<String> command = <String>[
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<void> _buildAssets( Future<void> _buildAssets(
FuchsiaProject fuchsiaProject, FuchsiaProject fuchsiaProject,
String target, // lib/main.dart String target, // lib/main.dart
@ -98,12 +156,17 @@ void _rewriteCmx(BuildMode mode, String runnerPackageSource, File src, File dst)
String runner; String runner;
switch (mode) { switch (mode) {
case BuildMode.debug: case BuildMode.debug:
case BuildMode.profile:
runner = 'flutter_jit_runner'; runner = 'flutter_jit_runner';
break; break;
case BuildMode.release: case BuildMode.profile:
runner = 'flutter_aot_runner';
break;
case BuildMode.jitRelease:
runner = 'flutter_jit_product_runner'; runner = 'flutter_jit_product_runner';
break; break;
case BuildMode.release:
runner = 'flutter_aot_product_runner';
break;
default: default:
throwToolExit('Fuchsia does not support build mode "$mode"'); throwToolExit('Fuchsia does not support build mode "$mode"');
break; break;
@ -122,7 +185,6 @@ Future<void> _buildPackage(
final String outDir = getFuchsiaBuildDirectory(); final String outDir = getFuchsiaBuildDirectory();
final String pkgDir = fs.path.join(outDir, 'pkg'); final String pkgDir = fs.path.join(outDir, 'pkg');
final String appName = fuchsiaProject.project.manifest.appName; 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 pkgassets = fs.path.join(outDir, '${appName}_pkgassets');
final String packageManifest = fs.path.join(pkgDir, 'package_manifest'); final String packageManifest = fs.path.join(pkgDir, 'package_manifest');
final String devKeyPath = fs.path.join(pkgDir, 'development.key'); final String devKeyPath = fs.path.join(pkgDir, 'development.key');
@ -137,9 +199,29 @@ Future<void> _buildPackage(
final File dstCmx = fs.file(fs.path.join(outDir, '$appName.cmx')); final File dstCmx = fs.file(fs.path.join(outDir, '$appName.cmx'));
_rewriteCmx(buildInfo.mode, runnerPackageSource, srcCmx, dstCmx); _rewriteCmx(buildInfo.mode, runnerPackageSource, srcCmx, dstCmx);
// Concatenate dilpmanifest and pkgassets into package_manifest.
final File manifestFile = fs.file(packageManifest); 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(), manifestFile.writeAsStringSync(fs.file(pkgassets).readAsStringSync(),
mode: FileMode.append); mode: FileMode.append);
manifestFile.writeAsStringSync('meta/$appName.cmx=${dstCmx.path}\n', manifestFile.writeAsStringSync('meta/$appName.cmx=${dstCmx.path}\n',

View file

@ -40,12 +40,14 @@ class FuchsiaDevFinder {
return result.stdout.split('\n'); return result.stdout.split('\n');
} }
/// Returns the host address by which the device [deviceName] should use for /// Returns the address of the named device.
/// the host. ///
/// 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 /// The string [deviceName] should be the name of the device from the
/// 'list' command, e.g. 'scare-cable-skip-joy'. /// 'list' command, e.g. 'scare-cable-skip-joy'.
Future<String> resolve(String deviceName) async { Future<String> resolve(String deviceName, {bool local = false}) async {
if (fuchsiaArtifacts.devFinder == null || if (fuchsiaArtifacts.devFinder == null ||
!fuchsiaArtifacts.devFinder.existsSync()) { !fuchsiaArtifacts.devFinder.existsSync()) {
throwToolExit('Fuchsia dev_finder tool not found.'); throwToolExit('Fuchsia dev_finder tool not found.');
@ -53,7 +55,7 @@ class FuchsiaDevFinder {
final List<String> command = <String>[ final List<String> command = <String>[
fuchsiaArtifacts.devFinder.path, fuchsiaArtifacts.devFinder.path,
'resolve', 'resolve',
'-local', if (local) '-local',
'-device-limit', '1', '-device-limit', '1',
deviceName, deviceName,
]; ];

View file

@ -230,13 +230,17 @@ class FuchsiaDevice extends Device {
}) async { }) async {
if (!prebuiltApplication) { if (!prebuiltApplication) {
await buildFuchsia(fuchsiaProject: FlutterProject.current().fuchsia, await buildFuchsia(fuchsiaProject: FlutterProject.current().fuchsia,
targetPlatform: await targetPlatform,
target: mainPath, target: mainPath,
buildInfo: debuggingOptions.buildInfo); buildInfo: debuggingOptions.buildInfo);
} }
// Stop the app if it's currently running. // Stop the app if it's currently running.
await stopApp(package); await stopApp(package);
// Find out who the device thinks we are. // 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) { if (host == null) {
printError('Failed to resolve host for Fuchsia device'); printError('Failed to resolve host for Fuchsia device');
return LaunchResult.failed(); return LaunchResult.failed();
@ -301,7 +305,7 @@ class FuchsiaDevice extends Device {
// Serve the flutter_runner. // Serve the flutter_runner.
final File flutterRunnerArchive = fs.file(artifacts.getArtifactPath( final File flutterRunnerArchive = fs.file(artifacts.getArtifactPath(
Artifact.fuchsiaFlutterJitRunner, Artifact.fuchsiaFlutterRunner,
platform: await targetPlatform, platform: await targetPlatform,
mode: debuggingOptions.buildInfo.mode, mode: debuggingOptions.buildInfo.mode,
)); ));
@ -318,10 +322,19 @@ class FuchsiaDevice extends Device {
serverRegistered = true; serverRegistered = true;
// Tell the package controller to prefetch the flutter_runner. // Tell the package controller to prefetch the flutter_runner.
String flutterRunnerName = 'flutter_jit_runner'; String flutterRunnerName;
if (!debuggingOptions.buildInfo.isDebug && if (debuggingOptions.buildInfo.usesAot) {
!debuggingOptions.buildInfo.isProfile) { if (debuggingOptions.buildInfo.mode.isRelease) {
flutterRunnerName = 'flutter_jit_product_runner'; 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( if (!await fuchsiaDeviceTools.amberCtl.pkgCtlResolve(
this, fuchsiaPackageServer, flutterRunnerName)) { this, fuchsiaPackageServer, flutterRunnerName)) {
@ -367,14 +380,15 @@ class FuchsiaDevice extends Device {
status.cancel(); status.cancel();
} }
if (!debuggingOptions.buildInfo.isDebug && if (debuggingOptions.buildInfo.mode.isRelease) {
!debuggingOptions.buildInfo.isProfile) { printTrace('App succesfully started in a release mode.');
return LaunchResult.succeeded(); 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. // In a debug or profile build, try to find the observatory uri.
final FuchsiaIsolateDiscoveryProtocol discovery = final FuchsiaIsolateDiscoveryProtocol discovery =
getIsolateDiscoveryProtocol(appName); getIsolateDiscoveryProtocol(appName);
try { try {
final Uri observatoryUri = await discovery.uri; final Uri observatoryUri = await discovery.uri;
return LaunchResult.succeeded(observatoryUri: observatoryUri); return LaunchResult.succeeded(observatoryUri: observatoryUri);
@ -452,9 +466,9 @@ class FuchsiaDevice extends Device {
@override @override
bool get supportsScreenshot => false; bool get supportsScreenshot => false;
bool get ipv6 { Future<bool> get ipv6 async {
// Workaround for https://github.com/dart-lang/sdk/issues/29456 // Workaround for https://github.com/dart-lang/sdk/issues/29456
final String fragment = id.split('%').first; final String fragment = (await _resolvedIp).split('%').first;
try { try {
Uri.parseIPv6Address(fragment); Uri.parseIPv6Address(fragment);
return true; return true;
@ -468,7 +482,7 @@ class FuchsiaDevice extends Device {
const String findCommand = 'find /hub -name vmservice-port'; const String findCommand = 'find /hub -name vmservice-port';
final RunResult findResult = await shell(findCommand); final RunResult findResult = await shell(findCommand);
if (findResult.exitCode != 0) { if (findResult.exitCode != 0) {
throwToolExit("'$findCommand' on device $id failed. stderr: '${findResult.stderr}'"); throwToolExit("'$findCommand' on device $name failed. stderr: '${findResult.stderr}'");
return null; return null;
} }
final String findOutput = findResult.stdout; final String findOutput = findResult.stdout;
@ -485,7 +499,7 @@ class FuchsiaDevice extends Device {
final String lsCommand = 'ls $path'; final String lsCommand = 'ls $path';
final RunResult lsResult = await shell(lsCommand); final RunResult lsResult = await shell(lsCommand);
if (lsResult.exitCode != 0) { if (lsResult.exitCode != 0) {
throwToolExit("'$lsCommand' on device $id failed"); throwToolExit("'$lsCommand' on device $name failed");
return null; return null;
} }
final String lsOutput = lsResult.stdout; final String lsOutput = lsResult.stdout;
@ -502,6 +516,15 @@ class FuchsiaDevice extends Device {
return ports; return ports;
} }
String _cachedResolvedIp;
Future<String> get _resolvedIp async {
return _cachedResolvedIp ??= await fuchsiaSdk.fuchsiaDevFinder.resolve(
name,
local: false,
);
}
/// Run `command` on the Fuchsia device shell. /// Run `command` on the Fuchsia device shell.
Future<RunResult> shell(String command) async { Future<RunResult> shell(String command) async {
if (fuchsiaArtifacts.sshConfig == null) { if (fuchsiaArtifacts.sshConfig == null) {
@ -512,7 +535,7 @@ class FuchsiaDevice extends Device {
'ssh', 'ssh',
'-F', '-F',
fuchsiaArtifacts.sshConfig.absolute.path, fuchsiaArtifacts.sshConfig.absolute.path,
id, await _resolvedIp,
command, command,
]); ]);
} }
@ -633,7 +656,7 @@ class FuchsiaIsolateDiscoveryProtocol {
} }
final Uri address = flutterView.owner.vmService.httpAddress; final Uri address = flutterView.owner.vmService.httpAddress;
if (flutterView.uiIsolate.name.contains(_isolateName)) { if (flutterView.uiIsolate.name.contains(_isolateName)) {
_foundUri.complete(_device.ipv6 _foundUri.complete(await _device.ipv6
? Uri.parse('http://[$_ipv6Loopback]:${address.port}/') ? Uri.parse('http://[$_ipv6Loopback]:${address.port}/')
: Uri.parse('http://$_ipv4Loopback:${address.port}/')); : Uri.parse('http://$_ipv4Loopback:${address.port}/'));
_status.stop(); _status.stop();
@ -674,7 +697,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
'-f', '-f',
'-L', '-L',
'$hostPort:$_ipv4Loopback:$devicePort', '$hostPort:$_ipv4Loopback:$devicePort',
device.id, await device._resolvedIp,
'true', 'true',
]; ];
final Process process = await processManager.start(command); final Process process = await processManager.start(command);
@ -706,7 +729,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
'-vvv', '-vvv',
'-L', '-L',
'${forwardedPort.hostPort}:$_ipv4Loopback:${forwardedPort.devicePort}', '${forwardedPort.hostPort}:$_ipv4Loopback:${forwardedPort.devicePort}',
device.id, await device._resolvedIp,
]; ];
final ProcessResult result = await processManager.run(command); final ProcessResult result = await processManager.run(command);
if (result.exitCode != 0) { if (result.exitCode != 0) {

View file

@ -7,11 +7,9 @@ import 'package:meta/meta.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../convert.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
@ -58,35 +56,31 @@ class FuchsiaKernelCompiler {
'--filesystem-root', fsRoot, '--filesystem-root', fsRoot,
'--packages', '$multiRootScheme:///$relativePackagesFile', '--packages', '$multiRootScheme:///$relativePackagesFile',
'--output', fs.path.join(outDir, '$appName.dil'), '--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, '--component-name', appName,
];
if (buildInfo.isDebug) { // AOT/JIT:
flags += <String>[ if (buildInfo.usesAot) ...<String>['--aot', '--tfa']
'--embed-sources', else ...<String>[
]; // TODO(zra): Add back when this is supported again.
} else if (buildInfo.isProfile) { // See: https://github.com/flutter/flutter/issues/44925
flags += <String>[ // '--no-link-platform',
'--no-embed-sources', '--split-output-by-packages',
'-Ddart.vm.profile=true', '--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) ...<String>[
'--gen-bytecode', '--gen-bytecode',
'--drop-ast', '--drop-ast',
]; ],
} else if (buildInfo.isRelease) { ];
flags += <String>[
'--no-embed-sources',
'-Ddart.vm.release=true',
'--gen-bytecode',
'--drop-ast',
];
} else {
throwToolExit('Expected build type to be debug, profile, or release');
}
flags += <String>[ flags += <String>[
'$multiRootScheme:///$target', '$multiRootScheme:///$target',
@ -97,22 +91,13 @@ class FuchsiaKernelCompiler {
kernelCompiler, kernelCompiler,
...flags, ...flags,
]; ];
final Process process = await processUtils.start(command);
final Status status = logger.startProgress( final Status status = logger.startProgress(
'Building Fuchsia application...', 'Building Fuchsia application...',
timeout: null, timeout: null,
); );
int result; int result;
try { try {
process.stderr result = await processUtils.stream(command, trace: true);
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printError);
process.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printTrace);
result = await process.exitCode;
} finally { } finally {
status.cancel(); status.cancel();
} }

View file

@ -337,6 +337,10 @@ abstract class FlutterCommand extends Command<void> {
argParser.addFlag('release', argParser.addFlag('release',
negatable: false, negatable: false,
help: 'Build a release version of your app${defaultToRelease ? ' (default mode)' : ''}.'); 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() { void addShrinkingFlag() {
@ -374,10 +378,18 @@ abstract class FlutterCommand extends Command<void> {
} }
BuildMode getBuildMode() { 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 bool debugResult = !_excludeDebug && boolArg('debug');
final List<bool> modeFlags = <bool>[debugResult, boolArg('profile'), boolArg('release')]; final List<bool> modeFlags = <bool>[
debugResult,
boolArg('jit-release'),
boolArg('profile'),
boolArg('release'),
];
if (modeFlags.where((bool flag) => flag).length > 1) { 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) { if (debugResult) {
return BuildMode.debug; return BuildMode.debug;
@ -388,6 +400,9 @@ abstract class FlutterCommand extends Command<void> {
if (boolArg('release')) { if (boolArg('release')) {
return BuildMode.release; return BuildMode.release;
} }
if (boolArg('jit-release')) {
return BuildMode.jitRelease;
}
return _defaultBuildMode; return _defaultBuildMode;
} }

View file

@ -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_pm.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart'; import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
import 'package:flutter_tools/src/fuchsia/tiles_ctl.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/project.dart';
import 'package:flutter_tools/src/vmservice.dart'; import 'package:flutter_tools/src/vmservice.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
@ -111,6 +112,7 @@ void main() {
expect(await device.targetPlatform, TargetPlatform.fuchsia_arm64); expect(await device.targetPlatform, TargetPlatform.fuchsia_arm64);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
ProcessUtils: () => mockProcessUtils, ProcessUtils: () => mockProcessUtils,
}); });
@ -122,6 +124,7 @@ void main() {
expect(await device.targetPlatform, TargetPlatform.fuchsia_x64); expect(await device.targetPlatform, TargetPlatform.fuchsia_x64);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
ProcessUtils: () => mockProcessUtils, ProcessUtils: () => mockProcessUtils,
}); });
}); });
@ -180,6 +183,7 @@ void main() {
sshConfig: mockFile, sshConfig: mockFile,
devFinder: mockFile, devFinder: mockFile,
), ),
FuchsiaSdk: () => MockFuchsiaSdk(),
}); });
group('device logs', () { 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; MemoryFileSystem memoryFileSystem;
FakeOperatingSystemUtils osUtils; FakeOperatingSystemUtils osUtils;
FakeFuchsiaDeviceTools fuchsiaDeviceTools; FakeFuchsiaDeviceTools fuchsiaDeviceTools;
@ -420,7 +455,7 @@ void main() {
mode: anyNamed('mode'), mode: anyNamed('mode'),
)).thenReturn(patchedSdk.path); )).thenReturn(patchedSdk.path);
when(mockArtifacts.getArtifactPath( when(mockArtifacts.getArtifactPath(
Artifact.fuchsiaFlutterJitRunner, Artifact.fuchsiaFlutterRunner,
platform: anyNamed('platform'), platform: anyNamed('platform'),
mode: anyNamed('mode'), mode: anyNamed('mode'),
)).thenReturn(runner.path); )).thenReturn(runner.path);
@ -650,6 +685,7 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => mockSuccessProcessManager, ProcessManager: () => mockSuccessProcessManager,
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
}); });
testUsingContext('returns "Fuchsia" when device command fails', () async { testUsingContext('returns "Fuchsia" when device command fails', () async {
@ -658,6 +694,7 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => mockFailureProcessManager, ProcessManager: () => mockFailureProcessManager,
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
}); });
testUsingContext('returns "Fuchsia" when device gives an empty result', () async { testUsingContext('returns "Fuchsia" when device gives an empty result', () async {
@ -666,6 +703,7 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => emptyStdoutProcessManager, ProcessManager: () => emptyStdoutProcessManager,
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig), FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
}); });
}); });
} }
@ -722,12 +760,16 @@ Process _createMockProcess({
} }
class MockFuchsiaDevice extends Mock implements FuchsiaDevice { class MockFuchsiaDevice extends Mock implements FuchsiaDevice {
MockFuchsiaDevice(this.id, this.portForwarder, this.ipv6); MockFuchsiaDevice(this.id, this.portForwarder, this._ipv6);
final bool _ipv6;
@override @override
final bool ipv6; Future<bool> get ipv6 async => _ipv6;
@override @override
final String id; final String id;
@override @override
final DevicePortForwarder portForwarder; final DevicePortForwarder portForwarder;
@ -1073,7 +1115,7 @@ class FakeFuchsiaDevFinder implements FuchsiaDevFinder {
} }
@override @override
Future<String> resolve(String deviceName) async { Future<String> resolve(String deviceName, {bool local = false}) async {
return '192.168.42.10'; return '192.168.42.10';
} }
} }
@ -1085,7 +1127,7 @@ class FailingDevFinder implements FuchsiaDevFinder {
} }
@override @override
Future<String> resolve(String deviceName) async { Future<String> resolve(String deviceName, {bool local = false}) async {
return null; return null;
} }
} }