Unverified Commit 598f2ab0 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Cleanups to resident runner and flutter device classes (#45673)

parent b39949ff
......@@ -645,7 +645,7 @@ abstract class DeviceLogReader {
/// Some logs can be obtained from a VM service stream.
/// Set this after the VM services are connected.
List<VMService> connectedVMServices;
VMService connectedVMService;
@override
String toString() => name;
......@@ -675,7 +675,7 @@ class NoOpDeviceLogReader implements DeviceLogReader {
int appPid;
@override
List<VMService> connectedVMServices;
VMService connectedVMService;
@override
Stream<String> get logLines => const Stream<String>.empty();
......
......@@ -578,33 +578,30 @@ class IOSDeviceLogReader extends DeviceLogReader {
String get name => device.name;
@override
List<VMService> get connectedVMServices => _connectedVMServices;
List<VMService> _connectedVMServices;
VMService get connectedVMService => _connectedVMService;
VMService _connectedVMService;
@override
set connectedVMServices(List<VMService> connectedVMServices) {
_listenToUnifiedLoggingEvents(connectedVMServices);
_connectedVMServices = connectedVMServices;
set connectedVMService(VMService connectedVmService) {
_listenToUnifiedLoggingEvents(connectedVmService);
_connectedVMService = connectedVmService;
}
static const int _minimumUniversalLoggingSdkVersion = 13;
Future<void> _listenToUnifiedLoggingEvents(List<VMService> vmServices) async {
Future<void> _listenToUnifiedLoggingEvents(VMService connectedVmService) async {
if (device.majorSdkVersion < _minimumUniversalLoggingSdkVersion) {
return;
}
for (VMService vmService in vmServices) {
// The VM service will not publish logging events unless the debug stream is being listened to.
// onDebugEvent listens to this stream as a side effect.
unawaited(vmService.onDebugEvent);
_loggingSubscriptions.add((await vmService.onStdoutEvent).listen((ServiceEvent event) {
final String logMessage = event.message;
if (logMessage.isNotEmpty) {
_linesController.add(logMessage);
}
}));
}
_connectedVMServices = connectedVMServices;
// The VM service will not publish logging events unless the debug stream is being listened to.
// onDebugEvent listens to this stream as a side effect.
unawaited(connectedVmService.onDebugEvent);
_loggingSubscriptions.add((await connectedVmService.onStdoutEvent).listen((ServiceEvent event) {
final String logMessage = event.message;
if (logMessage.isNotEmpty) {
_linesController.add(logMessage);
}
}));
}
void _listenToSysLog () {
......
......@@ -134,7 +134,7 @@ class FlutterDevice {
final Device device;
final ResidentCompiler generator;
Stream<Uri> observatoryUris;
List<VMService> vmServices;
VMService vmService;
DevFS devFS;
ApplicationPackage package;
List<String> fileSystemRoots;
......@@ -191,8 +191,8 @@ class FlutterDevice {
}
printTrace('Successfully connected to service protocol: $observatoryUri');
vmServices = <VMService>[service];
device.getLogReader(app: package).connectedVMServices = vmServices;
vmService = service;
device.getLogReader(app: package).connectedVMService = vmService;
completer.complete();
await subscription.cancel();
}, onError: (dynamic error) {
......@@ -208,37 +208,23 @@ class FlutterDevice {
}
Future<void> refreshViews() async {
if (vmServices == null || vmServices.isEmpty) {
return Future<void>.value(null);
if (vmService == null) {
return;
}
final List<Future<void>> futures = <Future<void>>[
for (VMService service in vmServices) service.vm.refreshViews(waitForViews: true),
];
await Future.wait(futures);
await vmService.vm.refreshViews(waitForViews: true);
}
List<FlutterView> get views {
if (vmServices == null) {
if (vmService == null || vmService.isClosed) {
return <FlutterView>[];
}
return vmServices
.where((VMService service) => !service.isClosed)
.expand<FlutterView>(
(VMService service) {
return viewFilter != null
? service.vm.allViewsWithName(viewFilter)
: service.vm.views;
},
)
.toList();
return (viewFilter != null
? vmService.vm.allViewsWithName(viewFilter)
: vmService.vm.views).toList();
}
Future<void> getVMs() async {
for (VMService service in vmServices) {
await service.getVM();
}
}
Future<void> getVMs() => vmService.getVM();
Future<void> exitApps() async {
if (!device.supportsFlutterExit) {
......@@ -249,7 +235,6 @@ class FlutterDevice {
if (flutterViews == null || flutterViews.isEmpty) {
return;
}
final List<Future<void>> futures = <Future<void>>[];
// If any of the flutter views are paused, we might not be able to
// cleanly exit since the service extension may not have been registered.
if (flutterViews.any((FlutterView view) {
......@@ -262,6 +247,7 @@ class FlutterDevice {
await device.stopApp(package);
return;
}
final List<Future<void>> futures = <Future<void>>[];
for (FlutterView view in flutterViews) {
if (view != null && view.uiIsolate != null) {
assert(!view.uiIsolate.pauseEvent.isPauseEvent);
......@@ -281,7 +267,7 @@ class FlutterDevice {
}) {
// One devFS per device. Shared by all running instances.
devFS = DevFS(
vmServices[0],
vmService,
fsName,
rootDirectory,
packagesFilePath: packagesFilePath,
......@@ -416,7 +402,7 @@ class FlutterDevice {
}
void initLogReader() {
device.getLogReader(app: package).appPid = vmServices.first.vm.pid;
device.getLogReader(app: package).appPid = vmService.vm.pid;
}
Future<int> runHot({
......@@ -736,7 +722,7 @@ abstract class ResidentRunner {
void writeVmserviceFile() {
if (debuggingOptions.vmserviceOutFile != null) {
try {
final String address = flutterDevices.first.vmServices.first.wsAddress.toString();
final String address = flutterDevices.first.vmService.wsAddress.toString();
final File vmserviceOutFile = fs.file(debuggingOptions.vmserviceOutFile);
vmserviceOutFile.createSync(recursive: true);
vmserviceOutFile.writeAsStringSync(address);
......@@ -940,15 +926,13 @@ abstract class ResidentRunner {
// Listen for service protocol connection to close.
for (FlutterDevice device in flutterDevices) {
for (VMService service in device.vmServices) {
// This hooks up callbacks for when the connection stops in the future.
// We don't want to wait for them. We don't handle errors in those callbacks'
// futures either because they just print to logger and is not critical.
unawaited(service.done.then<void>(
_serviceProtocolDone,
onError: _serviceProtocolError,
).whenComplete(_serviceDisconnected));
}
// This hooks up callbacks for when the connection stops in the future.
// We don't want to wait for them. We don't handle errors in those callbacks'
// futures either because they just print to logger and is not critical.
unawaited(device.vmService.done.then<void>(
_serviceProtocolDone,
onError: _serviceProtocolError,
).whenComplete(_serviceDisconnected));
}
}
......
......@@ -83,15 +83,15 @@ class ColdRunner extends ResidentRunner {
if (flutterDevices.first.observatoryUris != null) {
// For now, only support one debugger connection.
connectionInfoCompleter?.complete(DebugConnectionInfo(
httpUri: flutterDevices.first.vmServices.first.httpAddress,
wsUri: flutterDevices.first.vmServices.first.wsAddress,
httpUri: flutterDevices.first.vmService.httpAddress,
wsUri: flutterDevices.first.vmService.wsAddress,
));
}
printTrace('Application running.');
for (FlutterDevice device in flutterDevices) {
if (device.vmServices == null) {
if (device.vmService == null) {
continue;
}
device.initLogReader();
......@@ -102,10 +102,10 @@ class ColdRunner extends ResidentRunner {
if (traceStartup) {
// Only trace startup for the first device.
final FlutterDevice device = flutterDevices.first;
if (device.vmServices != null && device.vmServices.isNotEmpty) {
if (device.vmService != null) {
printStatus('Tracing startup on ${device.device.name}.');
await downloadStartupTrace(
device.vmServices.first,
device.vmService,
awaitFirstFrame: awaitFirstFrameWhenTracing,
);
}
......@@ -183,10 +183,9 @@ class ColdRunner extends ResidentRunner {
bool haveAnything = false;
for (FlutterDevice device in flutterDevices) {
final String dname = device.device.name;
if (device.vmServices != null) {
for (VMService vm in device.vmServices) {
printStatus('An Observatory debugger and profiler on $dname is available at: ${vm.httpAddress}');
}
if (device.vmService != null) {
printStatus('An Observatory debugger and profiler on $dname is '
'available at: ${device.vmService .httpAddress}');
}
}
if (supportsServiceProtocol) {
......@@ -212,7 +211,7 @@ class ColdRunner extends ResidentRunner {
Future<void> preExit() async {
for (FlutterDevice device in flutterDevices) {
// If we're running in release mode, stop the app using the device logic.
if (device.vmServices == null || device.vmServices.isEmpty) {
if (device.vmService == null) {
await device.device.stopApp(device.package);
}
}
......
......@@ -10,7 +10,6 @@ import 'package:meta/meta.dart';
import 'package:pool/pool.dart';
import 'base/async_guard.dart';
import 'base/common.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/logger.dart';
......@@ -180,8 +179,8 @@ class HotRunner extends ResidentRunner {
// Only handle one debugger connection.
connectionInfoCompleter.complete(
DebugConnectionInfo(
httpUri: flutterDevices.first.vmServices.first.httpAddress,
wsUri: flutterDevices.first.vmServices.first.wsAddress,
httpUri: flutterDevices.first.vmService.httpAddress,
wsUri: flutterDevices.first.vmService.wsAddress,
baseUri: baseUris.first.toString(),
),
);
......@@ -428,23 +427,18 @@ class HotRunner extends ResidentRunner {
continue;
}
// Reload the isolate.
final Completer<void> completer = Completer<void>();
futures.add(completer.future);
unawaited(view.uiIsolate.reload().then(
(ServiceObject _) {
final ServiceEvent pauseEvent = view.uiIsolate.pauseEvent;
if ((pauseEvent != null) && pauseEvent.isPauseEvent) {
// Resume the isolate so that it can be killed by the embedder.
return view.uiIsolate.resume();
}
return null;
},
).whenComplete(
() { completer.complete(null); },
));
futures.add(view.uiIsolate.reload().then((ServiceObject _) {
final ServiceEvent pauseEvent = view.uiIsolate.pauseEvent;
if ((pauseEvent != null) && pauseEvent.isPauseEvent) {
// Resume the isolate so that it can be killed by the embedder.
return view.uiIsolate.resume();
}
return null;
}));
}
}
await Future.wait(futures);
// We are now running from source.
_runningFromSnapshot = false;
await _launchFromDevFS(mainPath + '.dill');
......@@ -718,12 +712,10 @@ class HotRunner extends ResidentRunner {
// running from snapshot to running from uploaded files.
await device.resetAssetDirectory();
}
final Completer<DeviceReloadReport> completer = Completer<DeviceReloadReport>();
allReportsFutures.add(completer.future);
final List<Future<Map<String, dynamic>>> reportFutures = device.reloadSources(
entryPath, pause: pause,
);
unawaited(Future.wait(reportFutures).then(
allReportsFutures.add(Future.wait(reportFutures).then(
(List<Map<String, dynamic>> reports) async {
// TODO(aam): Investigate why we are validating only first reload report,
// which seems to be current behavior
......@@ -733,7 +725,7 @@ class HotRunner extends ResidentRunner {
await device.updateReloadStatus(
validateReloadReport(firstReport, printErrors: false),
);
completer.complete(DeviceReloadReport(device, reports));
return DeviceReloadReport(device, reports);
},
));
}
......@@ -795,13 +787,12 @@ class HotRunner extends ResidentRunner {
printTrace('Sending reload event to "${view.uiIsolate.name}"');
futuresViews.add(view.uiIsolate.reload());
}
final Completer<void> deviceCompleter = Completer<void>();
unawaited(Future.wait(futuresViews).whenComplete(() {
deviceCompleter.complete(device.refreshViews());
allDevices.add(Future.wait(futuresViews).whenComplete(() {
return device.refreshViews();
}));
allDevices.add(deviceCompleter.future);
}
await Future.wait(allDevices);
// We are now running from source.
_runningFromSnapshot = false;
// Check if any isolates are paused.
......@@ -851,7 +842,7 @@ class HotRunner extends ResidentRunner {
}
}(),
];
final Future<void> reassembleFuture = Future.wait<void>(futures).then<void>((List<void> values) { });
final Future<void> reassembleFuture = Future.wait<void>(futures);
await reassembleFuture.timeout(
const Duration(seconds: 2),
onTimeout: () async {
......@@ -987,9 +978,8 @@ class HotRunner extends ResidentRunner {
printStatus(message);
for (FlutterDevice device in flutterDevices) {
final String dname = device.device.name;
for (VMService vm in device.vmServices) {
printStatus('An Observatory debugger and profiler on $dname is available at: ${vm.httpAddress}');
}
printStatus('An Observatory debugger and profiler on $dname is '
'available at: ${device.vmService.httpAddress}');
}
final String quitMessage = _didAttach
? 'To detach, press "d"; to quit, press "q".'
......
......@@ -104,7 +104,7 @@ void main() {
.thenAnswer((Invocation invocation) async {
return testUri;
});
when(mockFlutterDevice.vmServices).thenReturn(<VMService>[mockVMService]);
when(mockFlutterDevice.vmService).thenReturn(mockVMService);
when(mockFlutterDevice.refreshViews()).thenAnswer((Invocation invocation) async { });
when(mockFlutterDevice.reloadSources(any, pause: anyNamed('pause'))).thenReturn(<Future<Map<String, dynamic>>>[
Future<Map<String, dynamic>>.value(<String, dynamic>{
......@@ -631,7 +631,7 @@ void main() {
);
await flutterDevice.connect();
verify(mockLogReader.connectedVMServices = <VMService>[ mockVMService ]);
verify(mockLogReader.connectedVMService = mockVMService);
}, overrides: <Type, Generator>{
VMServiceConnector: () => (Uri httpUri, {
ReloadSources reloadSources,
......
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