[dds/dap] Handle "Service has disappeared" errors for in-flight requests when app may be shutting down

Fixes https://github.com/flutter/flutter/issues/116235.

Change-Id: Ibfd24bce45519116e350a7f409609f19ca502ad3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/303580
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
Danny Tuppeny 2023-05-16 14:44:23 +00:00 committed by Commit Queue
parent 578dd70fae
commit 84f528d26d
4 changed files with 28 additions and 13 deletions

View file

@ -1,3 +1,6 @@
# 2.8.2
- [DAP] Fixed an issue that could result in unhandled exceptions from in-flight requests when the application/VM Service is shutting down.
# 2.8.1
- Updated DDS protocol version to 1.5.
- Added `getPerfettoVMTimelineWithCpuSamples` RPC.

View file

@ -2425,17 +2425,29 @@ abstract class DartDebugAdapter<TL extends LaunchRequestArguments,
try {
return await func();
} on vm.RPCError catch (e) {
// If we've been asked to shut down while this request was occurring,
// it's normal to get some types of errors from in-flight VM Service
// requests and we should handle them silently.
if (isTerminating) {
// kServiceDisappeared is thrown sometimes when services disappear.
if (e.code == RpcErrorCodes.kServiceDisappeared) {
// kServiceDisappeared is thrown sometimes when the VM Service is
// shutting down. Usually this is because we're shutting down (and
// `isTerminating` is true), but it can also happen if the app is closed
// outside of the DAP (eg. closing the simulator) so it's possible our
// requests will fail in this way before we've handled any event to set
// `isTerminating`.
if (e.code == RpcErrorCodes.kServiceDisappeared) {
return null;
}
// For any other kind of server error, ignore it if we're shutting down
// (because lots of requests can generate all sorts of errors if the VM
// and Isolates are shutting down), or if it's a "client closed with
// pending request" error (which also indicates a shutdown, but as above,
// we might not have set `isTerminating` yet).
if (e.code == json_rpc_errors.SERVER_ERROR) {
// Ignore all server errors during shutdown.
if (isTerminating) {
return null;
}
// SERVER_ERROR can occur when DDS completes any outstanding requests
// with "The client closed with pending request".
if (e.code == json_rpc_errors.SERVER_ERROR) {
// Always ignore "closed with pending request" errors.
if (e.message.contains("The client closed with pending request")) {
return null;
}
}

View file

@ -1,5 +1,5 @@
name: dds
version: 2.8.1
version: 2.8.2
description: >-
A library used to spawn the Dart Developer Service, used to communicate with
a Dart VM Service instance.

View file

@ -372,12 +372,12 @@ main() {
test('can shutdown during startup', () async {
final testFile = dap.createTestFile(simpleArgPrintingProgram);
// Terminate the app immediately upon receiving the first Thread event.
// Request termination immediately upon receiving the first Thread event.
// The DAP is also responding to this event to configure the isolate (eg.
// set breakpoints and exception pause behaviour) and will cause it to
// receive "Service has disappeared" responses if these are in-flight as
// the process terminates. These should not go unhandled since they are
// normal during shutdown.
// the process terminates. These should be silently discarded since they
// are normal during shutdown.
unawaited(dap.client.event('thread').then((_) => dap.client.terminate()));
// Start the program and expect termination.