Commit 2fc8e9a1 authored by Devon Carew's avatar Devon Carew

create a crash report

parent 03830d56
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:path/path.dart' as path;
import 'package:stack_trace/stack_trace.dart'; import 'package:stack_trace/stack_trace.dart';
import 'src/base/context.dart'; import 'src/base/context.dart';
...@@ -31,6 +32,7 @@ import 'src/commands/update_packages.dart'; ...@@ -31,6 +32,7 @@ import 'src/commands/update_packages.dart';
import 'src/commands/upgrade.dart'; import 'src/commands/upgrade.dart';
import 'src/device.dart'; import 'src/device.dart';
import 'src/doctor.dart'; import 'src/doctor.dart';
import 'src/globals.dart';
import 'src/runner/flutter_command_runner.dart'; import 'src/runner/flutter_command_runner.dart';
/// Main entry point for commands. /// Main entry point for commands.
...@@ -89,9 +91,65 @@ Future<Null> main(List<String> args) async { ...@@ -89,9 +91,65 @@ Future<Null> main(List<String> args) async {
// We've caught an exit code. // We've caught an exit code.
exit(error.exitCode); exit(error.exitCode);
} else { } else {
stderr.writeln(error); // We've crashed; emit a log report.
stderr.writeln(chain.terse); stderr.writeln();
stderr.writeln('Oops; flutter has crashed: "$error"');
File file = _createCrashReport(args, error, chain);
stderr.writeln();
stderr.writeln('Crash report written to ${path.relative(file.path)}.');
stderr.writeln('Please let us know at https://github.com/flutter/flutter/issues!');
exit(1); exit(1);
} }
}); });
} }
File _createCrashReport(List<String> args, dynamic error, Chain chain) {
File crashFile = _createCrashFileName(Directory.current, 'flutter');
StringBuffer buf = new StringBuffer();
buf.writeln('Flutter crash report; please file at https://github.com/flutter/flutter/issues.\n');
buf.writeln('## command\n');
buf.writeln('flutter ${args.join(' ')}\n');
buf.writeln('## exception\n');
buf.writeln('$error\n');
buf.writeln('${chain.terse}');
buf.writeln('## flutter doctor\n');
buf.writeln(_doctorText());
crashFile.writeAsStringSync(buf.toString());
return crashFile;
}
File _createCrashFileName(Directory dir, String baseName) {
int i = 1;
while (true) {
String name = '${baseName}_${i.toString().padLeft(2, '0')}.log';
File file = new File(path.join(dir.path, name));
if (!file.existsSync())
return file;
i++;
}
}
String _doctorText() {
try {
BufferLogger logger = new BufferLogger();
AppContext appContext = new AppContext();
appContext[Logger] = logger;
appContext.runInZone(() => doctor.diagnose());
return logger.statusText;
} catch (error) {
return '';
}
}
...@@ -223,9 +223,9 @@ class AndroidDevice extends Device { ...@@ -223,9 +223,9 @@ class AndroidDevice extends Device {
ServiceProtocolDiscovery serviceProtocolDiscovery = ServiceProtocolDiscovery serviceProtocolDiscovery =
new ServiceProtocolDiscovery(logReader); new ServiceProtocolDiscovery(logReader);
// We take this future here but do not wait for completion until *after* // We take this future here but do not wait for completion until *after* we
// we start the bundle. // start the bundle.
Future<int> serviceProtocolPort = serviceProtocolDiscovery.nextPort(); Future<int> scrapeServicePort = serviceProtocolDiscovery.nextPort();
List<String> cmd = adbCommandForDevice(<String>[ List<String> cmd = adbCommandForDevice(<String>[
'shell', 'am', 'start', 'shell', 'am', 'start',
...@@ -250,13 +250,23 @@ class AndroidDevice extends Device { ...@@ -250,13 +250,23 @@ class AndroidDevice extends Device {
return false; return false;
} }
// Wait for the service protocol port here. This will complete once // Wait for the service protocol port here. This will complete once the
// the device has printed "Observatory is listening on..." // device has printed "Observatory is listening on...".
int devicePort = await serviceProtocolPort; printTrace('Waiting for observatory port to be available...');
printTrace('service protocol port = $devicePort');
await _forwardObservatoryPort(devicePort, debugPort);
return true; try {
int devicePort = await scrapeServicePort.timeout(new Duration(seconds: 12));
printTrace('service protocol port = $devicePort');
await _forwardObservatoryPort(devicePort, debugPort);
return true;
} catch (error) {
if (error is TimeoutException)
printError('Timed out while waiting for a debug connection.');
else
printError('Error waiting for a debug connection: $error');
return false;
}
} }
@override @override
...@@ -303,7 +313,7 @@ class AndroidDevice extends Device { ...@@ -303,7 +313,7 @@ class AndroidDevice extends Device {
return runCommandAndStreamOutput(command).then((int exitCode) => exitCode == 0); return runCommandAndStreamOutput(command).then((int exitCode) => exitCode == 0);
} }
// TODO(devoncarew): Return android_arm or android_x64 based on [isLocalEmulator]. // TODO(devoncarew): Use isLocalEmulator to return android_arm or android_x64.
@override @override
TargetPlatform get platform => TargetPlatform.android_arm; TargetPlatform get platform => TargetPlatform.android_arm;
...@@ -533,7 +543,9 @@ class _AdbLogReader extends DeviceLogReader { ...@@ -533,7 +543,9 @@ class _AdbLogReader extends DeviceLogReader {
String lastTimestamp = device.lastLogcatTimestamp; String lastTimestamp = device.lastLogcatTimestamp;
if (lastTimestamp != null) if (lastTimestamp != null)
args.addAll(<String>['-T', lastTimestamp]); args.addAll(<String>['-T', lastTimestamp]);
args.addAll(<String>['-s', 'flutter:V', 'ActivityManager:W', 'System.err:W', '*:F']); args.addAll(<String>[
'-s', 'flutter:V', 'SkyMain:V', 'AndroidRuntime:W', 'ActivityManager:W', 'System.err:W', '*:F'
]);
_process = await runCommand(device.adbCommandForDevice(args)); _process = await runCommand(device.adbCommandForDevice(args));
_stdoutSubscription = _stdoutSubscription =
_process.stdout.transform(UTF8.decoder) _process.stdout.transform(UTF8.decoder)
......
...@@ -125,8 +125,7 @@ class ApplicationPackageStore { ...@@ -125,8 +125,7 @@ class ApplicationPackageStore {
for (BuildConfiguration config in configs) { for (BuildConfiguration config in configs) {
switch (config.targetPlatform) { switch (config.targetPlatform) {
case TargetPlatform.android_arm: case TargetPlatform.android_arm:
assert(android == null); android ??= new AndroidApk.fromBuildConfiguration(config);
android = new AndroidApk.fromBuildConfiguration(config);
break; break;
case TargetPlatform.ios: case TargetPlatform.ios:
......
...@@ -72,12 +72,15 @@ class Artifact { ...@@ -72,12 +72,15 @@ class Artifact {
class ArtifactStore { class ArtifactStore {
static const List<Artifact> knownArtifacts = const <Artifact>[ static const List<Artifact> knownArtifacts = const <Artifact>[
// tester
const Artifact._( const Artifact._(
name: 'Flutter Tester', name: 'Flutter Tester',
fileName: 'sky_shell', fileName: 'sky_shell',
type: ArtifactType.shell, type: ArtifactType.shell,
targetPlatform: TargetPlatform.linux_x64 targetPlatform: TargetPlatform.linux_x64
), ),
// snapshotters
const Artifact._( const Artifact._(
name: 'Sky Snapshot', name: 'Sky Snapshot',
fileName: 'sky_snapshot', fileName: 'sky_snapshot',
...@@ -90,6 +93,8 @@ class ArtifactStore { ...@@ -90,6 +93,8 @@ class ArtifactStore {
type: ArtifactType.snapshot, type: ArtifactType.snapshot,
hostPlatform: HostPlatform.mac hostPlatform: HostPlatform.mac
), ),
// mojo
const Artifact._( const Artifact._(
name: 'Flutter for Mojo', name: 'Flutter for Mojo',
fileName: 'flutter.mojo', fileName: 'flutter.mojo',
...@@ -102,6 +107,8 @@ class ArtifactStore { ...@@ -102,6 +107,8 @@ class ArtifactStore {
type: ArtifactType.mojo, type: ArtifactType.mojo,
targetPlatform: TargetPlatform.linux_x64 targetPlatform: TargetPlatform.linux_x64
), ),
// android-arm
const Artifact._( const Artifact._(
name: 'Compiled Java code', name: 'Compiled Java code',
fileName: 'classes.dex.jar', fileName: 'classes.dex.jar',
...@@ -126,6 +133,8 @@ class ArtifactStore { ...@@ -126,6 +133,8 @@ class ArtifactStore {
type: ArtifactType.androidLibSkyShell, type: ArtifactType.androidLibSkyShell,
targetPlatform: TargetPlatform.android_arm targetPlatform: TargetPlatform.android_arm
), ),
// iOS
const Artifact._( const Artifact._(
name: 'iOS Runner (Xcode Project)', name: 'iOS Runner (Xcode Project)',
fileName: 'FlutterXcode.zip', fileName: 'FlutterXcode.zip',
...@@ -202,7 +211,7 @@ class ArtifactStore { ...@@ -202,7 +211,7 @@ class ArtifactStore {
return cacheDir; return cacheDir;
} }
static Future<String> getPath(Artifact artifact) async { static String getPath(Artifact artifact) {
File cachedFile = new File(path.join( File cachedFile = new File(path.join(
getBaseCacheDir().path, 'engine', artifact.platform, artifact.fileName getBaseCacheDir().path, 'engine', artifact.platform, artifact.fileName
)); ));
......
...@@ -116,22 +116,28 @@ String _runWithLoggingSync(List<String> cmd, { ...@@ -116,22 +116,28 @@ String _runWithLoggingSync(List<String> cmd, {
printTrace(cmdText); printTrace(cmdText);
ProcessResult results = ProcessResult results =
Process.runSync(cmd[0], cmd.getRange(1, cmd.length).toList(), workingDirectory: workingDirectory); Process.runSync(cmd[0], cmd.getRange(1, cmd.length).toList(), workingDirectory: workingDirectory);
printTrace('Exit code ${results.exitCode} from: ${cmd.join(' ')}');
if (results.stdout.isNotEmpty) {
if (results.exitCode != 0 && noisyErrors)
printStatus(results.stdout.trim());
else
printTrace(results.stdout.trim());
}
if (results.exitCode != 0) { if (results.exitCode != 0) {
String errorDescription = 'Error code ${results.exitCode} ' if (results.stderr.isNotEmpty) {
'returned when attempting to run command: ${cmd.join(' ')}'; if (noisyErrors)
printTrace(errorDescription);
if (results.stderr.length > 0) {
if (noisyErrors) {
printError(results.stderr.trim()); printError(results.stderr.trim());
} else { else
printTrace('Errors logged: ${results.stderr.trim()}'); printTrace(results.stderr.trim());
}
} }
if (checked) if (checked)
throw errorDescription; throw 'Exit code ${results.exitCode} from: ${cmd.join(' ')}';
} }
if (results.stdout.trim().isNotEmpty)
printTrace(results.stdout.trim());
return results.stdout.trim(); return results.stdout.trim();
} }
......
...@@ -187,7 +187,10 @@ class BuildApkCommand extends FlutterCommand { ...@@ -187,7 +187,10 @@ class BuildApkCommand extends FlutterCommand {
await downloadToolchain(); await downloadToolchain();
// TODO(devoncarew): This command should take an arg for the output type (arm / x64).
return await buildAndroid( return await buildAndroid(
TargetPlatform.android_arm,
toolchain: toolchain, toolchain: toolchain,
configs: buildConfigurations, configs: buildConfigurations,
enginePath: runner.enginePath, enginePath: runner.enginePath,
...@@ -212,6 +215,7 @@ Future<_ApkComponents> _findApkComponents( ...@@ -212,6 +215,7 @@ Future<_ApkComponents> _findApkComponents(
) async { ) async {
List<String> artifactPaths; List<String> artifactPaths;
if (enginePath != null) { if (enginePath != null) {
// TODO(devoncarew): Support x64.
artifactPaths = [ artifactPaths = [
'$enginePath/third_party/icu/android/icudtl.dat', '$enginePath/third_party/icu/android/icudtl.dat',
'${config.buildDir}/gen/sky/shell/shell/classes.dex.jar', '${config.buildDir}/gen/sky/shell/shell/classes.dex.jar',
...@@ -225,10 +229,13 @@ Future<_ApkComponents> _findApkComponents( ...@@ -225,10 +229,13 @@ Future<_ApkComponents> _findApkComponents(
ArtifactType.androidLibSkyShell, ArtifactType.androidLibSkyShell,
ArtifactType.androidKeystore, ArtifactType.androidKeystore,
]; ];
Iterable<Future<String>> pathFutures = artifactTypes.map( Iterable<String> pathFutures = artifactTypes.map((ArtifactType type) {
(ArtifactType type) => ArtifactStore.getPath(ArtifactStore.getArtifact( return ArtifactStore.getPath(ArtifactStore.getArtifact(
type: type, targetPlatform: TargetPlatform.android_arm))); type: type,
artifactPaths = await Future.wait(pathFutures); targetPlatform: config.targetPlatform
));
});
artifactPaths = pathFutures.toList();
} }
_ApkComponents components = new _ApkComponents(); _ApkComponents components = new _ApkComponents();
...@@ -254,9 +261,14 @@ Future<_ApkComponents> _findApkComponents( ...@@ -254,9 +261,14 @@ Future<_ApkComponents> _findApkComponents(
} }
int _buildApk( int _buildApk(
_ApkComponents components, String flxPath, ApkKeystoreInfo keystore, String outputFile TargetPlatform platform,
_ApkComponents components,
String flxPath,
ApkKeystoreInfo keystore,
String outputFile
) { ) {
Directory tempDir = Directory.systemTemp.createTempSync('flutter_tools'); Directory tempDir = Directory.systemTemp.createTempSync('flutter_tools');
try { try {
_ApkBuilder builder = new _ApkBuilder(androidSdk.latestVersion); _ApkBuilder builder = new _ApkBuilder(androidSdk.latestVersion);
...@@ -273,7 +285,9 @@ int _buildApk( ...@@ -273,7 +285,9 @@ int _buildApk(
_AssetBuilder artifactBuilder = new _AssetBuilder(tempDir, 'artifacts'); _AssetBuilder artifactBuilder = new _AssetBuilder(tempDir, 'artifacts');
artifactBuilder.add(classesDex, 'classes.dex'); artifactBuilder.add(classesDex, 'classes.dex');
artifactBuilder.add(components.libSkyShell, 'lib/armeabi-v7a/libsky_shell.so'); // x86? x86_64?
String abiDir = platform == TargetPlatform.android_arm ? 'armeabi-v7a' : 'x86';
artifactBuilder.add(components.libSkyShell, 'lib/$abiDir/libsky_shell.so');
File unalignedApk = new File('${tempDir.path}/app.apk.unaligned'); File unalignedApk = new File('${tempDir.path}/app.apk.unaligned');
builder.package( builder.package(
...@@ -359,7 +373,8 @@ bool _needsRebuild(String apkPath, String manifest) { ...@@ -359,7 +373,8 @@ bool _needsRebuild(String apkPath, String manifest) {
return false; return false;
} }
Future<int> buildAndroid({ Future<int> buildAndroid(
TargetPlatform platform, {
Toolchain toolchain, Toolchain toolchain,
List<BuildConfiguration> configs, List<BuildConfiguration> configs,
String enginePath, String enginePath,
...@@ -367,7 +382,7 @@ Future<int> buildAndroid({ ...@@ -367,7 +382,7 @@ Future<int> buildAndroid({
String manifest: _kDefaultAndroidManifestPath, String manifest: _kDefaultAndroidManifestPath,
String resources, String resources,
String outputFile: _kDefaultOutputPath, String outputFile: _kDefaultOutputPath,
String target: '', String target,
String flxPath, String flxPath,
ApkKeystoreInfo keystore ApkKeystoreInfo keystore
}) async { }) async {
...@@ -399,10 +414,9 @@ Future<int> buildAndroid({ ...@@ -399,10 +414,9 @@ Future<int> buildAndroid({
resources = _kDefaultResourcesPath; resources = _kDefaultResourcesPath;
} }
BuildConfiguration config = configs.firstWhere( BuildConfiguration config = configs.firstWhere((BuildConfiguration bc) => bc.targetPlatform == platform);
(BuildConfiguration bc) => bc.targetPlatform == TargetPlatform.android_arm
);
_ApkComponents components = await _findApkComponents(config, enginePath, manifest, resources); _ApkComponents components = await _findApkComponents(config, enginePath, manifest, resources);
if (components == null) { if (components == null) {
printError('Failure building APK. Unable to find components.'); printError('Failure building APK. Unable to find components.');
return 1; return 1;
...@@ -416,36 +430,34 @@ Future<int> buildAndroid({ ...@@ -416,36 +430,34 @@ Future<int> buildAndroid({
printError('(Omit the --flx option to build the FLX automatically)'); printError('(Omit the --flx option to build the FLX automatically)');
return 1; return 1;
} }
return _buildApk(components, flxPath, keystore, outputFile);
return _buildApk(platform, components, flxPath, keystore, outputFile);
} else { } else {
// Find the path to the main Dart file; build the FLX. // Find the path to the main Dart file; build the FLX.
String mainPath = findMainDartFile(target); String mainPath = findMainDartFile(target);
String localBundlePath = await flx.buildFlx(toolchain, mainPath: mainPath); String localBundlePath = await flx.buildFlx(toolchain, mainPath: mainPath);
return _buildApk(components, localBundlePath, keystore, outputFile); return _buildApk(platform, components, localBundlePath, keystore, outputFile);
} }
} }
// TODO(mpcomplete): move this to Device? // TODO(mpcomplete): move this to Device?
/// This is currently Android specific. /// This is currently Android specific.
Future<int> buildAll( Future<int> buildForDevice(
List<Device> devices, Device device,
ApplicationPackageStore applicationPackages, ApplicationPackageStore applicationPackages,
Toolchain toolchain, Toolchain toolchain,
List<BuildConfiguration> configs, { List<BuildConfiguration> configs, {
String enginePath, String enginePath,
String target: '' String target: ''
}) async { }) async {
for (Device device in devices) { ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform);
ApplicationPackage package = applicationPackages.getPackageForPlatform(device.platform); if (package == null)
if (package == null) return 0;
continue;
// TODO(mpcomplete): Temporary hack. We only support the apk builder atm.
if (package != applicationPackages.android)
continue;
int result = await build(toolchain, configs, enginePath: enginePath, target: target); // TODO(mpcomplete): Temporary hack. We only support the apk builder atm.
if (package == applicationPackages.android) {
int result = await build(device.platform, toolchain, configs, enginePath: enginePath, target: target);
if (result != 0) if (result != 0)
return result; return result;
} }
...@@ -454,10 +466,11 @@ Future<int> buildAll( ...@@ -454,10 +466,11 @@ Future<int> buildAll(
} }
Future<int> build( Future<int> build(
TargetPlatform platform,
Toolchain toolchain, Toolchain toolchain,
List<BuildConfiguration> configs, { List<BuildConfiguration> configs, {
String enginePath, String enginePath,
String target: '' String target
}) async { }) async {
if (!FileSystemEntity.isFileSync(_kDefaultAndroidManifestPath)) { if (!FileSystemEntity.isFileSync(_kDefaultAndroidManifestPath)) {
printError('Cannot build APK. Missing $_kDefaultAndroidManifestPath.'); printError('Cannot build APK. Missing $_kDefaultAndroidManifestPath.');
...@@ -465,6 +478,7 @@ Future<int> build( ...@@ -465,6 +478,7 @@ Future<int> build(
} }
int result = await buildAndroid( int result = await buildAndroid(
platform,
toolchain: toolchain, toolchain: toolchain,
configs: configs, configs: configs,
enginePath: enginePath, enginePath: enginePath,
......
...@@ -245,8 +245,10 @@ Future<int> startApp(DriveCommand command) async { ...@@ -245,8 +245,10 @@ Future<int> startApp(DriveCommand command) async {
// TODO(devoncarew): We should remove the need to special case here. // TODO(devoncarew): We should remove the need to special case here.
if (command.device is AndroidDevice) { if (command.device is AndroidDevice) {
printTrace('Building an APK.'); printTrace('Building an APK.');
int result = await build_apk.build(command.toolchain, command.buildConfigurations, int result = await build_apk.build(
enginePath: command.runner.enginePath, target: command.target); command.device.platform, command.toolchain, command.buildConfigurations,
enginePath: command.runner.enginePath, target: command.target
);
if (result != 0) if (result != 0)
return result; return result;
......
...@@ -182,8 +182,8 @@ Future<int> startApp( ...@@ -182,8 +182,8 @@ Future<int> startApp(
if (install) { if (install) {
printTrace('Running build command.'); printTrace('Running build command.');
int result = await buildAll( int result = await buildForDevice(
<Device>[device], applicationPackages, toolchain, configs, device, applicationPackages, toolchain, configs,
enginePath: enginePath, enginePath: enginePath,
target: target target: target
); );
...@@ -232,15 +232,8 @@ Future<int> startApp( ...@@ -232,15 +232,8 @@ Future<int> startApp(
platformArgs: platformArgs platformArgs: platformArgs
); );
if (!result) { if (!result)
printError('Error running application on ${device.name}.'); printError('Error running application on ${device.name}.');
} else {
// If the user specified --start-paused (and the device supports it) then
// wait for the observatory port to become available before returning from
// `startApp()`.
if (startPaused && device.supportsStartPaused)
await delayUntilObservatoryAvailable('localhost', debugPort);
}
return result ? 0 : 2; return result ? 0 : 2;
} }
......
...@@ -99,7 +99,7 @@ class RunMojoCommand extends FlutterCommand { ...@@ -99,7 +99,7 @@ class RunMojoCommand extends FlutterCommand {
if (config == null || config.type == BuildType.prebuilt) { if (config == null || config.type == BuildType.prebuilt) {
TargetPlatform targetPlatform = argResults['android'] ? TargetPlatform.android_arm : TargetPlatform.linux_x64; TargetPlatform targetPlatform = argResults['android'] ? TargetPlatform.android_arm : TargetPlatform.linux_x64;
Artifact artifact = ArtifactStore.getArtifact(type: ArtifactType.mojo, targetPlatform: targetPlatform); Artifact artifact = ArtifactStore.getArtifact(type: ArtifactType.mojo, targetPlatform: targetPlatform);
flutterPath = _makePathAbsolute(await ArtifactStore.getPath(artifact)); flutterPath = _makePathAbsolute(ArtifactStore.getPath(artifact));
} else { } else {
String localPath = path.join(config.buildDir, 'flutter.mojo'); String localPath = path.join(config.buildDir, 'flutter.mojo');
flutterPath = _makePathAbsolute(localPath); flutterPath = _makePathAbsolute(localPath);
......
...@@ -49,7 +49,7 @@ class TestCommand extends FlutterCommand { ...@@ -49,7 +49,7 @@ class TestCommand extends FlutterCommand {
if (config.type == BuildType.prebuilt) { if (config.type == BuildType.prebuilt) {
Artifact artifact = ArtifactStore.getArtifact( Artifact artifact = ArtifactStore.getArtifact(
type: ArtifactType.shell, targetPlatform: config.targetPlatform); type: ArtifactType.shell, targetPlatform: config.targetPlatform);
return await ArtifactStore.getPath(artifact); return ArtifactStore.getPath(artifact);
} else { } else {
switch (config.targetPlatform) { switch (config.targetPlatform) {
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
......
...@@ -104,8 +104,8 @@ Future<int> setupXcodeProjectHarness(String flutterProjectPath) async { ...@@ -104,8 +104,8 @@ Future<int> setupXcodeProjectHarness(String flutterProjectPath) async {
targetPlatform: TargetPlatform.ios targetPlatform: TargetPlatform.ios
); );
String xcodeProjectPath = await ArtifactStore.getPath(xcodeProject); String xcodeProjectPath = ArtifactStore.getPath(xcodeProject);
List<int> archiveBytes = await new File(xcodeProjectPath).readAsBytes(); List<int> archiveBytes = new File(xcodeProjectPath).readAsBytesSync();
if (archiveBytes.isEmpty) { if (archiveBytes.isEmpty) {
printError('Error: No archive bytes received.'); printError('Error: No archive bytes received.');
......
...@@ -459,9 +459,9 @@ class IOSSimulator extends Device { ...@@ -459,9 +459,9 @@ class IOSSimulator extends Device {
ServiceProtocolDiscovery serviceProtocolDiscovery = ServiceProtocolDiscovery serviceProtocolDiscovery =
new ServiceProtocolDiscovery(logReader); new ServiceProtocolDiscovery(logReader);
// We take this future here but do not wait for completion until *after* // We take this future here but do not wait for completion until *after* we
// we start the application. // start the application.
Future<int> serviceProtocolPort = serviceProtocolDiscovery.nextPort(); Future<int> scrapeServicePort = serviceProtocolDiscovery.nextPort();
// Prepare launch arguments. // Prepare launch arguments.
List<String> args = <String>[ List<String> args = <String>[
...@@ -487,14 +487,23 @@ class IOSSimulator extends Device { ...@@ -487,14 +487,23 @@ class IOSSimulator extends Device {
return false; return false;
} }
// Wait for the service protocol port here. This will complete once // Wait for the service protocol port here. This will complete once the
// the device has printed "Observatory is listening on..." // device has printed "Observatory is listening on..."
int devicePort = await serviceProtocolPort; printTrace('Waiting for observatory port to be available...');
printTrace('service protocol port = $devicePort');
printTrace('Successfully started ${app.name} on $id.');
printStatus('Observatory listening on http://127.0.0.1:$devicePort');
return true; try {
int devicePort = await scrapeServicePort.timeout(new Duration(seconds: 12));
printTrace('service protocol port = $devicePort');
printStatus('Observatory listening on http://127.0.0.1:$devicePort');
return true;
} catch (error) {
if (error is TimeoutException)
printError('Timed out while waiting for a debug connection.');
else
printError('Error waiting for a debug connection: $error');
return false;
}
} }
bool _applicationIsInstalledAndRunning(ApplicationPackage app) { bool _applicationIsInstalledAndRunning(ApplicationPackage app) {
......
...@@ -167,8 +167,9 @@ class FlutterCommandRunner extends CommandRunner { ...@@ -167,8 +167,9 @@ class FlutterCommandRunner extends CommandRunner {
@override @override
Future<dynamic> run(Iterable<String> args) { Future<dynamic> run(Iterable<String> args) {
return super.run(args).then((dynamic result) { return super.run(args).then((dynamic result) {
logger.flush();
return result; return result;
}).whenComplete(() {
logger.flush();
}); });
} }
......
...@@ -36,7 +36,7 @@ class SnapshotCompiler { ...@@ -36,7 +36,7 @@ class SnapshotCompiler {
} }
} }
Future<String> _getCompilerPath(BuildConfiguration config) async { String _getCompilerPath(BuildConfiguration config) {
if (config.type != BuildType.prebuilt) { if (config.type != BuildType.prebuilt) {
String compilerPath = path.join(config.buildDir, 'clang_x64', 'sky_snapshot'); String compilerPath = path.join(config.buildDir, 'clang_x64', 'sky_snapshot');
if (FileSystemEntity.isFileSync(compilerPath)) if (FileSystemEntity.isFileSync(compilerPath))
...@@ -48,7 +48,7 @@ Future<String> _getCompilerPath(BuildConfiguration config) async { ...@@ -48,7 +48,7 @@ Future<String> _getCompilerPath(BuildConfiguration config) async {
} }
Artifact artifact = ArtifactStore.getArtifact( Artifact artifact = ArtifactStore.getArtifact(
type: ArtifactType.snapshot, hostPlatform: config.hostPlatform); type: ArtifactType.snapshot, hostPlatform: config.hostPlatform);
return await ArtifactStore.getPath(artifact); return ArtifactStore.getPath(artifact);
} }
class Toolchain { class Toolchain {
...@@ -58,7 +58,7 @@ class Toolchain { ...@@ -58,7 +58,7 @@ class Toolchain {
static Future<Toolchain> forConfigs(List<BuildConfiguration> configs) async { static Future<Toolchain> forConfigs(List<BuildConfiguration> configs) async {
for (BuildConfiguration config in configs) { for (BuildConfiguration config in configs) {
String compilerPath = await _getCompilerPath(config); String compilerPath = _getCompilerPath(config);
if (compilerPath != null) if (compilerPath != null)
return new Toolchain(compiler: new SnapshotCompiler(compilerPath)); return new Toolchain(compiler: new SnapshotCompiler(compilerPath));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment