mirror of
https://github.com/flutter/flutter
synced 2024-07-16 10:29:14 +00:00
[flutter_tools] Catch rpc error in render frame with raster stats (#144190)
Fixes https://github.com/flutter/flutter/issues/143010. This is intended to be cherrypicked into the 3.19 and 3.20 releases. Long-term, we should deprecate this feature: https://github.com/flutter/flutter/issues/144191
This commit is contained in:
parent
47b0ef8127
commit
f89b4f151e
|
@ -714,23 +714,30 @@ abstract class ResidentHandlers {
|
|||
continue;
|
||||
}
|
||||
final List<FlutterView> views = await device!.vmService!.getFlutterViews();
|
||||
for (final FlutterView view in views) {
|
||||
final Map<String, Object?>? rasterData =
|
||||
await device.vmService!.renderFrameWithRasterStats(
|
||||
viewId: view.id,
|
||||
uiIsolateId: view.uiIsolate!.id,
|
||||
);
|
||||
if (rasterData != null) {
|
||||
final File tempFile = globals.fsUtils.getUniqueFile(
|
||||
globals.fs.currentDirectory,
|
||||
'flutter_jank_metrics',
|
||||
'json',
|
||||
);
|
||||
tempFile.writeAsStringSync(jsonEncode(rasterData), flush: true);
|
||||
logger.printStatus('Wrote jank metrics to ${tempFile.absolute.path}');
|
||||
} else {
|
||||
logger.printWarning('Unable to get jank metrics.');
|
||||
try {
|
||||
for (final FlutterView view in views) {
|
||||
final Map<String, Object?>? rasterData =
|
||||
await device.vmService!.renderFrameWithRasterStats(
|
||||
viewId: view.id,
|
||||
uiIsolateId: view.uiIsolate!.id,
|
||||
);
|
||||
if (rasterData != null) {
|
||||
final File tempFile = globals.fsUtils.getUniqueFile(
|
||||
globals.fs.currentDirectory,
|
||||
'flutter_jank_metrics',
|
||||
'json',
|
||||
);
|
||||
tempFile.writeAsStringSync(jsonEncode(rasterData), flush: true);
|
||||
logger.printStatus('Wrote jank metrics to ${tempFile.absolute.path}');
|
||||
} else {
|
||||
logger.printWarning('Unable to get jank metrics.');
|
||||
}
|
||||
}
|
||||
} on vm_service.RPCError catch (err) {
|
||||
if (err.code != RPCErrorCodes.kServerError || !err.message.contains('Raster status not supported on Impeller backend')) {
|
||||
rethrow;
|
||||
}
|
||||
logger.printWarning('Unable to get jank metrics for Impeller renderer');
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -48,13 +48,13 @@ const FakeVmServiceRequest failingCreateDevFSRequest = FakeVmServiceRequest(
|
|||
args: <String, Object>{
|
||||
'fsName': 'test',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest failingDeleteDevFSRequest = FakeVmServiceRequest(
|
||||
method: '_deleteDevFS',
|
||||
args: <String, dynamic>{'fsName': 'test'},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
);
|
||||
|
||||
void main() {
|
||||
|
|
|
@ -264,14 +264,14 @@ void main() {
|
|||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: kListViewsMethod,
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: 'streamCancel',
|
||||
args: <String, Object>{
|
||||
'streamId': 'Isolate',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
], httpAddress: Uri.parse('http://localhost:1234'));
|
||||
|
||||
|
@ -340,14 +340,14 @@ void main() {
|
|||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: kListViewsMethod,
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: 'streamCancel',
|
||||
args: <String, Object>{
|
||||
'streamId': 'Isolate',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
], httpAddress: Uri.parse('http://localhost:5678'));
|
||||
|
||||
|
|
|
@ -114,6 +114,18 @@ final FakeVmServiceRequest listViews = FakeVmServiceRequest(
|
|||
},
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest renderFrameRasterStats = FakeVmServiceRequest(
|
||||
method: kRenderFrameWithRasterStatsMethod,
|
||||
args: <String, Object>{
|
||||
'viewId': 'a',
|
||||
'isolateId': '1',
|
||||
},
|
||||
error: FakeRPCError(
|
||||
code: RPCErrorCodes.kServerError,
|
||||
error: 'Raster status not supported on Impeller backend',
|
||||
),
|
||||
);
|
||||
|
||||
const FakeVmServiceRequest setAssetBundlePath = FakeVmServiceRequest(
|
||||
method: '_flutter.setAssetBundlePath',
|
||||
args: <String, Object>{
|
||||
|
|
|
@ -333,6 +333,32 @@ void main() {
|
|||
Usage: () => TestUsage(),
|
||||
}));
|
||||
|
||||
testUsingContext('ResidentRunner can handle an RPC exception from debugFrameJankMetrics', () => testbed.run(() async {
|
||||
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
|
||||
listViews,
|
||||
listViews,
|
||||
listViews,
|
||||
renderFrameRasterStats,
|
||||
]);
|
||||
final Completer<DebugConnectionInfo> futureConnectionInfo = Completer<DebugConnectionInfo>.sync();
|
||||
final Completer<void> futureAppStart = Completer<void>.sync();
|
||||
unawaited(residentRunner.attach(
|
||||
appStartedCompleter: futureAppStart,
|
||||
connectionInfoCompleter: futureConnectionInfo,
|
||||
enableDevTools: true,
|
||||
));
|
||||
await futureAppStart.future;
|
||||
|
||||
final bool result = await residentRunner.debugFrameJankMetrics();
|
||||
expect(result, true);
|
||||
expect((globals.flutterUsage as TestUsage).events, isEmpty);
|
||||
expect(fakeAnalytics.sentEvents, isEmpty);
|
||||
expect(fakeVmServiceHost?.hasRemainingExpectations, false);
|
||||
expect((globals.logger as BufferLogger).warningText, contains('Unable to get jank metrics for Impeller renderer'));
|
||||
}, overrides: <Type, Generator>{
|
||||
Usage: () => TestUsage(),
|
||||
}));
|
||||
|
||||
testUsingContext('ResidentRunner fails its operation if the device initialization is not complete', () => testbed.run(() async {
|
||||
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
|
||||
listViews,
|
||||
|
|
|
@ -973,7 +973,7 @@ void main() {
|
|||
const FakeVmServiceRequest(
|
||||
method: kHotRestartServiceName,
|
||||
// Failed response,
|
||||
errorCode: RPCErrorCodes.kInternalError,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kInternalError),
|
||||
),
|
||||
]);
|
||||
setupMocks();
|
||||
|
|
|
@ -1125,7 +1125,7 @@ void main() {
|
|||
const FakeVmServiceRequest(
|
||||
method: 'ext.dwds.screenshot',
|
||||
// Failed response,
|
||||
errorCode: RPCErrorCodes.kInternalError,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kInternalError),
|
||||
),
|
||||
FakeVmServiceRequest(
|
||||
method: 'ext.flutter.debugAllowBanner',
|
||||
|
@ -1165,7 +1165,7 @@ void main() {
|
|||
'enabled': 'true',
|
||||
},
|
||||
// Failed response,
|
||||
errorCode: RPCErrorCodes.kInternalError,
|
||||
error: const FakeRPCError(code: RPCErrorCodes.kInternalError),
|
||||
),
|
||||
],
|
||||
logger: logger,
|
||||
|
|
|
@ -140,7 +140,7 @@ void main() {
|
|||
...vmServiceSetup,
|
||||
const FakeVmServiceRequest(
|
||||
method: 'getVMTimeline',
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: 'setVMTimelineFlags',
|
||||
|
|
|
@ -301,7 +301,7 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kMethodNotFound,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kMethodNotFound),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
@ -320,7 +320,7 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kMethodNotFound,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kMethodNotFound),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
@ -339,7 +339,7 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kMethodNotFound,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kMethodNotFound),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
@ -358,7 +358,7 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kMethodNotFound,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kMethodNotFound),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
@ -377,7 +377,7 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kMethodNotFound,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kMethodNotFound),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
@ -396,7 +396,7 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kMethodNotFound,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kMethodNotFound),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
@ -436,26 +436,26 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'viewId': '1234',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: kListViewsMethod,
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: kScreenshotSkpMethod,
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: 'setVMTimelineFlags',
|
||||
args: <String, dynamic>{
|
||||
'recordedStreams': <String>['test'],
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: 'getVMTimeline',
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: kRenderFrameWithRasterStatsMethod,
|
||||
|
@ -463,7 +463,7 @@ void main() {
|
|||
'viewId': '1',
|
||||
'isolateId': '12',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
@ -495,9 +495,13 @@ void main() {
|
|||
testWithoutContext('getIsolateOrNull returns null if service disappears ', () async {
|
||||
final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost(
|
||||
requests: <VmServiceExpectation>[
|
||||
const FakeVmServiceRequest(method: 'getIsolate', args: <String, Object>{
|
||||
'isolateId': 'isolate/123',
|
||||
}, errorCode: RPCErrorCodes.kServiceDisappeared),
|
||||
const FakeVmServiceRequest(
|
||||
method: 'getIsolate',
|
||||
args: <String, Object>{
|
||||
'isolateId': 'isolate/123',
|
||||
},
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -702,7 +706,7 @@ void main() {
|
|||
args: <String, Object>{
|
||||
'isolateId': '1',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
// Assume a different isolate returns.
|
||||
FakeVmServiceStreamResponse(
|
||||
|
@ -734,7 +738,7 @@ void main() {
|
|||
'streamId': 'Isolate',
|
||||
},
|
||||
// Stream already subscribed - https://github.com/dart-lang/sdk/blob/main/runtime/vm/service/service.md#streamlisten
|
||||
errorCode: 103,
|
||||
error: FakeRPCError(code: 103),
|
||||
),
|
||||
listViewsRequest,
|
||||
FakeVmServiceRequest(
|
||||
|
@ -802,14 +806,14 @@ void main() {
|
|||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: kListViewsMethod,
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
const FakeVmServiceRequest(
|
||||
method: 'streamCancel',
|
||||
args: <String, Object>{
|
||||
'streamId': 'Isolate',
|
||||
},
|
||||
errorCode: RPCErrorCodes.kServiceDisappeared,
|
||||
error: FakeRPCError(code: RPCErrorCodes.kServiceDisappeared),
|
||||
),
|
||||
]);
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ class FakeVmServiceHost {
|
|||
expect(_requests, isEmpty);
|
||||
return;
|
||||
}
|
||||
if (fakeRequest.errorCode == null) {
|
||||
if (fakeRequest.error == null) {
|
||||
_input.add(json.encode(<String, Object?>{
|
||||
'jsonrpc': '2.0',
|
||||
'id': request['id'],
|
||||
|
@ -50,8 +50,8 @@ class FakeVmServiceHost {
|
|||
'jsonrpc': '2.0',
|
||||
'id': request['id'],
|
||||
'error': <String, Object?>{
|
||||
'code': fakeRequest.errorCode,
|
||||
'message': 'error',
|
||||
'code': fakeRequest.error!.code,
|
||||
'message': fakeRequest.error!.error,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
@ -90,12 +90,22 @@ abstract class VmServiceExpectation {
|
|||
bool get isRequest;
|
||||
}
|
||||
|
||||
class FakeRPCError {
|
||||
const FakeRPCError({
|
||||
required this.code,
|
||||
this.error = 'error',
|
||||
});
|
||||
|
||||
final int code;
|
||||
final String error;
|
||||
}
|
||||
|
||||
class FakeVmServiceRequest implements VmServiceExpectation {
|
||||
const FakeVmServiceRequest({
|
||||
required this.method,
|
||||
this.args = const <String, Object?>{},
|
||||
this.jsonResponse,
|
||||
this.errorCode,
|
||||
this.error,
|
||||
this.close = false,
|
||||
});
|
||||
|
||||
|
@ -106,7 +116,7 @@ class FakeVmServiceRequest implements VmServiceExpectation {
|
|||
|
||||
/// If non-null, the error code for a [vm_service.RPCError] in place of a
|
||||
/// standard response.
|
||||
final int? errorCode;
|
||||
final FakeRPCError? error;
|
||||
final Map<String, Object?>? args;
|
||||
final Map<String, Object?>? jsonResponse;
|
||||
|
||||
|
|
Loading…
Reference in a new issue