[fuchsia_reload] Find and attach to the first instance of the named app (#8830)
diff --git a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
index 31a8268..808d5a6 100644
--- a/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
+++ b/packages/flutter_tools/lib/src/commands/fuchsia_reload.dart
@@ -9,12 +9,14 @@
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/platform.dart';
+import '../cache.dart';
import '../device.dart';
import '../flx.dart' as flx;
import '../fuchsia/fuchsia_device.dart';
import '../globals.dart';
import '../run_hot.dart';
import '../runner/flutter_command.dart';
+import '../vmservice.dart';
// Usage:
// With e.g. flutter_gallery already running, a HotRunner can be attached to it
@@ -62,6 +64,8 @@
@override
Future<Null> runCommand() async {
+ Cache.releaseLockEarly();
+
_validateArguments();
// Find the network ports used on the device by VM service instances.
@@ -70,24 +74,57 @@
throwToolExit("Couldn't find any running Observatory instances.");
}
for (int port in servicePorts) {
- printStatus("Fuchsia service port: $port");
+ printTrace("Fuchsia service port: $port");
}
- // TODO(zra): Check that there are running VM services on the returned
+ // Check that there are running VM services on the returned
// ports, and find the Isolates that are running the target app.
+ final String isolateName = "$_projectName\$main";
+ final List<int> targetPorts = await _filterPorts(servicePorts, isolateName);
+ if (targetPorts.length == 0) {
+ throwToolExit("No VMs found running $_projectName");
+ }
+ for (int port in targetPorts) {
+ printTrace("Found $_projectName at $port");
+ }
// Set up a device and hot runner and attach the hot runner to the first
// vm service we found.
- final int firstPort = servicePorts[0];
- final FuchsiaDevice device = new FuchsiaDevice("$_address:$firstPort");
+ final int firstPort = targetPorts[0];
+ final String fullAddress = "$_address:$firstPort";
+ final FuchsiaDevice device = new FuchsiaDevice(fullAddress);
final HotRunner hotRunner = new HotRunner(
device,
debuggingOptions: new DebuggingOptions.enabled(getBuildMode()),
target: _target,
projectRootPath: _fuchsiaProjectPath,
packagesFilePath: _dotPackagesPath);
- final Uri observatoryUri = Uri.parse("http://$_address:$firstPort");
- await hotRunner.attach(observatoryUri);
+ final Uri observatoryUri = Uri.parse("http://$fullAddress");
+ printStatus("Connecting to $_projectName at $observatoryUri");
+ await hotRunner.attach(observatoryUri, isolateFilter: isolateName);
+ }
+
+ // Find ports where there is a view isolate with the given name
+ Future<List<int>> _filterPorts(List<int> ports, String isolateFilter) async {
+ final List<int> result = new List<int>();
+ for (int port in ports) {
+ final String addr = "http://$_address:$port";
+ final Uri uri = Uri.parse(addr);
+ final VMService vmService = VMService.connect(uri);
+ await vmService.getVM();
+ await vmService.waitForViews();
+ if (vmService.vm.firstView == null) {
+ printTrace("Found no views at $addr");
+ continue;
+ }
+ for (FlutterView v in vmService.vm.views) {
+ printTrace("At $addr, found view: ${v.uiIsolate.name}");
+ if (v.uiIsolate.name.indexOf(isolateFilter) == 0) {
+ result.add(port);
+ }
+ }
+ }
+ return result;
}
void _validateArguments() {
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index fbe0296..bd3b874 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -209,7 +209,7 @@
_loggingSubscription = null;
}
- Future<Null> connectToServiceProtocol(Uri uri) async {
+ Future<Null> connectToServiceProtocol(Uri uri, {String isolateFilter}) async {
if (!debuggingOptions.debuggingEnabled) {
return new Future<Null>.error('Error the service protocol is not enabled.');
}
@@ -217,15 +217,11 @@
printTrace('Connected to service protocol: $uri');
await vmService.getVM();
- // Refresh the view list.
- await vmService.vm.refreshViews();
- for (int i = 0; vmService.vm.mainView == null && i < 5; i++) {
- // If the VM doesn't yet have a view, wait for one to show up.
- printTrace('Waiting for Flutter view');
- await new Future<Null>.delayed(const Duration(seconds: 1));
- await vmService.vm.refreshViews();
- }
- currentView = vmService.vm.mainView;
+ // Refresh the view list, and wait a bit for the list to populate.
+ await vmService.waitForViews();
+ currentView = (isolateFilter == null)
+ ? vmService.vm.firstView
+ : vmService.vm.firstViewWithName(isolateFilter);
if (currentView == null)
throwToolExit('No Flutter view is available');
diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart
index b82eeb0..ab2587c 100644
--- a/packages/flutter_tools/lib/src/run_cold.dart
+++ b/packages/flutter_tools/lib/src/run_cold.dart
@@ -115,7 +115,7 @@
if (vmService != null) {
await vmService.vm.refreshViews();
- printTrace('Connected to ${vmService.vm.mainView}\.');
+ printTrace('Connected to ${vmService.vm.firstView}\.');
}
if (vmService != null && traceStartup) {
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 183491a..27379c5 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -90,10 +90,12 @@
Future<int> attach(Uri observatoryUri, {
Completer<DebugConnectionInfo> connectionInfoCompleter,
Completer<Null> appStartedCompleter,
+ String isolateFilter,
}) async {
_observatoryUri = observatoryUri;
try {
- await connectToServiceProtocol(_observatoryUri);
+ await connectToServiceProtocol(
+ _observatoryUri, isolateFilter: isolateFilter);
} catch (error) {
printError('Error connecting to the service protocol: $error');
return 2;
@@ -121,7 +123,7 @@
}
await vmService.vm.refreshViews();
- printTrace('Connected to ${vmService.vm.mainView}.');
+ printTrace('Connected to $currentView.');
if (stayResident) {
setupTerminal();
@@ -302,7 +304,7 @@
Future<Null> _launchInView(Uri entryUri,
Uri packagesUri,
Uri assetsDirectoryUri) async {
- final FlutterView view = vmService.vm.mainView;
+ final FlutterView view = currentView;
return view.runFromSource(entryUri, packagesUri, assetsDirectoryUri);
}
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart
index 8a5b844..bbbee28 100644
--- a/packages/flutter_tools/lib/src/vmservice.dart
+++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -170,6 +170,16 @@
Future<VM> getVM() {
return _vm.reload();
}
+
+ Future<Null> waitForViews({int attempts = 5, int attemptSeconds = 1}) async {
+ await vm.refreshViews();
+ for (int i = 0; (vm.firstView == null) && (i < attempts); i++) {
+ // If the VM doesn't yet have a view, wait for one to show up.
+ printTrace('Waiting for Flutter view');
+ await new Future<Null>.delayed(new Duration(seconds: attemptSeconds));
+ await vm.refreshViews();
+ }
+ }
}
/// An error that is thrown when constructing/updating a service object.
@@ -743,9 +753,20 @@
await vmService.vm.invokeRpc('_flutter.listViews', timeout: kLongRequestTimeout);
}
- FlutterView get mainView {
+ Iterable<FlutterView> get views => _viewCache.values;
+
+ FlutterView get firstView {
return _viewCache.values.isEmpty ? null : _viewCache.values.first;
}
+
+ FlutterView firstViewWithName(String isolateFilter) {
+ if (_viewCache.values.isEmpty) {
+ return null;
+ }
+ return _viewCache.values.firstWhere(
+ (FlutterView v) => v.uiIsolate.name.contains(isolateFilter),
+ orElse: () => null);
+ }
}
/// An isolate running inside the VM. Instances of the Isolate class are always