Handle service disappeared RPCError when VM service connection disappears (#74424)
* Handle service disappeared RPCError when VM service connection disappears while invoking a service extension registered by the framework * Add unit test, handle non-trivial cases
This commit is contained in:
parent
1f07fde45d
commit
08068fd94c
@ -417,6 +417,25 @@ extension FlutterVmService on vm_service.VmService {
|
|||||||
|
|
||||||
Uri get httpAddress => this != null ? _httpAddressExpando[this] : null;
|
Uri get httpAddress => this != null ? _httpAddressExpando[this] : null;
|
||||||
|
|
||||||
|
Future<vm_service.Response> callMethodWrapper(
|
||||||
|
String method, {
|
||||||
|
String isolateId,
|
||||||
|
Map<String, dynamic> args
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
return await callMethod(method, isolateId: isolateId, args: args);
|
||||||
|
} on vm_service.RPCError catch (e) {
|
||||||
|
// If the service disappears mid-request the tool is unable to recover
|
||||||
|
// and should begin to shutdown due to the service connection closing.
|
||||||
|
// Swallow the exception here and let the shutdown logic elsewhere deal
|
||||||
|
// with cleaning up.
|
||||||
|
if (e.code == RPCErrorCodes.kServiceDisappeared) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the asset directory for the an attached Flutter view.
|
/// Set the asset directory for the an attached Flutter view.
|
||||||
Future<void> setAssetDirectory({
|
Future<void> setAssetDirectory({
|
||||||
@required Uri assetsDirectory,
|
@required Uri assetsDirectory,
|
||||||
@ -424,7 +443,7 @@ extension FlutterVmService on vm_service.VmService {
|
|||||||
@required String uiIsolateId,
|
@required String uiIsolateId,
|
||||||
}) async {
|
}) async {
|
||||||
assert(assetsDirectory != null);
|
assert(assetsDirectory != null);
|
||||||
await callMethod(kSetAssetBundlePathMethod,
|
await callMethodWrapper(kSetAssetBundlePathMethod,
|
||||||
isolateId: uiIsolateId,
|
isolateId: uiIsolateId,
|
||||||
args: <String, dynamic>{
|
args: <String, dynamic>{
|
||||||
'viewId': viewId,
|
'viewId': viewId,
|
||||||
@ -439,12 +458,15 @@ extension FlutterVmService on vm_service.VmService {
|
|||||||
Future<Map<String, Object>> getSkSLs({
|
Future<Map<String, Object>> getSkSLs({
|
||||||
@required String viewId,
|
@required String viewId,
|
||||||
}) async {
|
}) async {
|
||||||
final vm_service.Response response = await callMethod(
|
final vm_service.Response response = await callMethodWrapper(
|
||||||
kGetSkSLsMethod,
|
kGetSkSLsMethod,
|
||||||
args: <String, String>{
|
args: <String, String>{
|
||||||
'viewId': viewId,
|
'viewId': viewId,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if (response == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return response.json['SkSLs'] as Map<String, Object>;
|
return response.json['SkSLs'] as Map<String, Object>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +476,7 @@ extension FlutterVmService on vm_service.VmService {
|
|||||||
Future<void> flushUIThreadTasks({
|
Future<void> flushUIThreadTasks({
|
||||||
@required String uiIsolateId,
|
@required String uiIsolateId,
|
||||||
}) async {
|
}) async {
|
||||||
await callMethod(
|
await callMethodWrapper(
|
||||||
kFlushUIThreadTasksMethod,
|
kFlushUIThreadTasksMethod,
|
||||||
args: <String, String>{
|
args: <String, String>{
|
||||||
'isolateId': uiIsolateId,
|
'isolateId': uiIsolateId,
|
||||||
@ -480,7 +502,7 @@ extension FlutterVmService on vm_service.VmService {
|
|||||||
final Future<void> onRunnable = onIsolateEvent.firstWhere((vm_service.Event event) {
|
final Future<void> onRunnable = onIsolateEvent.firstWhere((vm_service.Event event) {
|
||||||
return event.kind == vm_service.EventKind.kIsolateRunnable;
|
return event.kind == vm_service.EventKind.kIsolateRunnable;
|
||||||
});
|
});
|
||||||
await callMethod(
|
await callMethodWrapper(
|
||||||
kRunInViewMethod,
|
kRunInViewMethod,
|
||||||
args: <String, Object>{
|
args: <String, Object>{
|
||||||
'viewId': viewId,
|
'viewId': viewId,
|
||||||
@ -745,9 +767,12 @@ extension FlutterVmService on vm_service.VmService {
|
|||||||
Duration delay = const Duration(milliseconds: 50),
|
Duration delay = const Duration(milliseconds: 50),
|
||||||
}) async {
|
}) async {
|
||||||
while (true) {
|
while (true) {
|
||||||
final vm_service.Response response = await callMethod(
|
final vm_service.Response response = await callMethodWrapper(
|
||||||
kListViewsMethod,
|
kListViewsMethod,
|
||||||
);
|
);
|
||||||
|
if (response == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final List<Object> rawViews = response.json['views'] as List<Object>;
|
final List<Object> rawViews = response.json['views'] as List<Object>;
|
||||||
final List<FlutterView> views = <FlutterView>[
|
final List<FlutterView> views = <FlutterView>[
|
||||||
for (final Object rawView in rawViews)
|
for (final Object rawView in rawViews)
|
||||||
|
@ -312,6 +312,27 @@ void main() {
|
|||||||
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWithoutContext('Framework service extension invocations return null if service disappears ', () async {
|
||||||
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||||
|
requests: <VmServiceExpectation>[
|
||||||
|
const FakeVmServiceRequest(method: kGetSkSLsMethod, args: <String, Object>{
|
||||||
|
'viewId': '1234',
|
||||||
|
}, errorCode: RPCErrorCodes.kServiceDisappeared),
|
||||||
|
const FakeVmServiceRequest(method: kListViewsMethod, errorCode: RPCErrorCodes.kServiceDisappeared),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
final Map<String, Object> skSLs = await fakeVmServiceHost.vmService.getSkSLs(
|
||||||
|
viewId: '1234',
|
||||||
|
);
|
||||||
|
expect(skSLs, null);
|
||||||
|
|
||||||
|
final List<FlutterView> views = await fakeVmServiceHost.vmService.getFlutterViews();
|
||||||
|
expect(views, null);
|
||||||
|
|
||||||
|
expect(fakeVmServiceHost.hasRemainingExpectations, false);
|
||||||
|
});
|
||||||
|
|
||||||
testWithoutContext('getFlutterViews polls until a view is returned', () async {
|
testWithoutContext('getFlutterViews polls until a view is returned', () async {
|
||||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||||
requests: <VmServiceExpectation>[
|
requests: <VmServiceExpectation>[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user