Commit 3a012b32 authored by John McCutchan's avatar John McCutchan Committed by GitHub

vmservice redux (#5437)

parent 53dd5dbd
...@@ -143,7 +143,7 @@ class RunCommand extends RunCommandBase { ...@@ -143,7 +143,7 @@ class RunCommand extends RunCommandBase {
return 1; return 1;
} }
} else { } else {
if (argResults['control-pipe']) { if (argResults['control-pipe'] != null) {
printError('--control-pipe requires --hot'); printError('--control-pipe requires --hot');
return 1; return 1;
} }
......
...@@ -95,40 +95,39 @@ class TraceCommand extends FlutterCommand { ...@@ -95,40 +95,39 @@ class TraceCommand extends FlutterCommand {
} }
class Tracing { class Tracing {
Tracing(this.observatory); Tracing(this.vmService);
static Future<Tracing> connect(int port) { static Future<Tracing> connect(int port) {
return VMService.connect(port).then((VMService observatory) => new Tracing(observatory)); return VMService.connect(port).then((VMService observatory) => new Tracing(observatory));
} }
final VMService observatory; final VMService vmService;
Future<Null> startTracing() async { Future<Null> startTracing() async {
await observatory.setVMTimelineFlags(<String>['Compiler', 'Dart', 'Embedder', 'GC']); await vmService.vm.setVMTimelineFlags(<String>['Compiler', 'Dart', 'Embedder', 'GC']);
await observatory.clearVMTimeline(); await vmService.vm.clearVMTimeline();
} }
/// Stops tracing; optionally wait for first frame. /// Stops tracing; optionally wait for first frame.
Future<Map<String, dynamic>> stopTracingAndDownloadTimeline({ Future<Map<String, dynamic>> stopTracingAndDownloadTimeline({
bool waitForFirstFrame: false bool waitForFirstFrame: false
}) async { }) async {
Response timeline; Map<String, dynamic> timeline;
if (!waitForFirstFrame) { if (!waitForFirstFrame) {
// Stop tracing immediately and get the timeline // Stop tracing immediately and get the timeline
await observatory.setVMTimelineFlags(<String>[]); await vmService.vm.setVMTimelineFlags(<String>[]);
timeline = await observatory.getVMTimeline(); timeline = await vmService.vm.getVMTimeline();
} else { } else {
Completer<Null> whenFirstFrameRendered = new Completer<Null>(); Completer<Null> whenFirstFrameRendered = new Completer<Null>();
observatory.onTimelineEvent.listen((Event timelineEvent) { vmService.onTimelineEvent.listen((ServiceEvent timelineEvent) {
List<Map<String, dynamic>> events = timelineEvent['timelineEvents']; List<Map<String, dynamic>> events = timelineEvent.timelineEvents;
for (Map<String, dynamic> event in events) { for (Map<String, dynamic> event in events) {
if (event['name'] == kFirstUsefulFrameEventName) if (event['name'] == kFirstUsefulFrameEventName)
whenFirstFrameRendered.complete(); whenFirstFrameRendered.complete();
} }
}); });
await observatory.streamListen('Timeline');
await whenFirstFrameRendered.future.timeout( await whenFirstFrameRendered.future.timeout(
const Duration(seconds: 10), const Duration(seconds: 10),
...@@ -142,12 +141,12 @@ class Tracing { ...@@ -142,12 +141,12 @@ class Tracing {
} }
); );
timeline = await observatory.getVMTimeline(); timeline = await vmService.vm.getVMTimeline();
await observatory.setVMTimelineFlags(<String>[]); await vmService.vm.setVMTimelineFlags(<String>[]);
} }
return timeline.response; return timeline;
} }
} }
......
...@@ -106,22 +106,22 @@ abstract class DevFSOperations { ...@@ -106,22 +106,22 @@ abstract class DevFSOperations {
} }
/// An implementation of [DevFSOperations] that speaks to the /// An implementation of [DevFSOperations] that speaks to the
/// service protocol. /// vm service.
class ServiceProtocolDevFSOperations implements DevFSOperations { class ServiceProtocolDevFSOperations implements DevFSOperations {
final VMService serviceProtocol; final VMService vmService;
ServiceProtocolDevFSOperations(this.serviceProtocol); ServiceProtocolDevFSOperations(this.vmService);
@override @override
Future<Uri> create(String fsName) async { Future<Uri> create(String fsName) async {
Response response = await serviceProtocol.createDevFS(fsName); Map<String, dynamic> response = await vmService.vm.createDevFS(fsName);
return Uri.parse(response['uri']); return Uri.parse(response['uri']);
} }
@override @override
Future<dynamic> destroy(String fsName) async { Future<dynamic> destroy(String fsName) async {
await serviceProtocol.sendRequest('_deleteDevFS', await vmService.vm.invokeRpcRaw('_deleteDevFS',
<String, dynamic> { 'fsName': fsName }); <String, dynamic> { 'fsName': fsName });
} }
@override @override
...@@ -134,12 +134,12 @@ class ServiceProtocolDevFSOperations implements DevFSOperations { ...@@ -134,12 +134,12 @@ class ServiceProtocolDevFSOperations implements DevFSOperations {
} }
String fileContents = BASE64.encode(bytes); String fileContents = BASE64.encode(bytes);
try { try {
return await serviceProtocol.sendRequest('_writeDevFSFile', return await vmService.vm.invokeRpcRaw('_writeDevFSFile',
<String, dynamic> { <String, dynamic> {
'fsName': fsName, 'fsName': fsName,
'path': entry.devicePath, 'path': entry.devicePath,
'fileContents': fileContents 'fileContents': fileContents
}); });
} catch (e) { } catch (e) {
printTrace('DevFS: Failed to write ${entry.devicePath}: $e'); printTrace('DevFS: Failed to write ${entry.devicePath}: $e');
} }
...@@ -155,12 +155,12 @@ class ServiceProtocolDevFSOperations implements DevFSOperations { ...@@ -155,12 +155,12 @@ class ServiceProtocolDevFSOperations implements DevFSOperations {
String devicePath, String devicePath,
String contents) async { String contents) async {
String fileContents = BASE64.encode(UTF8.encode(contents)); String fileContents = BASE64.encode(UTF8.encode(contents));
return await serviceProtocol.sendRequest('_writeDevFSFile', return await vmService.vm.invokeRpcRaw('_writeDevFSFile',
<String, dynamic> { <String, dynamic> {
'fsName': fsName, 'fsName': fsName,
'path': devicePath, 'path': devicePath,
'fileContents': fileContents 'fileContents': fileContents
}); });
} }
} }
...@@ -251,7 +251,8 @@ class DevFS { ...@@ -251,7 +251,8 @@ class DevFS {
final Set<DevFSEntry> _deletedEntries = new Set<DevFSEntry>(); final Set<DevFSEntry> _deletedEntries = new Set<DevFSEntry>();
final Set<DevFSEntry> dirtyAssetEntries = new Set<DevFSEntry>(); final Set<DevFSEntry> dirtyAssetEntries = new Set<DevFSEntry>();
final List<Future<Response>> _pendingOperations = new List<Future<Response>>(); final List<Future<Map<String, dynamic>>> _pendingOperations =
new List<Future<Map<String, dynamic>>>();
int _bytes = 0; int _bytes = 0;
int get bytes => _bytes; int get bytes => _bytes;
...@@ -358,7 +359,8 @@ class DevFS { ...@@ -358,7 +359,8 @@ class DevFS {
if (_deletedEntries.length > 0) { if (_deletedEntries.length > 0) {
status = logger.startProgress('Removing deleted files...'); status = logger.startProgress('Removing deleted files...');
for (DevFSEntry entry in _deletedEntries) { for (DevFSEntry entry in _deletedEntries) {
Future<Response> operation = _operations.deleteFile(fsName, entry); Future<Map<String, dynamic>> operation =
_operations.deleteFile(fsName, entry);
if (operation != null) if (operation != null)
_pendingOperations.add(operation); _pendingOperations.add(operation);
} }
...@@ -382,7 +384,8 @@ class DevFS { ...@@ -382,7 +384,8 @@ class DevFS {
} else { } else {
// Make service protocol requests for each. // Make service protocol requests for each.
for (DevFSEntry entry in _dirtyEntries) { for (DevFSEntry entry in _dirtyEntries) {
Future<Response> operation = _operations.writeFile(fsName, entry); Future<Map<String, dynamic>> operation =
_operations.writeFile(fsName, entry);
if (operation != null) if (operation != null)
_pendingOperations.add(operation); _pendingOperations.add(operation);
} }
......
...@@ -23,7 +23,6 @@ import 'devfs.dart'; ...@@ -23,7 +23,6 @@ import 'devfs.dart';
import 'vmservice.dart'; import 'vmservice.dart';
import 'resident_runner.dart'; import 'resident_runner.dart';
import 'toolchain.dart'; import 'toolchain.dart';
import 'view.dart';
String getDevFSLoaderScript() { String getDevFSLoaderScript() {
return path.absolute(path.join(Cache.flutterRoot, return path.absolute(path.join(Cache.flutterRoot,
...@@ -80,18 +79,18 @@ class StartupDependencySetBuilder { ...@@ -80,18 +79,18 @@ class StartupDependencySetBuilder {
class FirstFrameTimer { class FirstFrameTimer {
FirstFrameTimer(this.serviceProtocol); FirstFrameTimer(this.vmService);
void start() { void start() {
stopwatch.reset(); stopwatch.reset();
stopwatch.start(); stopwatch.start();
_subscription = serviceProtocol.onExtensionEvent.listen(_onExtensionEvent); _subscription = vmService.onExtensionEvent.listen(_onExtensionEvent);
} }
/// Returns a Future which completes after the first frame event is received. /// Returns a Future which completes after the first frame event is received.
Future<Null> firstFrame() => _completer.future; Future<Null> firstFrame() => _completer.future;
void _onExtensionEvent(Event event) { void _onExtensionEvent(ServiceEvent event) {
if (event.extensionKind == 'Flutter.FirstFrame') if (event.extensionKind == 'Flutter.FirstFrame')
_stop(); _stop();
} }
...@@ -108,10 +107,10 @@ class FirstFrameTimer { ...@@ -108,10 +107,10 @@ class FirstFrameTimer {
return stopwatch.elapsed; return stopwatch.elapsed;
} }
final VMService serviceProtocol; final VMService vmService;
final Stopwatch stopwatch = new Stopwatch(); final Stopwatch stopwatch = new Stopwatch();
final Completer<Null> _completer = new Completer<Null>(); final Completer<Null> _completer = new Completer<Null>();
StreamSubscription<Event> _subscription; StreamSubscription<ServiceEvent> _subscription;
} }
class HotRunner extends ResidentRunner { class HotRunner extends ResidentRunner {
...@@ -294,8 +293,8 @@ class HotRunner extends ResidentRunner { ...@@ -294,8 +293,8 @@ class HotRunner extends ResidentRunner {
return 3; return 3;
} }
await viewManager.refresh(); await vmService.vm.refreshViews();
printStatus('Connected to view \'${viewManager.mainView}\'.'); printStatus('Connected to view \'${vmService.vm.mainView}\'.');
printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...'); printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...');
_loaderShowMessage('Launching...'); _loaderShowMessage('Launching...');
...@@ -332,13 +331,13 @@ class HotRunner extends ResidentRunner { ...@@ -332,13 +331,13 @@ class HotRunner extends ResidentRunner {
} }
void _loaderShowMessage(String message, { int progress, int max }) { void _loaderShowMessage(String message, { int progress, int max }) {
serviceProtocol.flutterLoaderShowMessage(serviceProtocol.firstIsolateId, message); currentView.uiIsolate.flutterLoaderShowMessage(message);
if (progress != null) { if (progress != null) {
serviceProtocol.flutterLoaderSetProgress(serviceProtocol.firstIsolateId, progress.toDouble()); currentView.uiIsolate.flutterLoaderSetProgress(progress.toDouble());
serviceProtocol.flutterLoaderSetProgressMax(serviceProtocol.firstIsolateId, max?.toDouble() ?? 0.0); currentView.uiIsolate.flutterLoaderSetProgressMax(max?.toDouble() ?? 0.0);
} else { } else {
serviceProtocol.flutterLoaderSetProgress(serviceProtocol.firstIsolateId, 0.0); currentView.uiIsolate.flutterLoaderSetProgress(0.0);
serviceProtocol.flutterLoaderSetProgressMax(serviceProtocol.firstIsolateId, -1.0); currentView.uiIsolate.flutterLoaderSetProgressMax(-1.0);
} }
} }
...@@ -346,7 +345,7 @@ class HotRunner extends ResidentRunner { ...@@ -346,7 +345,7 @@ class HotRunner extends ResidentRunner {
Future<Uri> _initDevFS() { Future<Uri> _initDevFS() {
String fsName = path.basename(_projectRootPath); String fsName = path.basename(_projectRootPath);
_devFS = new DevFS(serviceProtocol, _devFS = new DevFS(vmService,
fsName, fsName,
new Directory(_projectRootPath)); new Directory(_projectRootPath));
return _devFS.create(); return _devFS.create();
...@@ -377,11 +376,10 @@ class HotRunner extends ResidentRunner { ...@@ -377,11 +376,10 @@ class HotRunner extends ResidentRunner {
Future<Null> _evictDirtyAssets() async { Future<Null> _evictDirtyAssets() async {
if (_devFS.dirtyAssetEntries.length == 0) if (_devFS.dirtyAssetEntries.length == 0)
return; return;
if (serviceProtocol.firstIsolateId == null) if (currentView.uiIsolate == null)
throw 'Application isolate not found'; throw 'Application isolate not found';
for (DevFSEntry entry in _devFS.dirtyAssetEntries) { for (DevFSEntry entry in _devFS.dirtyAssetEntries) {
await serviceProtocol.flutterEvictAsset(serviceProtocol.firstIsolateId, await currentView.uiIsolate.flutterEvictAsset(entry.assetPath);
entry.assetPath);
} }
} }
...@@ -400,7 +398,7 @@ class HotRunner extends ResidentRunner { ...@@ -400,7 +398,7 @@ class HotRunner extends ResidentRunner {
Future<Null> _launchInView(String entryPath, Future<Null> _launchInView(String entryPath,
String packagesPath, String packagesPath,
String assetsDirectoryPath) async { String assetsDirectoryPath) async {
FlutterView view = viewManager.mainView; FlutterView view = vmService.vm.mainView;
return view.runFromSource(entryPath, packagesPath, assetsDirectoryPath); return view.runFromSource(entryPath, packagesPath, assetsDirectoryPath);
} }
...@@ -419,7 +417,7 @@ class HotRunner extends ResidentRunner { ...@@ -419,7 +417,7 @@ class HotRunner extends ResidentRunner {
} }
Future<Null> _restartFromSources() async { Future<Null> _restartFromSources() async {
FirstFrameTimer firstFrameTimer = new FirstFrameTimer(serviceProtocol); FirstFrameTimer firstFrameTimer = new FirstFrameTimer(vmService);
firstFrameTimer.start(); firstFrameTimer.start();
await _updateDevFS(); await _updateDevFS();
await _launchFromDevFS(_package, _mainPath); await _launchFromDevFS(_package, _mainPath);
...@@ -459,16 +457,16 @@ class HotRunner extends ResidentRunner { ...@@ -459,16 +457,16 @@ class HotRunner extends ResidentRunner {
} }
Future<bool> _reloadSources() async { Future<bool> _reloadSources() async {
if (serviceProtocol.firstIsolateId == null) if (currentView.uiIsolate == null)
throw 'Application isolate not found'; throw 'Application isolate not found';
FirstFrameTimer firstFrameTimer = new FirstFrameTimer(serviceProtocol); FirstFrameTimer firstFrameTimer = new FirstFrameTimer(vmService);
firstFrameTimer.start(); firstFrameTimer.start();
if (_devFS != null) if (_devFS != null)
await _updateDevFS(); await _updateDevFS();
Status reloadStatus = logger.startProgress('Performing hot reload...'); Status reloadStatus = logger.startProgress('Performing hot reload...');
try { try {
Map<String, dynamic> reloadReport = Map<String, dynamic> reloadReport =
await serviceProtocol.reloadSources(serviceProtocol.firstIsolateId); await currentView.uiIsolate.reloadSources();
reloadStatus.stop(showElapsedTime: true); reloadStatus.stop(showElapsedTime: true);
if (!_printReloadReport(reloadReport)) { if (!_printReloadReport(reloadReport)) {
// Reload failed. // Reload failed.
...@@ -477,16 +475,16 @@ class HotRunner extends ResidentRunner { ...@@ -477,16 +475,16 @@ class HotRunner extends ResidentRunner {
} else { } else {
flutterUsage.sendEvent('hot', 'reload'); flutterUsage.sendEvent('hot', 'reload');
} }
} catch (errorMessage) { } catch (errorMessage, st) {
reloadStatus.stop(showElapsedTime: true); reloadStatus.stop(showElapsedTime: true);
printError('Hot reload failed:\n$errorMessage'); printError('Hot reload failed:\n$errorMessage\n$st');
return false; return false;
} }
await _evictDirtyAssets(); await _evictDirtyAssets();
Status reassembleStatus = Status reassembleStatus =
logger.startProgress('Reassembling application...'); logger.startProgress('Reassembling application...');
try { try {
await serviceProtocol.flutterReassemble(serviceProtocol.firstIsolateId); await currentView.uiIsolate.flutterReassemble();
} catch (_) { } catch (_) {
reassembleStatus.stop(showElapsedTime: true); reassembleStatus.stop(showElapsedTime: true);
printError('Reassembling application failed.'); printError('Reassembling application failed.');
......
...@@ -12,7 +12,6 @@ import 'build_info.dart'; ...@@ -12,7 +12,6 @@ import 'build_info.dart';
import 'device.dart'; import 'device.dart';
import 'globals.dart'; import 'globals.dart';
import 'vmservice.dart'; import 'vmservice.dart';
import 'view.dart';
// Shared code between different resident application runners. // Shared code between different resident application runners.
abstract class ResidentRunner { abstract class ResidentRunner {
...@@ -28,8 +27,8 @@ abstract class ResidentRunner { ...@@ -28,8 +27,8 @@ abstract class ResidentRunner {
final bool usesTerminalUI; final bool usesTerminalUI;
final Completer<int> _finished = new Completer<int>(); final Completer<int> _finished = new Completer<int>();
VMService serviceProtocol; VMService vmService;
ViewManager viewManager; FlutterView currentView;
StreamSubscription<String> _loggingSubscription; StreamSubscription<String> _loggingSubscription;
/// Start the app and keep the process running during its lifetime. /// Start the app and keep the process running during its lifetime.
...@@ -48,11 +47,11 @@ abstract class ResidentRunner { ...@@ -48,11 +47,11 @@ abstract class ResidentRunner {
} }
Future<Null> _debugDumpApp() async { Future<Null> _debugDumpApp() async {
await serviceProtocol.flutterDebugDumpApp(serviceProtocol.firstIsolateId); await currentView.uiIsolate.flutterDebugDumpApp();
} }
Future<Null> _debugDumpRenderTree() async { Future<Null> _debugDumpRenderTree() async {
await serviceProtocol.flutterDebugDumpRenderTree(serviceProtocol.firstIsolateId); await currentView.uiIsolate.flutterDebugDumpRenderTree();
} }
void registerSignalHandlers() { void registerSignalHandlers() {
...@@ -90,22 +89,23 @@ abstract class ResidentRunner { ...@@ -90,22 +89,23 @@ abstract class ResidentRunner {
if (!debuggingOptions.debuggingEnabled) { if (!debuggingOptions.debuggingEnabled) {
return new Future<Null>.error('Error the service protocol is not enabled.'); return new Future<Null>.error('Error the service protocol is not enabled.');
} }
serviceProtocol = await VMService.connect(port); vmService = await VMService.connect(port);
printTrace('Connected to service protocol on port $port'); printTrace('Connected to service protocol on port $port');
serviceProtocol.populateIsolateInfo(); await vmService.getVM();
serviceProtocol.onExtensionEvent.listen((Event event) { vmService.onExtensionEvent.listen((ServiceEvent event) {
printTrace(event.toString()); printTrace(event.toString());
}); });
serviceProtocol.onIsolateEvent.listen((Event event) { vmService.onIsolateEvent.listen((ServiceEvent event) {
printTrace(event.toString()); printTrace(event.toString());
}); });
// Setup view manager and refresh the view list. // Refresh the view list.
viewManager = new ViewManager(serviceProtocol); await vmService.vm.refreshViews();
await viewManager.refresh(); currentView = vmService.vm.mainView;
assert(currentView != null);
// Listen for service protocol connection to close. // Listen for service protocol connection to close.
serviceProtocol.done.whenComplete(() { vmService.done.whenComplete(() {
appFinished(); appFinished();
}); });
} }
...@@ -175,9 +175,10 @@ abstract class ResidentRunner { ...@@ -175,9 +175,10 @@ abstract class ResidentRunner {
Future<Null> preStop() async { } Future<Null> preStop() async { }
Future<Null> stopApp() async { Future<Null> stopApp() async {
if (serviceProtocol != null && !serviceProtocol.isClosed) { if (vmService != null && !vmService.isClosed) {
if (serviceProtocol.isolates.isNotEmpty) { if ((currentView != null) && (currentView.uiIsolate != null)) {
serviceProtocol.flutterExit(serviceProtocol.firstIsolateId); // TODO(johnmccutchan): Wait for the exit command to complete.
currentView.uiIsolate.flutterExit();
await new Future<Null>.delayed(new Duration(milliseconds: 100)); await new Future<Null>.delayed(new Duration(milliseconds: 100));
} }
} }
......
...@@ -59,17 +59,17 @@ class RunAndStayResident extends ResidentRunner { ...@@ -59,17 +59,17 @@ class RunAndStayResident extends ResidentRunner {
@override @override
Future<bool> restart({ bool fullRestart: false }) async { Future<bool> restart({ bool fullRestart: false }) async {
if (serviceProtocol == null) { if (vmService == null) {
printError('Debugging is not enabled.'); printError('Debugging is not enabled.');
return false; return false;
} else { } else {
Status status = logger.startProgress('Re-starting application...'); Status status = logger.startProgress('Re-starting application...');
Future<Event> extensionAddedEvent; Future<ServiceEvent> extensionAddedEvent;
if (device.restartSendsFrameworkInitEvent) { if (device.restartSendsFrameworkInitEvent) {
extensionAddedEvent = serviceProtocol.onExtensionEvent extensionAddedEvent = vmService.onExtensionEvent
.where((Event event) => event.extensionKind == 'Flutter.FrameworkInitialization') .where((ServiceEvent event) => event.extensionKind == 'Flutter.FrameworkInitialization')
.first; .first;
} }
...@@ -77,7 +77,7 @@ class RunAndStayResident extends ResidentRunner { ...@@ -77,7 +77,7 @@ class RunAndStayResident extends ResidentRunner {
_package, _package,
_result, _result,
mainPath: _mainPath, mainPath: _mainPath,
observatory: serviceProtocol observatory: vmService
); );
status.stop(showElapsedTime: true); status.stop(showElapsedTime: true);
...@@ -178,16 +178,20 @@ class RunAndStayResident extends ResidentRunner { ...@@ -178,16 +178,20 @@ class RunAndStayResident extends ResidentRunner {
if (debuggingOptions.debuggingEnabled) { if (debuggingOptions.debuggingEnabled) {
await connectToServiceProtocol(_result.observatoryPort); await connectToServiceProtocol(_result.observatoryPort);
if (benchmark) if (benchmark) {
await serviceProtocol.waitFirstIsolate; await vmService.getVM();
}
} }
printStatus('Application running.'); printStatus('Application running.');
if (serviceProtocol != null && traceStartup) { await vmService.vm.refreshViews();
printStatus('Connected to view \'${vmService.vm.mainView}\'.');
if (vmService != null && traceStartup) {
printStatus('Downloading startup trace info...'); printStatus('Downloading startup trace info...');
try { try {
await downloadStartupTrace(serviceProtocol); await downloadStartupTrace(vmService);
} catch(error) { } catch(error) {
printError(error); printError(error);
return 2; return 2;
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'globals.dart';
import 'vmservice.dart';
/// Peered to a Android/iOS FlutterView widget on a device.
class FlutterView {
FlutterView(this.viewId, this.viewManager);
final String viewId;
final ViewManager viewManager;
String _uiIsolateId;
String get uiIsolateId => _uiIsolateId;
Future<Null> runFromSource(String entryPath,
String packagesPath,
String assetsDirectoryPath) async {
return viewManager._runFromSource(this,
entryPath,
packagesPath,
assetsDirectoryPath);
}
@override
String toString() => viewId;
@override
bool operator ==(FlutterView other) {
return other.viewId == viewId;
}
@override
int get hashCode => viewId.hashCode;
}
/// Manager of FlutterViews.
class ViewManager {
ViewManager(this.serviceProtocol);
final VMService serviceProtocol;
Future<Null> refresh() async {
List<Map<String, String>> viewList = await serviceProtocol.getViewList();
for (Map<String, String> viewDescription in viewList) {
FlutterView view = new FlutterView(viewDescription['id'], this);
if (!views.contains(view)) {
// Canonicalize views against the view set.
views.add(view);
}
}
}
// TODO(johnmccutchan): Report errors when running failed.
Future<Null> _runFromSource(FlutterView view,
String entryPath,
String packagesPath,
String assetsDirectoryPath) async {
final String viewId = await serviceProtocol.getFirstViewId();
// When this completer completes the isolate is running.
final Completer<Null> completer = new Completer<Null>();
final StreamSubscription<Event> subscription =
serviceProtocol.onIsolateEvent.listen((Event event) {
// TODO(johnmccutchan): Listen to the debug stream and catch initial
// launch errors.
if (event.kind == 'IsolateRunnable') {
printTrace('Isolate is runnable.');
completer.complete(null);
}
});
await serviceProtocol.runInView(viewId,
entryPath,
packagesPath,
assetsDirectoryPath);
await completer.future;
await subscription.cancel();
}
// TODO(johnmccutchan): Remove this accessor and make the runner multi-view
// aware.
FlutterView get mainView {
return views.first;
}
final Set<FlutterView> views = new Set<FlutterView>();
}
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