Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3dba3f2

Browse files
authored
Update proxied devices to handle connection interface and diagnostics. (#145061)
Also improve the performance of daemon device discovery by parallelizing the calls.
1 parent 1908744 commit 3dba3f2

File tree

7 files changed

+159
-4
lines changed

7 files changed

+159
-4
lines changed

packages/flutter_tools/lib/src/commands/daemon.dart

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,7 @@ class DeviceDomain extends Domain {
10081008
registerHandler('startDartDevelopmentService', startDartDevelopmentService);
10091009
registerHandler('shutdownDartDevelopmentService', shutdownDartDevelopmentService);
10101010
registerHandler('setExternalDevToolsUriForDartDevelopmentService', setExternalDevToolsUriForDartDevelopmentService);
1011+
registerHandler('getDiagnostics', getDiagnostics);
10111012

10121013
// Use the device manager discovery so that client provided device types
10131014
// are usable via the daemon protocol.
@@ -1059,12 +1060,23 @@ class DeviceDomain extends Domain {
10591060
}
10601061

10611062
/// Return a list of the current devices, discarding existing cache of devices.
1062-
Future<List<Map<String, Object?>>> discoverDevices([ Map<String, Object?>? args ]) async {
1063-
return <Map<String, Object?>>[
1063+
Future<List<Map<String, Object?>>> discoverDevices(Map<String, Object?> args) async {
1064+
final int? timeoutInMilliseconds = _getIntArg(args, 'timeoutInMilliseconds');
1065+
final Duration? timeout = timeoutInMilliseconds != null ? Duration(milliseconds: timeoutInMilliseconds) : null;
1066+
1067+
// Calling `discoverDevices()` and `_deviceToMap()` in parallel for better performance.
1068+
final List<List<Device>> devicesListList = await Future.wait(<Future<List<Device>>>[
10641069
for (final PollingDeviceDiscovery discoverer in _discoverers)
1065-
for (final Device device in await discoverer.discoverDevices())
1066-
await _deviceToMap(device),
1070+
discoverer.discoverDevices(timeout: timeout),
1071+
]);
1072+
1073+
final List<Device> devices = <Device>[
1074+
for (final List<Device> devicesList in devicesListList)
1075+
...devicesList,
10671076
];
1077+
return Future.wait(<Future<Map<String, Object?>>>[
1078+
for (final Device device in devices) _deviceToMap(device),
1079+
]);
10681080
}
10691081

10701082
/// Enable device events.
@@ -1298,6 +1310,21 @@ class DeviceDomain extends Domain {
12981310
}
12991311
return null;
13001312
}
1313+
1314+
/// Gets a list of diagnostic messages pertaining to issues with any connected
1315+
/// devices.
1316+
Future<List<String>> getDiagnostics(Map<String, Object?> args) async {
1317+
// Call `getDiagnostics()` in parallel to improve performance.
1318+
final List<List<String>> diagnosticsLists = await Future.wait(<Future<List<String>>>[
1319+
for (final PollingDeviceDiscovery discoverer in _discoverers)
1320+
discoverer.getDiagnostics(),
1321+
]);
1322+
1323+
return <String>[
1324+
for (final List<String> diagnostics in diagnosticsLists)
1325+
...diagnostics,
1326+
];
1327+
}
13011328
}
13021329

13031330
class DevToolsDomain extends Domain {
@@ -1333,6 +1360,8 @@ Future<Map<String, Object?>> _deviceToMap(Device device) async {
13331360
'ephemeral': device.ephemeral,
13341361
'emulatorId': await device.emulatorId,
13351362
'sdk': await device.sdkNameAndVersion,
1363+
'isConnected': device.isConnected,
1364+
'connectionInterface': getNameForDeviceConnectionInterface(device.connectionInterface),
13361365
'capabilities': <String, Object>{
13371366
'hotReload': device.supportsHotReload,
13381367
'hotRestart': device.supportsHotRestart,

packages/flutter_tools/lib/src/device.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,27 @@ enum DeviceConnectionInterface {
586586
wireless,
587587
}
588588

589+
/// Returns the `DeviceConnectionInterface` enum based on its string name.
590+
DeviceConnectionInterface getDeviceConnectionInterfaceForName(String name) {
591+
switch (name) {
592+
case 'attached':
593+
return DeviceConnectionInterface.attached;
594+
case 'wireless':
595+
return DeviceConnectionInterface.wireless;
596+
}
597+
throw Exception('Unsupported DeviceConnectionInterface name "$name"');
598+
}
599+
600+
/// Returns a `DeviceConnectionInterface`'s string name.
601+
String getNameForDeviceConnectionInterface(DeviceConnectionInterface connectionInterface) {
602+
switch (connectionInterface) {
603+
case DeviceConnectionInterface.attached:
604+
return 'attached';
605+
case DeviceConnectionInterface.wireless:
606+
return 'wireless';
607+
}
608+
}
609+
589610
/// A device is a physical hardware that can run a Flutter application.
590611
///
591612
/// This may correspond to a connected iOS or Android device, or represent

packages/flutter_tools/lib/src/proxied_devices/devices.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ class ProxiedDevices extends PollingDeviceDiscovery {
102102
@visibleForTesting
103103
ProxiedDevice deviceFromDaemonResult(Map<String, Object?> device) {
104104
final Map<String, Object?> capabilities = _cast<Map<String, Object?>>(device['capabilities']);
105+
final String? connectionInterfaceName = _cast<String?>(device['connectionInterface']);
106+
final DeviceConnectionInterface? connectionInterface = connectionInterfaceName != null ? getDeviceConnectionInterfaceForName(connectionInterfaceName) : null;
105107
return ProxiedDevice(
106108
connection, _cast<String>(device['id']),
107109
deltaFileTransfer: _deltaFileTransfer,
@@ -110,6 +112,8 @@ class ProxiedDevices extends PollingDeviceDiscovery {
110112
platformType: PlatformType.fromString(_cast<String>(device['platformType'])),
111113
targetPlatform: getTargetPlatformForName(_cast<String>(device['platform'])),
112114
ephemeral: _cast<bool>(device['ephemeral']),
115+
isConnected: _cast<bool?>(device['isConnected']) ?? true,
116+
connectionInterface: connectionInterface ?? DeviceConnectionInterface.attached,
113117
name: 'Proxied ${device['name']}',
114118
isLocalEmulator: _cast<bool>(device['emulator']),
115119
emulatorId: _cast<String?>(device['emulatorId']),
@@ -124,6 +128,21 @@ class ProxiedDevices extends PollingDeviceDiscovery {
124128
fileTransfer: _fileTransfer,
125129
);
126130
}
131+
132+
@override
133+
Future<List<String>> getDiagnostics() async {
134+
try {
135+
final List<String> diagnostics = _cast<List<dynamic>>(await connection.sendRequest('device.getDiagnostics')).cast<String>();
136+
return diagnostics;
137+
} on String catch (e) { // Daemon actually does throw string types.
138+
if (e.contains('command not understood')) {
139+
_logger.printTrace('The daemon is on an older version that does not support `device.getDiagnostics`.');
140+
// Silently ignore.
141+
return <String>[];
142+
}
143+
rethrow;
144+
}
145+
}
127146
}
128147

129148
/// A [Device] that acts as a proxy to remotely connected device.
@@ -143,6 +162,8 @@ class ProxiedDevice extends Device {
143162
required PlatformType? platformType,
144163
required TargetPlatform targetPlatform,
145164
required bool ephemeral,
165+
required this.isConnected,
166+
required this.connectionInterface,
146167
required this.name,
147168
required bool isLocalEmulator,
148169
required String? emulatorId,
@@ -180,6 +201,12 @@ class ProxiedDevice extends Device {
180201

181202
final FileTransfer _fileTransfer;
182203

204+
@override
205+
final bool isConnected;
206+
207+
@override
208+
final DeviceConnectionInterface connectionInterface;
209+
183210
@override
184211
final String name;
185212

packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ void main() {
459459
'ephemeral': false,
460460
'emulatorId': 'device',
461461
'sdk': 'Android 12',
462+
'isConnected': true,
463+
'connectionInterface': 'attached',
462464
'capabilities': <String, Object?>{
463465
'hotReload': true,
464466
'hotRestart': true,
@@ -479,6 +481,8 @@ void main() {
479481
'ephemeral': false,
480482
'emulatorId': null,
481483
'sdk': 'preview',
484+
'isConnected': true,
485+
'connectionInterface': 'attached',
482486
'capabilities': <String, Object?>{
483487
'hotReload': true,
484488
'hotRestart': true,
@@ -725,6 +729,31 @@ void main() {
725729
expect(device.dds.shutdownCalled, true);
726730
});
727731

732+
testUsingContext('device.getDiagnostics returns correct value', () async {
733+
daemon = Daemon(
734+
daemonConnection,
735+
notifyingLogger: notifyingLogger,
736+
);
737+
final FakePollingDeviceDiscovery discoverer1 = FakePollingDeviceDiscovery();
738+
discoverer1.diagnostics = <String>['fake diagnostic 1', 'fake diagnostic 2'];
739+
final FakePollingDeviceDiscovery discoverer2 = FakePollingDeviceDiscovery();
740+
discoverer2.diagnostics = <String>['fake diagnostic 3', 'fake diagnostic 4'];
741+
daemon.deviceDomain.addDeviceDiscoverer(discoverer1);
742+
daemon.deviceDomain.addDeviceDiscoverer(discoverer2);
743+
daemonStreams.inputs.add(DaemonMessage(<String, Object?>{
744+
'id': 0,
745+
'method': 'device.getDiagnostics',
746+
}));
747+
final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent);
748+
expect(response.data['id'], 0);
749+
expect(response.data['result'], <String>[
750+
'fake diagnostic 1',
751+
'fake diagnostic 2',
752+
'fake diagnostic 3',
753+
'fake diagnostic 4',
754+
]);
755+
});
756+
728757
testUsingContext('emulator.launch without an emulatorId should report an error', () async {
729758
daemon = Daemon(
730759
daemonConnection,
@@ -1128,6 +1157,9 @@ class FakeAndroidDevice extends Fake implements AndroidDevice {
11281157
@override
11291158
final bool isConnected = true;
11301159

1160+
@override
1161+
final DeviceConnectionInterface connectionInterface = DeviceConnectionInterface.attached;
1162+
11311163
@override
11321164
Future<String> get sdkNameAndVersion async => 'Android 12';
11331165

packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ class FakeAndroidDevice extends Fake implements AndroidDevice {
274274
@override
275275
bool get isConnected => true;
276276

277+
@override
278+
final DeviceConnectionInterface connectionInterface = DeviceConnectionInterface.attached;
279+
277280
@override
278281
Future<String> get sdkNameAndVersion async => 'Android 12';
279282

packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,44 @@ void main() {
562562
expect(devicesAdded[0].id, fakeDevice['id']);
563563
expect(devicesAdded[1].id, fakeDevice2['id']);
564564
});
565+
566+
testWithoutContext('handles getDiagnostics', () async {
567+
bufferLogger = BufferLogger.test();
568+
final ProxiedDevices proxiedDevices = ProxiedDevices(
569+
clientDaemonConnection,
570+
logger: bufferLogger,
571+
);
572+
573+
final Future<List<String>> resultFuture = proxiedDevices.getDiagnostics();
574+
575+
final DaemonMessage message = await serverDaemonConnection.incomingCommands.first;
576+
expect(message.data['id'], isNotNull);
577+
expect(message.data['method'], 'device.getDiagnostics');
578+
579+
serverDaemonConnection.sendResponse(message.data['id']!, <String>['1', '2']);
580+
581+
final List<String> result = await resultFuture;
582+
expect(result, <String>['1', '2']);
583+
});
584+
585+
testWithoutContext('returns empty result when daemon does not understand getDiagnostics', () async {
586+
bufferLogger = BufferLogger.test();
587+
final ProxiedDevices proxiedDevices = ProxiedDevices(
588+
clientDaemonConnection,
589+
logger: bufferLogger,
590+
);
591+
592+
final Future<List<String>> resultFuture = proxiedDevices.getDiagnostics();
593+
594+
final DaemonMessage message = await serverDaemonConnection.incomingCommands.first;
595+
expect(message.data['id'], isNotNull);
596+
expect(message.data['method'], 'device.getDiagnostics');
597+
598+
serverDaemonConnection.sendErrorResponse(message.data['id']!, 'command not understood: device.getDiagnostics', StackTrace.current);
599+
600+
final List<String> result = await resultFuture;
601+
expect(result, isEmpty);
602+
});
565603
});
566604

567605
group('ProxiedDartDevelopmentService', () {

packages/flutter_tools/test/src/fake_devices.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ class FakePollingDeviceDiscovery extends PollingDeviceDiscovery {
269269

270270
@override
271271
List<String> wellKnownIds = <String>[];
272+
273+
List<String> diagnostics = <String>[];
274+
275+
@override
276+
Future<List<String>> getDiagnostics() => Future<List<String>>.value(diagnostics);
272277
}
273278

274279
/// A fake implementation of the [DeviceLogReader].

0 commit comments

Comments
 (0)