Skip to content

Commit d8f8613

Browse files
authored
when setting up the log reader for a device during flutter run, discard any RPCError thrown due to the device being disconnected (#155049)
Fixes flutter/flutter#154903 This PR contains some refactoring. To make the actual change easier to figure out, I've tried to separate parts of the change into multiple commits for easier reviewing �. **I plan on cherry-picking this change to stable.**
1 parent 50a190c commit d8f8613

File tree

8 files changed

+72
-8
lines changed

8 files changed

+72
-8
lines changed

packages/flutter_tools/lib/src/resident_runner.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,19 @@ class FlutterDevice {
416416
_loggingSubscription = null;
417417
}
418418

419-
Future<void> initLogReader() async {
420-
final vm_service.VM vm = await vmService!.service.getVM();
419+
/// Attempts to set up reading logs from the Flutter app on the device.
420+
///
421+
/// This can fail if the device if no longer connected.
422+
Future<void> tryInitLogReader() async {
423+
final vm_service.VM? vm = await vmService!.getVmGuarded();
424+
if (vm == null) {
425+
globals.printError(
426+
'Unable to initiate log reader for device'
427+
'${device?.name}, because the Flutter VM service connection '
428+
'is closed.',
429+
);
430+
return;
431+
}
421432
final DeviceLogReader logReader = await device!.getLogReader(app: package);
422433
logReader.appPid = vm.pid;
423434
}

packages/flutter_tools/lib/src/run_cold.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class ColdRunner extends ResidentRunner {
104104
if (device!.vmService == null) {
105105
continue;
106106
}
107-
await device.initLogReader();
107+
await device.tryInitLogReader();
108108
globals.printTrace('Connected to ${device.device!.name}');
109109
}
110110

@@ -154,7 +154,7 @@ class ColdRunner extends ResidentRunner {
154154
}
155155

156156
for (final FlutterDevice? device in flutterDevices) {
157-
await device!.initLogReader();
157+
await device!.tryInitLogReader();
158158
}
159159
for (final FlutterDevice? device in flutterDevices) {
160160
final List<FlutterView> views = await device!.vmService!.getFlutterViews();

packages/flutter_tools/lib/src/run_hot.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class HotRunner extends ResidentRunner {
261261
}
262262

263263
for (final FlutterDevice? device in flutterDevices) {
264-
await device!.initLogReader();
264+
await device!.tryInitLogReader();
265265
device
266266
.developmentShaderCompiler
267267
.configureCompiler(device.targetPlatform);

packages/flutter_tools/lib/src/vmservice.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,22 @@ class FlutterVmService {
491491
final Uri? wsAddress;
492492
final Uri? httpAddress;
493493

494+
/// Calls [service.getVM]. However, in the case that an [vm_service.RPCError]
495+
/// is thrown due to the service being disconnected, the error is discarded
496+
/// and null is returned.
497+
Future<vm_service.VM?> getVmGuarded() async {
498+
try {
499+
return await service.getVM();
500+
} on vm_service.RPCError catch (err) {
501+
if (err.code == RPCErrorCodes.kServiceDisappeared ||
502+
err.message.contains('Service connection disposed')) {
503+
globals.printTrace('VmService.getVm call failed: $err');
504+
return null;
505+
}
506+
rethrow;
507+
}
508+
}
509+
494510
Future<vm_service.Response?> callMethodWrapper(
495511
String method, {
496512
String? isolateId,

packages/flutter_tools/test/general.shard/cold_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
165165
}
166166

167167
@override
168-
Future<void> initLogReader() async { }
168+
Future<void> tryInitLogReader() async { }
169169
}
170170

171171
class FakeDevice extends Fake implements Device {

packages/flutter_tools/test/general.shard/resident_runner_helpers.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
228228
Future<void> stopEchoingDeviceLog() async { }
229229

230230
@override
231-
Future<void> initLogReader() async { }
231+
Future<void> tryInitLogReader() async { }
232232

233233
@override
234234
Future<Uri> setupDevFS(String fsName, Directory rootDirectory) async {

packages/flutter_tools/test/general.shard/resident_runner_test.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,6 +1934,43 @@ flutter:
19341934
ProcessManager: () => FakeProcessManager.any(),
19351935
});
19361936

1937+
testUsingContext('FlutterDevice does not throw when unable to initiate log reader due to VM service disconnection', () async {
1938+
fakeVmServiceHost = FakeVmServiceHost(
1939+
requests: <VmServiceExpectation>[
1940+
const FakeVmServiceRequest(
1941+
method: 'getVM',
1942+
error: FakeRPCError(
1943+
code: RPCErrorCodes.kServerError,
1944+
error: 'Service connection disposed',
1945+
),
1946+
),
1947+
],
1948+
);
1949+
final TestFlutterDevice flutterDevice = TestFlutterDevice(device);
1950+
flutterDevice.vmService = fakeVmServiceHost!.vmService;
1951+
await flutterDevice.tryInitLogReader();
1952+
final BufferLogger logger = globals.logger as BufferLogger;
1953+
expect(
1954+
logger.traceText,
1955+
contains(
1956+
'VmService.getVm call failed: getVM: (-32000) '
1957+
'Service connection disposed\n',
1958+
),
1959+
);
1960+
expect(
1961+
logger.errorText,
1962+
contains(
1963+
'Unable to initiate log reader for deviceFakeDevice, because '
1964+
'the Flutter VM service connection is closed.\n',
1965+
),
1966+
);
1967+
}, overrides: <Type, Generator>{
1968+
Logger: () => BufferLogger.test(),
1969+
Artifacts: () => Artifacts.test(),
1970+
FileSystem: () => MemoryFileSystem.test(),
1971+
ProcessManager: () => FakeProcessManager.any(),
1972+
});
1973+
19371974
testUsingContext('Uses existing DDS URI from exception field', () => testbed.run(() async {
19381975
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]);
19391976
final FakeDevice device = FakeDevice()

packages/flutter_tools/test/general.shard/resident_web_runner_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1755,7 +1755,7 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
17551755
Future<void> stopEchoingDeviceLog() async {}
17561756

17571757
@override
1758-
Future<void> initLogReader() async {}
1758+
Future<void> tryInitLogReader() async {}
17591759

17601760
@override
17611761
Future<Uri?> setupDevFS(String fsName, Directory rootDirectory) async {

0 commit comments

Comments
 (0)