Unverified Commit b91aedb1 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

Fix StateError during hot reload when no Dart isolates found (#130537)

Fixes https://github.com/flutter/flutter/issues/116262
parent f5a5581f
......@@ -91,7 +91,7 @@ class HotRunner extends ResidentRunner {
this.multidexEnabled = false,
super.devtoolsHandler,
StopwatchFactory stopwatchFactory = const StopwatchFactory(),
ReloadSourcesHelper reloadSourcesHelper = _defaultReloadSourcesHelper,
ReloadSourcesHelper reloadSourcesHelper = defaultReloadSourcesHelper,
ReassembleHelper reassembleHelper = _defaultReassembleHelper,
}) : _stopwatchFactory = stopwatchFactory,
_reloadSourcesHelper = reloadSourcesHelper,
......@@ -1174,7 +1174,8 @@ typedef ReloadSourcesHelper = Future<OperationResult> Function(
String? reason,
);
Future<OperationResult> _defaultReloadSourcesHelper(
@visibleForTesting
Future<OperationResult> defaultReloadSourcesHelper(
HotRunner hotRunner,
List<FlutterDevice?> flutterDevices,
bool? pause,
......@@ -1186,7 +1187,7 @@ Future<OperationResult> _defaultReloadSourcesHelper(
) async {
final Stopwatch vmReloadTimer = Stopwatch()..start();
const String entryPath = 'main.dart.incremental.dill';
final List<Future<DeviceReloadReport>> allReportsFutures = <Future<DeviceReloadReport>>[];
final List<Future<DeviceReloadReport?>> allReportsFutures = <Future<DeviceReloadReport?>>[];
for (final FlutterDevice? device in flutterDevices) {
final List<Future<vm_service.ReloadReport>> reportFutures = await _reloadDeviceSources(
......@@ -1194,10 +1195,13 @@ Future<OperationResult> _defaultReloadSourcesHelper(
entryPath,
pause: pause,
);
allReportsFutures.add(Future.wait(reportFutures).then(
allReportsFutures.add(Future.wait(reportFutures).then<DeviceReloadReport?>(
(List<vm_service.ReloadReport> reports) async {
// TODO(aam): Investigate why we are validating only first reload report,
// which seems to be current behavior
if (reports.isEmpty) {
return null;
}
final vm_service.ReloadReport firstReport = reports.first;
// Don't print errors because they will be printed further down when
// `validateReloadReport` is called again.
......@@ -1208,9 +1212,9 @@ Future<OperationResult> _defaultReloadSourcesHelper(
},
));
}
final List<DeviceReloadReport> reports = await Future.wait(allReportsFutures);
final vm_service.ReloadReport reloadReport = reports.first.reports[0];
if (!HotRunner.validateReloadReport(reloadReport)) {
final Iterable<DeviceReloadReport> reports = (await Future.wait(allReportsFutures)).whereType<DeviceReloadReport>();
final vm_service.ReloadReport? reloadReport = reports.isEmpty ? null : reports.first.reports[0];
if (reloadReport == null || !HotRunner.validateReloadReport(reloadReport)) {
// Reload failed.
HotEvent('reload-reject',
targetPlatform: targetPlatform!,
......@@ -1223,6 +1227,9 @@ Future<OperationResult> _defaultReloadSourcesHelper(
// Reset devFS lastCompileTime to ensure the file will still be marked
// as dirty on subsequent reloads.
_resetDevFSCompileTime(flutterDevices);
if (reloadReport == null) {
return OperationResult(1, 'No Dart isolates found');
}
final ReloadReportContents contents = ReloadReportContents.fromReloadReport(reloadReport);
return OperationResult(1, 'Reload rejected: ${contents.notices.join("\n")}');
}
......
// Copyright 2014 The Flutter 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 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/resident_runner.dart';
import 'package:flutter_tools/src/run_hot.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:test/fake.dart';
import 'package:vm_service/vm_service.dart' as vm_service;
import '../src/context.dart';
void main() {
testUsingContext('defaultReloadSourcesHelper() handles empty DeviceReloadReports)', () {
defaultReloadSourcesHelper(
_FakeHotRunner(),
<FlutterDevice?>[_FakeFlutterDevice()],
false,
const <String, dynamic>{},
'android',
'flutter-sdk',
false,
'test-reason',
);
});
}
class _FakeHotRunner extends Fake implements HotRunner {}
class _FakeDevFS extends Fake implements DevFS {
@override
final Uri? baseUri = Uri();
@override
void resetLastCompiled() {}
}
class _FakeFlutterDevice extends Fake implements FlutterDevice {
@override
final DevFS? devFS = _FakeDevFS();
@override
final FlutterVmService? vmService = _FakeFlutterVmService();
}
class _FakeFlutterVmService extends Fake implements FlutterVmService {
@override
final vm_service.VmService service = _FakeVmService();
}
class _FakeVmService extends Fake implements vm_service.VmService {
@override
Future<_FakeVm> getVM() async => _FakeVm();
}
class _FakeVm extends Fake implements vm_service.VM {
final List<vm_service.IsolateRef> _isolates = <vm_service.IsolateRef>[];
@override
List<vm_service.IsolateRef>? get isolates => _isolates;
}
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