Introduce the concept of asynchronicity to the service extensions. (#7823)
This allows us, for example, to wait for the slow mode banner to have
been removed from the screen before triggering a screen shot.
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart
index 00ba858..a7dd705 100644
--- a/packages/flutter_tools/lib/src/vmservice.dart
+++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -34,7 +34,7 @@
///
/// Requests made via the returns [VMService] time out after [requestTimeout]
/// amount of time, which is [kDefaultRequestTimeout] by default.
- static Future<VMService> connect(Uri httpUri, {Duration requestTimeout: kDefaultRequestTimeout}) async {
+ static Future<VMService> connect(Uri httpUri, { Duration requestTimeout: kDefaultRequestTimeout }) async {
Uri wsUri = httpUri.replace(scheme: 'ws', path: path.join(httpUri.path, 'ws'));
WebSocket ws;
try {
@@ -264,7 +264,7 @@
Map<String, dynamic> params = <String, dynamic>{
'objectId': id,
};
- return _owner.isolate.invokeRpcRaw('getObject', params);
+ return _owner.isolate.invokeRpcRaw('getObject', params: params);
}
Future<ServiceObject> _inProgressReload;
@@ -437,7 +437,7 @@
@override
Future<Map<String, dynamic>> _fetchDirect() async {
- return invokeRpcRaw('getVM', <String, dynamic> {});
+ return invokeRpcRaw('getVM');
}
@override
@@ -567,27 +567,39 @@
}
/// Invoke the RPC and return the raw response.
- Future<Map<String, dynamic>> invokeRpcRaw(
- String method, [Map<String, dynamic> params, Duration timeout]) async {
- if (params == null) {
- params = <String, dynamic>{};
- }
-
+ ///
+ /// If `timeoutFatal` is false, then a timeout will result in a null return
+ /// value. Otherwise, it results in an exception.
+ Future<Map<String, dynamic>> invokeRpcRaw(String method, {
+ Map<String, dynamic> params: const <String, dynamic>{},
+ Duration timeout,
+ bool timeoutFatal: true,
+ }) async {
+ assert(params != null);
+ timeout ??= _vmService._requestTimeout;
try {
Map<String, dynamic> result = await _vmService.peer
.sendRequest(method, params)
- .timeout(timeout ?? _vmService._requestTimeout);
+ .timeout(timeout);
return result;
- } on TimeoutException catch(_) {
- printError('Request to Dart VM Service timed out: $method($params)');
- rethrow;
+ } on TimeoutException {
+ printTrace('Request to Dart VM Service timed out: $method($params)');
+ if (timeoutFatal)
+ throw new TimeoutException('Request to Dart VM Service timed out: $method($params)');
+ return null;
}
}
- /// Invoke the RPC and return a ServiceObject response.
- Future<ServiceObject> invokeRpc(
- String method, { Map<String, dynamic> params, Duration timeout }) async {
- Map<String, dynamic> response = await invokeRpcRaw(method, params, timeout);
+ /// Invoke the RPC and return a [ServiceObject] response.
+ Future<ServiceObject> invokeRpc(String method, {
+ Map<String, dynamic> params: const <String, dynamic>{},
+ Duration timeout,
+ }) async {
+ Map<String, dynamic> response = await invokeRpcRaw(
+ method,
+ params: params,
+ timeout: timeout,
+ );
ServiceObject serviceObject = new ServiceObject._fromMap(this, response);
if ((serviceObject != null) && (serviceObject._canCache)) {
String serviceObjectId = serviceObject.id;
@@ -597,19 +609,13 @@
}
/// Create a new development file system on the device.
- Future<Map<String, dynamic>> createDevFS(String fsName) async {
- Map<String, dynamic> response =
- await invokeRpcRaw('_createDevFS', <String, dynamic> {
- 'fsName': fsName
- });
- return response;
+ Future<Map<String, dynamic>> createDevFS(String fsName) {
+ return invokeRpcRaw('_createDevFS', params: <String, dynamic> { 'fsName': fsName });
}
/// List the development file system son the device.
Future<List<String>> listDevFS() async {
- Map<String, dynamic> response =
- await invokeRpcRaw('_listDevFS', <String, dynamic>{});
- return response['fsNames'];
+ return (await invokeRpcRaw('_listDevFS'))['fsNames'];
}
// Write one file into a file system.
@@ -619,36 +625,36 @@
}) {
assert(path != null);
assert(fileContents != null);
-
- return invokeRpcRaw('_writeDevFSFile', <String, dynamic> {
- 'fsName': fsName,
- 'path': path,
- 'fileContents': BASE64.encode(fileContents)
- });
+ return invokeRpcRaw(
+ '_writeDevFSFile',
+ params: <String, dynamic>{
+ 'fsName': fsName,
+ 'path': path,
+ 'fileContents': BASE64.encode(fileContents),
+ },
+ );
}
// Read one file from a file system.
- Future<List<int>> readDevFSFile(String fsName, String path) {
- return invokeRpcRaw('_readDevFSFile', <String, dynamic> {
- 'fsName': fsName,
- 'path': path
- }).then((Map<String, dynamic> response) {
- return BASE64.decode(response['fileContents']);
- });
+ Future<List<int>> readDevFSFile(String fsName, String path) async {
+ Map<String, dynamic> response = await invokeRpcRaw(
+ '_readDevFSFile',
+ params: <String, dynamic>{
+ 'fsName': fsName,
+ 'path': path,
+ },
+ );
+ return BASE64.decode(response['fileContents']);
}
/// The complete list of a file system.
- Future<List<String>> listDevFSFiles(String fsName) {
- return invokeRpcRaw('_listDevFSFiles', <String, dynamic> {
- 'fsName': fsName
- }).then((Map<String, dynamic> response) {
- return response['files'];
- });
+ Future<List<String>> listDevFSFiles(String fsName) async {
+ return (await invokeRpcRaw('_listDevFSFiles', params: <String, dynamic>{ 'fsName': fsName }))['files'];
}
/// Delete an existing file system.
Future<Map<String, dynamic>> deleteDevFS(String fsName) {
- return invokeRpcRaw('_deleteDevFS', <String, dynamic> { 'fsName': fsName });
+ return invokeRpcRaw('_deleteDevFS', params: <String, dynamic>{ 'fsName': fsName });
}
Future<ServiceMap> runInView(String viewId,
@@ -665,20 +671,21 @@
}
Future<Map<String, dynamic>> clearVMTimeline() {
- return invokeRpcRaw('_clearVMTimeline', <String, dynamic>{});
+ return invokeRpcRaw('_clearVMTimeline');
}
- Future<Map<String, dynamic>> setVMTimelineFlags(
- List<String> recordedStreams) {
+ Future<Map<String, dynamic>> setVMTimelineFlags(List<String> recordedStreams) {
assert(recordedStreams != null);
-
- return invokeRpcRaw('_setVMTimelineFlags', <String, dynamic> {
- 'recordedStreams': recordedStreams
- });
+ return invokeRpcRaw(
+ '_setVMTimelineFlags',
+ params: <String, dynamic>{
+ 'recordedStreams': recordedStreams,
+ },
+ );
}
Future<Map<String, dynamic>> getVMTimeline() {
- return invokeRpcRaw('_getVMTimeline', <String, dynamic> {}, kLongRequestTimeout);
+ return invokeRpcRaw('_getVMTimeline', timeout: kLongRequestTimeout);
}
Future<Null> refreshViews() async {
@@ -736,12 +743,15 @@
@override
Future<Map<String, dynamic>> _fetchDirect() {
- return invokeRpcRaw('getIsolate', <String, dynamic>{});
+ return invokeRpcRaw('getIsolate');
}
/// Invoke the RPC and return the raw response.
- Future<Map<String, dynamic>> invokeRpcRaw(
- String method, [Map<String, dynamic> params, Duration timeout]) {
+ Future<Map<String, dynamic>> invokeRpcRaw(String method, {
+ Map<String, dynamic> params,
+ Duration timeout,
+ bool timeoutFatal: true,
+ }) {
// Inject the 'isolateId' parameter.
if (params == null) {
params = <String, dynamic>{
@@ -750,21 +760,18 @@
} else {
params['isolateId'] = id;
}
- return vm.invokeRpcRaw(method, params, timeout);
+ return vm.invokeRpcRaw(method, params: params, timeout: timeout, timeoutFatal: timeoutFatal);
}
/// Invoke the RPC and return a ServiceObject response.
- Future<ServiceObject> invokeRpc(
- String method, Map<String, dynamic> params) async {
- Map<String, dynamic> response = await invokeRpcRaw(method, params);
- return getFromMap(response);
+ Future<ServiceObject> invokeRpc(String method, Map<String, dynamic> params) async {
+ return getFromMap(await invokeRpcRaw(method, params: params));
}
@override
void _update(Map<String, dynamic> map, bool mapIsRef) {
- if (mapIsRef) {
+ if (mapIsRef)
return;
- }
_loaded = true;
int startTimeMillis = map['startTime'];
@@ -791,7 +798,7 @@
if (packagesPath != null) {
arguments['packagesUri'] = packagesPath;
}
- Map<String, dynamic> response = await invokeRpcRaw('_reloadSources', arguments);
+ Map<String, dynamic> response = await invokeRpcRaw('_reloadSources', params: arguments);
return response;
} on rpc.RpcException catch(e) {
return new Future<Map<String, dynamic>>.error(<String, dynamic>{
@@ -807,9 +814,14 @@
// Invoke a flutter extension method, if the flutter extension is not
// available, returns null.
Future<Map<String, dynamic>> invokeFlutterExtensionRpcRaw(
- String method, { Map<String, dynamic> params, Duration timeout }) async {
+ String method, {
+ Map<String, dynamic> params,
+ Duration timeout,
+ bool timeoutFatal: true,
+ }
+ ) async {
try {
- return await invokeRpcRaw(method, params, timeout);
+ return await invokeRpcRaw(method, params: params, timeout: timeout, timeoutFatal: timeoutFatal);
} on rpc.RpcException catch (e) {
// If an application is not using the framework
if (e.code == rpc_error_code.METHOD_NOT_FOUND)
@@ -821,29 +833,42 @@
// Debug dump extension methods.
Future<Map<String, dynamic>> flutterDebugDumpApp() {
- return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpApp');
+ return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpApp', timeout: kLongRequestTimeout);
}
Future<Map<String, dynamic>> flutterDebugDumpRenderTree() {
- return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpRenderTree');
+ return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpRenderTree', timeout: kLongRequestTimeout);
}
Future<Map<String, dynamic>> flutterToggleDebugPaintSizeEnabled() async {
Map<String, dynamic> state = await invokeFlutterExtensionRpcRaw('ext.flutter.debugPaint');
- if (state != null && state.containsKey('enabled') && state['enabled'] is bool)
- state = await invokeFlutterExtensionRpcRaw('ext.flutter.debugPaint',
- params: <String, dynamic>{ 'enabled': !state['enabled'] });
+ if (state != null && state.containsKey('enabled') && state['enabled'] is bool) {
+ state = await invokeFlutterExtensionRpcRaw(
+ 'ext.flutter.debugPaint',
+ params: <String, dynamic>{ 'enabled': !state['enabled'] },
+ timeout: const Duration(milliseconds: 150),
+ timeoutFatal: false,
+ );
+ }
return state;
}
Future<Null> flutterDebugAllowBanner(bool show) async {
- await invokeFlutterExtensionRpcRaw('ext.flutter.debugAllowBanner', params: <String, dynamic>{ 'enabled': show });
+ await invokeFlutterExtensionRpcRaw(
+ 'ext.flutter.debugAllowBanner',
+ params: <String, dynamic>{ 'enabled': show },
+ timeout: const Duration(milliseconds: 150),
+ timeoutFatal: false,
+ );
}
// Reload related extension methods.
Future<Map<String, dynamic>> flutterReassemble() async {
- return await invokeFlutterExtensionRpcRaw('ext.flutter.reassemble',
- timeout: kLongRequestTimeout);
+ return await invokeFlutterExtensionRpcRaw(
+ 'ext.flutter.reassemble',
+ timeout: kLongRequestTimeout,
+ timeoutFatal: false,
+ );
}
Future<bool> flutterFrameworkPresent() async {
@@ -856,16 +881,19 @@
Future<Map<String, dynamic>> flutterEvictAsset(String assetPath) async {
return await invokeFlutterExtensionRpcRaw('ext.flutter.evict',
- params: <String, dynamic>{
- 'value': assetPath
- }
+ params: <String, dynamic>{
+ 'value': assetPath,
+ }
);
}
// Application control extension methods.
Future<Map<String, dynamic>> flutterExit() async {
- return await invokeFlutterExtensionRpcRaw('ext.flutter.exit').timeout(
- const Duration(seconds: 2), onTimeout: () => null);
+ return await invokeFlutterExtensionRpcRaw(
+ 'ext.flutter.exit',
+ timeout: const Duration(seconds: 2),
+ timeoutFatal: false,
+ );
}
}