Skip to content

Commit 1f1efa3

Browse files
authored
Fix Flutter crash by catching WipError on resume and mapping to RPC error (#2188)
1 parent f8f752c commit 1f1efa3

File tree

5 files changed

+64
-54
lines changed

5 files changed

+64
-54
lines changed

dwds/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Update SDK constraint to `>=3.1.0-254.0.dev <4.0.0`. - [#2169](https://github.com/dart-lang/webdev/pull/2169)
55
- Require min `build_web_compilers` version `4.0.4` - [#2171](https://github.com/dart-lang/webdev/pull/2171)
66
- Switch to using new debugging API from DDC to support new type system. - [#2159](https://github.com/dart-lang/webdev/pull/2159)
7+
- Fix Flutter crash when calling `resume` when app is not paused. - [#2188](https://github.com/dart-lang/webdev/pull/2188)
78

89
## 19.0.2
910

dwds/lib/src/debugging/debugger.dart

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -121,32 +121,45 @@ class Debugger extends Domain {
121121
/// Note that stepping will automatically continue until Chrome is paused at
122122
/// a location for which we have source information.
123123
Future<Success> resume({String? step, int? frameIndex}) async {
124-
if (frameIndex != null) {
125-
throw ArgumentError('FrameIndex is currently unsupported.');
126-
}
127-
WipResponse? result;
128-
if (step != null) {
129-
_isStepping = true;
130-
switch (step) {
131-
case 'Over':
132-
result = await _remoteDebugger.stepOver();
133-
break;
134-
case 'Out':
135-
result = await _remoteDebugger.stepOut();
136-
break;
137-
case 'Into':
138-
result = await _remoteDebugger.stepInto();
139-
break;
140-
default:
141-
throwInvalidParam('resume', 'Unexpected value for step: $step');
124+
try {
125+
if (frameIndex != null) {
126+
throw ArgumentError('FrameIndex is currently unsupported.');
142127
}
143-
} else {
144-
_isStepping = false;
145-
_previousSteppingLocation = null;
146-
result = await _remoteDebugger.resume();
128+
WipResponse? result;
129+
if (step != null) {
130+
_isStepping = true;
131+
switch (step) {
132+
case 'Over':
133+
result = await _remoteDebugger.stepOver();
134+
break;
135+
case 'Out':
136+
result = await _remoteDebugger.stepOut();
137+
break;
138+
case 'Into':
139+
result = await _remoteDebugger.stepInto();
140+
break;
141+
default:
142+
throwInvalidParam('resume', 'Unexpected value for step: $step');
143+
}
144+
} else {
145+
_isStepping = false;
146+
_previousSteppingLocation = null;
147+
result = await _remoteDebugger.resume();
148+
}
149+
handleErrorIfPresent(result);
150+
return Success();
151+
} on WipError catch (e) {
152+
final errorMessage = e.message;
153+
if (errorMessage != null &&
154+
errorMessage.contains('Can only perform operation while paused')) {
155+
throw RPCError(
156+
'resume',
157+
RPCErrorKind.kIsolateMustBePaused.code,
158+
errorMessage,
159+
);
160+
}
161+
rethrow;
147162
}
148-
handleErrorIfPresent(result);
149-
return Success();
150163
}
151164

152165
/// Returns the current Dart stack for the paused debugger.

dwds/lib/src/services/chrome_proxy_service.dart

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,33 +1088,20 @@ ${globalLoadStrategy.loadModuleSnippet}("dart_sdk").developer.invokeExtension(
10881088
String? step,
10891089
int? frameIndex,
10901090
}) async {
1091-
try {
1092-
if (inspector.appConnection.isStarted) {
1093-
return captureElapsedTime(
1094-
() async {
1095-
await isInitialized;
1096-
await isStarted;
1097-
_checkIsolate('resume', isolateId);
1098-
return await (await debuggerFuture)
1099-
.resume(step: step, frameIndex: frameIndex);
1100-
},
1101-
(result) => DwdsEvent.resume(step),
1102-
);
1103-
} else {
1104-
inspector.appConnection.runMain();
1105-
return Success();
1106-
}
1107-
} on WipError catch (e) {
1108-
final errorMessage = e.message;
1109-
if (errorMessage != null &&
1110-
errorMessage.contains('Can only perform operation while paused')) {
1111-
throw RPCError(
1112-
'resume',
1113-
RPCErrorKind.kIsolateMustBePaused.code,
1114-
errorMessage,
1115-
);
1116-
}
1117-
rethrow;
1091+
if (inspector.appConnection.isStarted) {
1092+
return captureElapsedTime(
1093+
() async {
1094+
await isInitialized;
1095+
await isStarted;
1096+
_checkIsolate('resume', isolateId);
1097+
return await (await debuggerFuture)
1098+
.resume(step: step, frameIndex: frameIndex);
1099+
},
1100+
(result) => DwdsEvent.resume(step),
1101+
);
1102+
} else {
1103+
inspector.appConnection.runMain();
1104+
return Success();
11181105
}
11191106
}
11201107

dwds/test/chrome_proxy_service_test.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,12 +1339,17 @@ void main() {
13391339
expect(pauseBreakpoints, hasLength(1));
13401340
expect(pauseBreakpoints.first.id, bp.id);
13411341
await service.removeBreakpoint(isolateId!, bp.id!);
1342-
});
1343-
1344-
tearDown(() async {
13451342
// Resume execution to not impact other tests.
13461343
await service.resume(isolateId!);
13471344
});
1345+
1346+
test('resuming throws kIsolateMustBePaused error if not paused',
1347+
() async {
1348+
await expectLater(
1349+
service.resume(isolateId!),
1350+
throwsRPCErrorWithCode(RPCErrorKind.kIsolateMustBePaused.code),
1351+
);
1352+
});
13481353
});
13491354

13501355
group('Step', () {

dwds/test/fixtures/context.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ Matcher isRPCErrorWithMessage(String message) =>
5555
Matcher throwsRPCErrorWithMessage(String message) =>
5656
throwsA(isRPCErrorWithMessage(message));
5757

58+
Matcher isRPCErrorWithCode(int code) =>
59+
isA<RPCError>().having((e) => e.code, 'code', equals(code));
60+
Matcher throwsRPCErrorWithCode(int code) => throwsA(isRPCErrorWithCode(code));
61+
5862
enum CompilationMode { buildDaemon, frontendServer }
5963

6064
class TestContext {

0 commit comments

Comments
 (0)