Unverified Commit 5adfd38d authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] Move service methods to VmService extension methods (#54337)

parent 4987210a
...@@ -305,7 +305,11 @@ class FlutterDevice { ...@@ -305,7 +305,11 @@ class FlutterDevice {
globals.fs.path.toUri(getAssetBuildDirectory())); globals.fs.path.toUri(getAssetBuildDirectory()));
assert(deviceAssetsDirectoryUri != null); assert(deviceAssetsDirectoryUri != null);
await Future.wait<void>(views.map<Future<void>>( await Future.wait<void>(views.map<Future<void>>(
(FlutterView view) => view.setAssetDirectory(deviceAssetsDirectoryUri) (FlutterView view) => vmService.setAssetDirectory(
assetsDirectory: deviceAssetsDirectoryUri,
uiIsolateId: view.uiIsolate.id,
viewId: view.id,
)
)); ));
} }
...@@ -748,7 +752,9 @@ abstract class ResidentRunner { ...@@ -748,7 +752,9 @@ abstract class ResidentRunner {
if (!supportsWriteSkSL) { if (!supportsWriteSkSL) {
throw Exception('writeSkSL is not supported by this runner.'); throw Exception('writeSkSL is not supported by this runner.');
} }
final Map<String, Object> data = await flutterDevices.first.views.first.getSkSLs(); final Map<String, Object> data = await flutterDevices.first.vmService.getSkSLs(
viewId: flutterDevices.first.views.first.id,
);
if (data.isEmpty) { if (data.isEmpty) {
globals.logger.printStatus( globals.logger.printStatus(
'No data was receieved. To ensure SkSL data can be generated use a ' 'No data was receieved. To ensure SkSL data can be generated use a '
......
...@@ -486,7 +486,8 @@ class HotRunner extends ResidentRunner { ...@@ -486,7 +486,8 @@ class HotRunner extends ResidentRunner {
futures.clear(); futures.clear();
for (final FlutterDevice device in flutterDevices) { for (final FlutterDevice device in flutterDevices) {
for (final FlutterView view in device.views) { for (final FlutterView view in device.views) {
futures.add(view.flushUIThreadTasks()); futures.add(device.vmService
.flushUIThreadTasks(uiIsolateId: view.uiIsolate.id));
} }
} }
await Future.wait(futures); await Future.wait(futures);
......
...@@ -17,6 +17,10 @@ import 'device.dart'; ...@@ -17,6 +17,10 @@ import 'device.dart';
import 'globals.dart' as globals; import 'globals.dart' as globals;
import 'version.dart'; import 'version.dart';
const String kGetSkSLsMethod = '_flutter.getSkSLs';
const String kSetAssetBundlePathMethod = '_flutter.setAssetBundlePath';
const String kFlushUIThreadTasksMethod = '_flutter.flushUIThreadTasks';
/// Override `WebSocketConnector` in [context] to use a different constructor /// Override `WebSocketConnector` in [context] to use a different constructor
/// for [WebSocket]s (used by tests). /// for [WebSocket]s (used by tests).
typedef WebSocketConnector = Future<io.WebSocket> Function(String url, {io.CompressionOptions compression}); typedef WebSocketConnector = Future<io.WebSocket> Function(String url, {io.CompressionOptions compression});
...@@ -443,6 +447,14 @@ class VMService implements vm_service.VmService { ...@@ -443,6 +447,14 @@ class VMService implements vm_service.VmService {
return _delegateService.onEvent(streamId); return _delegateService.onEvent(streamId);
} }
@override
Future<vm_service.Response> callMethod(String method, {
String isolateId,
Map<dynamic, dynamic> args,
}) {
return _delegateService.callMethod(method, isolateId: isolateId, args: args);
}
StreamController<ServiceEvent> _getEventController(String eventName) { StreamController<ServiceEvent> _getEventController(String eventName) {
StreamController<ServiceEvent> controller = _eventControllers[eventName]; StreamController<ServiceEvent> controller = _eventControllers[eventName];
if (controller == null) { if (controller == null) {
...@@ -1536,43 +1548,56 @@ class FlutterView extends ServiceObject { ...@@ -1536,43 +1548,56 @@ class FlutterView extends ServiceObject {
await subscription.cancel(); await subscription.cancel();
} }
Future<void> setAssetDirectory(Uri assetsDirectory) async { bool get hasIsolate => _uiIsolate != null;
@override
String toString() => id;
}
/// Flutter specific VM Service functionality.
extension FlutterVmService on vm_service.VmService {
/// Set the asset directory for the an attached Flutter view.
Future<void> setAssetDirectory({
@required Uri assetsDirectory,
@required String viewId,
@required String uiIsolateId,
}) async {
assert(assetsDirectory != null); assert(assetsDirectory != null);
await owner.vmService.vm.invokeRpc<ServiceObject>('_flutter.setAssetBundlePath', await callMethod(kSetAssetBundlePathMethod,
params: <String, dynamic>{ isolateId: uiIsolateId,
'isolateId': _uiIsolate.id, args: <String, dynamic>{
'viewId': id, 'viewId': viewId,
'assetDirectory': assetsDirectory.toFilePath(windows: false), 'assetDirectory': assetsDirectory.toFilePath(windows: false),
}); });
} }
Future<void> setSemanticsEnabled(bool enabled) async { /// Retreive the cached SkSL shaders from an attached Flutter view.
assert(enabled != null); ///
await owner.vmService.vm.invokeRpc<ServiceObject>('_flutter.setSemanticsEnabled', /// This method will only return data if `--cache-sksl` was provided as a
params: <String, dynamic>{ /// flutter run agument, and only then on physical devices.
'isolateId': _uiIsolate.id, Future<Map<String, Object>> getSkSLs({
'viewId': id, @required String viewId,
'enabled': enabled, }) async {
}); final vm_service.Response response = await callMethod(
} kGetSkSLsMethod,
args: <String, String>{
Future<Map<String, Object>> getSkSLs() async { 'viewId': viewId,
final Map<String, dynamic> response = await owner.vmService.vm.invokeRpcRaw(
'_flutter.getSkSLs',
params: <String, dynamic>{
'viewId': id,
}, },
); );
return response['SkSLs'] as Map<String, Object>; return response.json['SkSLs'] as Map<String, Object>;
} }
bool get hasIsolate => _uiIsolate != null; /// Flush all tasks on the UI thead for an attached Flutter view.
///
Future<void> flushUIThreadTasks() async { /// This method is currently used only for benchmarking.
await owner.vm.invokeRpcRaw('_flutter.flushUIThreadTasks', Future<void> flushUIThreadTasks({
params: <String, dynamic>{'isolateId': _uiIsolate.id}); @required String uiIsolateId,
}) async {
await callMethod(
kFlushUIThreadTasksMethod,
args: <String, String>{
'isolateId': uiIsolateId,
},
);
} }
@override
String toString() => id;
} }
...@@ -426,8 +426,13 @@ void main() { ...@@ -426,8 +426,13 @@ void main() {
})); }));
test('ResidentRunner handles writeSkSL returning no data', () => testbed.run(() async { test('ResidentRunner handles writeSkSL returning no data', () => testbed.run(() async {
when(mockFlutterView.getSkSLs()).thenAnswer((Invocation invocation) async { when(mockVMService.callMethod(
return <String, Object>{}; kGetSkSLsMethod,
args: anyNamed('args'),
)).thenAnswer((Invocation invocation) async {
return vm_service.Response.parse(<String, Object>{
'SkSLs': <String, Object>{}
});
}); });
await residentRunner.writeSkSL(); await residentRunner.writeSkSL();
...@@ -439,10 +444,15 @@ void main() { ...@@ -439,10 +444,15 @@ void main() {
return TargetPlatform.android_arm; return TargetPlatform.android_arm;
}); });
when(mockDevice.name).thenReturn('test device'); when(mockDevice.name).thenReturn('test device');
when(mockFlutterView.getSkSLs()).thenAnswer((Invocation invocation) async { when(mockVMService.callMethod(
return <String, Object>{ kGetSkSLsMethod,
'A': 'B', args: anyNamed('args'),
}; )).thenAnswer((Invocation invocation) async {
return vm_service.Response.parse(<String, Object>{
'SkSLs': <String, Object>{
'A': 'B',
}
});
}); });
await residentRunner.writeSkSL(); await residentRunner.writeSkSL();
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:vm_service/vm_service.dart' as vm_service; import 'package:vm_service/vm_service.dart' as vm_service;
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
...@@ -211,6 +213,73 @@ void main() { ...@@ -211,6 +213,73 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FlutterVersion: () => MockFlutterVersion(), FlutterVersion: () => MockFlutterVersion(),
}); });
testWithoutContext('setAssetDirectory forwards arguments correctly', () async {
final Completer<String> completer = Completer<String>();
final vm_service.VmService vmService = vm_service.VmService(
const Stream<String>.empty(),
completer.complete,
);
unawaited(vmService.setAssetDirectory(
assetsDirectory: Uri(path: 'abc', scheme: 'file'),
viewId: 'abc',
uiIsolateId: 'def',
));
final Map<String, Object> rawRequest = json.decode(await completer.future) as Map<String, Object>;
expect(rawRequest, allOf(<Matcher>[
containsPair('method', kSetAssetBundlePathMethod),
containsPair('params', allOf(<Matcher>[
containsPair('viewId', 'abc'),
containsPair('assetDirectory', '/abc'),
containsPair('isolateId', 'def'),
]))
]));
});
testWithoutContext('getSkSLs forwards arguments correctly', () async {
final Completer<String> completer = Completer<String>();
final vm_service.VmService vmService = vm_service.VmService(
const Stream<String>.empty(),
completer.complete,
);
unawaited(vmService.getSkSLs(
viewId: 'abc',
));
final Map<String, Object> rawRequest = json.decode(await completer.future) as Map<String, Object>;
expect(rawRequest, allOf(<Matcher>[
containsPair('method', kGetSkSLsMethod),
containsPair('params', allOf(<Matcher>[
containsPair('viewId', 'abc'),
]))
]));
});
testWithoutContext('flushUIThreadTasks forwards arguments correctly', () async {
final Completer<String> completer = Completer<String>();
final vm_service.VmService vmService = vm_service.VmService(
const Stream<String>.empty(),
completer.complete,
);
unawaited(vmService.flushUIThreadTasks(
uiIsolateId: 'def',
));
final Map<String, Object> rawRequest = json.decode(await completer.future) as Map<String, Object>;
expect(rawRequest, allOf(<Matcher>[
containsPair('method', kFlushUIThreadTasksMethod),
containsPair('params', allOf(<Matcher>[
containsPair('isolateId', 'def'),
]))
]));
});
} }
class MockDevice extends Mock implements Device {} class MockDevice extends Mock implements Device {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment