Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit b187bc4

Browse files
authored
Switch the way we retrieve the vm_service_port from /hub to iquery, on device. (#114637)
* [fuchsia_remote_debug_protocol] Switch the way we retrieve the vm_service_port from /hub to iquery, on device. * [fuchsia_remote_debug_protocol] Switch the way we retrieve the vm_service_port from /hub to iquery, on device.
1 parent 6ea01e6 commit b187bc4

File tree

2 files changed

+165
-94
lines changed

2 files changed

+165
-94
lines changed

packages/fuchsia_remote_debug_protocol/lib/src/fuchsia_remote_connection.dart

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6+
import 'dart:convert';
67
import 'dart:io';
78

89
import 'package:process/process.dart';
@@ -506,6 +507,28 @@ class FuchsiaRemoteConnection {
506507
_pollDartVms = true;
507508
}
508509

510+
/// Helper for getDeviceServicePorts() to extract the vm_service_port from
511+
/// json response.
512+
List<int> getVmServicePortFromInspectSnapshot(List<dynamic> inspectSnapshot) {
513+
final ports = <int>[];
514+
for (final item in inspectSnapshot) {
515+
if (item['payload'] == null || !(item as Map).containsKey('payload')) continue;
516+
final payload = item['payload'];
517+
518+
if (payload['root'] == null || !(payload as Map).containsKey('root')) continue;
519+
final root = payload['root'];
520+
521+
if (root['vm_service_port'] == null ||
522+
!(root as Map).containsKey('vm_service_port')) continue;
523+
524+
final int? port = int.tryParse(root['vm_service_port']);
525+
if (port != null) {
526+
ports.add(port);
527+
}
528+
}
529+
return ports;
530+
}
531+
509532
/// Gets the open Dart VM service ports on a remote Fuchsia device.
510533
///
511534
/// The method attempts to get service ports through an SSH connection. Upon
@@ -514,24 +537,14 @@ class FuchsiaRemoteConnection {
514537
/// found. An exception is thrown in the event of an actual error when
515538
/// attempting to acquire the ports.
516539
Future<List<int>> getDeviceServicePorts() async {
517-
final List<String> portPaths = await _sshCommandRunner
518-
.run('/bin/find /hub -name vmservice-port');
519-
final List<int> ports = <int>[];
520-
for (final String path in portPaths) {
521-
if (path == '') {
522-
continue;
523-
}
524-
final List<String> lsOutput =
525-
await _sshCommandRunner.run('/bin/ls $path');
526-
for (final String line in lsOutput) {
527-
if (line == '') {
528-
continue;
529-
}
530-
final int? port = int.tryParse(line);
531-
if (port != null) {
532-
ports.add(port);
533-
}
534-
}
540+
final inspectResult = await _sshCommandRunner
541+
.run('iquery --format json show \'**:root:vm_service_port\'');
542+
final inspectOutputJson = jsonDecode(inspectResult.join('\n'));
543+
final List<int> ports =
544+
getVmServicePortFromInspectSnapshot(inspectOutputJson);
545+
546+
if (ports.length > 1) {
547+
throw StateError('More than one Flutter observatory port found');
535548
}
536549
return ports;
537550
}

packages/fuchsia_remote_debug_protocol/test/fuchsia_remote_connection_test.dart

Lines changed: 134 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void main() {
8282
restoreVmServiceConnectionFunction();
8383
});
8484

85-
test('end-to-end with three vm connections and flutter view query', () async {
85+
test('end-to-end with one vm connection and flutter view query', () async {
8686
int port = 0;
8787
Future<PortForwarder> fakePortForwardingFunction(
8888
String address,
@@ -102,54 +102,76 @@ void main() {
102102
fuchsiaPortForwardingFunction = fakePortForwardingFunction;
103103
final FakeSshCommandRunner fakeRunner = FakeSshCommandRunner();
104104
// Adds some extra junk to make sure the strings will be cleaned up.
105-
fakeRunner.findResponse = <String>['/hub/blah/blah/blah/vmservice-port\n'];
106-
fakeRunner.lsResponse = <String>['123\n\n\n', '456 ', '789'];
105+
fakeRunner.iqueryResponse = <String>[
106+
'[',
107+
' {',
108+
' "data_source": "Inspect",',
109+
' "metadata": {',
110+
' "filename": "fuchsia.inspect.Tree",',
111+
' "component_url": "fuchsia-pkg://fuchsia.com/flutter_aot_runner#meta/flutter_runner.cm",',
112+
' "timestamp": 12345678901234',
113+
' },',
114+
' "moniker": "core/session-manager/session\:session/flutter_runner",',
115+
' "payload": {',
116+
' "root": {',
117+
' "vm_service_port": "12345",',
118+
' "16859221": {',
119+
' "empty_tree": "this semantic tree is empty"',
120+
' },',
121+
' "build_info": {',
122+
' "dart_sdk_git_revision": "77e83fcc14fa94049f363d554579f48fbd6bb7a1",',
123+
' "dart_sdk_semantic_version": "2.19.0-317.0.dev",',
124+
' "flutter_engine_git_revision": "563b8e830c697a543bf0a8a9f4ae3edfad86ea86",',
125+
' "fuchsia_sdk_version": "10.20221018.0.1"',
126+
' },',
127+
' "vm": {',
128+
' "dst_status": 1,',
129+
' "get_profile_status": 0,',
130+
' "num_get_profile_calls": 1,',
131+
' "num_intl_provider_errors": 0,',
132+
' "num_on_change_calls": 0,',
133+
' "timezone_content_status": 0,',
134+
' "tz_data_close_status": -1,',
135+
' "tz_data_status": -1',
136+
' }',
137+
' }',
138+
' },',
139+
' "version": 1',
140+
' }',
141+
' ]'
142+
];
107143
fakeRunner.address = 'fe80::8eae:4cff:fef4:9247';
108144
fakeRunner.interface = 'eno1';
109145

110146
final FuchsiaRemoteConnection connection =
111147
await FuchsiaRemoteConnection.connectWithSshCommandRunner(fakeRunner);
112148

113-
// [fakePortForwardingFunction] will have returned three different
149+
// [fakePortForwardingFunction] will have returned one
114150
// forwarded ports, incrementing the port each time by one. (Just a sanity
115151
// check that the forwarding port was called).
116-
expect(forwardedPorts.length, 3);
117-
expect(forwardedPorts[0].remotePort, 123);
118-
expect(forwardedPorts[1].remotePort, 456);
119-
expect(forwardedPorts[2].remotePort, 789);
152+
expect(forwardedPorts.length, 1);
153+
expect(forwardedPorts[0].remotePort, 12345);
120154
expect(forwardedPorts[0].port, 0);
121-
expect(forwardedPorts[1].port, 1);
122-
expect(forwardedPorts[2].port, 2);
123155

124156
// VMs should be accessed via localhost ports given by
125157
// [fakePortForwardingFunction].
126158
expect(uriConnections[0],
127-
Uri(scheme:'ws', host:'[::1]', port:0, path:'/ws'));
128-
expect(uriConnections[1],
129-
Uri(scheme:'ws', host:'[::1]', port:1, path:'/ws'));
130-
expect(uriConnections[2],
131-
Uri(scheme:'ws', host:'[::1]', port:2, path:'/ws'));
159+
Uri(scheme: 'ws', host: '[::1]', port: 0, path: '/ws'));
132160

133161
final List<FlutterView> views = await connection.getFlutterViews();
134162
expect(views, isNot(null));
135-
expect(views.length, 3);
163+
expect(views.length, 1);
136164
// Since name can be null, check for the ID on all of them.
137165
expect(views[0].id, 'flutterView0');
138-
expect(views[1].id, 'flutterView1');
139-
expect(views[2].id, 'flutterView2');
140166

141167
expect(views[0].name, equals(null));
142-
expect(views[1].name, 'file://flutterBinary1');
143-
expect(views[2].name, 'file://flutterBinary2');
144168

145169
// Ensure the ports are all closed after stop was called.
146170
await connection.stop();
147171
expect(forwardedPorts[0].stopped, true);
148-
expect(forwardedPorts[1].stopped, true);
149-
expect(forwardedPorts[2].stopped, true);
150172
});
151173

152-
test('end-to-end with three vms and remote open port', () async {
174+
test('end-to-end with one vm and remote open port', () async {
153175
int port = 0;
154176
Future<PortForwarder> fakePortForwardingFunction(
155177
String address,
@@ -170,53 +192,72 @@ void main() {
170192
fuchsiaPortForwardingFunction = fakePortForwardingFunction;
171193
final FakeSshCommandRunner fakeRunner = FakeSshCommandRunner();
172194
// Adds some extra junk to make sure the strings will be cleaned up.
173-
fakeRunner.findResponse = <String>['/hub/blah/blah/blah/vmservice-port\n'];
174-
fakeRunner.lsResponse = <String>['123\n\n\n', '456 ', '789'];
195+
fakeRunner.iqueryResponse = <String>[
196+
'[',
197+
' {',
198+
' "data_source": "Inspect",',
199+
' "metadata": {',
200+
' "filename": "fuchsia.inspect.Tree",',
201+
' "component_url": "fuchsia-pkg://fuchsia.com/flutter_aot_runner#meta/flutter_runner.cm",',
202+
' "timestamp": 12345678901234',
203+
' },',
204+
' "moniker": "core/session-manager/session\:session/flutter_runner",',
205+
' "payload": {',
206+
' "root": {',
207+
' "vm_service_port": "12345",',
208+
' "16859221": {',
209+
' "empty_tree": "this semantic tree is empty"',
210+
' },',
211+
' "build_info": {',
212+
' "dart_sdk_git_revision": "77e83fcc14fa94049f363d554579f48fbd6bb7a1",',
213+
' "dart_sdk_semantic_version": "2.19.0-317.0.dev",',
214+
' "flutter_engine_git_revision": "563b8e830c697a543bf0a8a9f4ae3edfad86ea86",',
215+
' "fuchsia_sdk_version": "10.20221018.0.1"',
216+
' },',
217+
' "vm": {',
218+
' "dst_status": 1,',
219+
' "get_profile_status": 0,',
220+
' "num_get_profile_calls": 1,',
221+
' "num_intl_provider_errors": 0,',
222+
' "num_on_change_calls": 0,',
223+
' "timezone_content_status": 0,',
224+
' "tz_data_close_status": -1,',
225+
' "tz_data_status": -1',
226+
' }',
227+
' }',
228+
' },',
229+
' "version": 1',
230+
' }',
231+
' ]'
232+
];
175233
fakeRunner.address = 'fe80::8eae:4cff:fef4:9247';
176234
fakeRunner.interface = 'eno1';
177235
final FuchsiaRemoteConnection connection =
178236
await FuchsiaRemoteConnection.connectWithSshCommandRunner(fakeRunner);
179237

180-
// [fakePortForwardingFunction] will have returned three different
181-
// forwarded ports, incrementing the port each time by one. (Just a sanity
182-
// check that the forwarding port was called).
183-
expect(forwardedPorts.length, 3);
184-
expect(forwardedPorts[0].remotePort, 123);
185-
expect(forwardedPorts[1].remotePort, 456);
186-
expect(forwardedPorts[2].remotePort, 789);
238+
expect(forwardedPorts.length, 1);
239+
expect(forwardedPorts[0].remotePort, 12345);
187240
expect(forwardedPorts[0].port, 0);
188-
expect(forwardedPorts[1].port, 1);
189-
expect(forwardedPorts[2].port, 2);
190241

191242
// VMs should be accessed via the alternate address given by
192243
// [fakePortForwardingFunction].
193244
expect(uriConnections[0],
194-
Uri(scheme:'ws', host:'[fe80::1:2%25eno2]', port:0, path:'/ws'));
195-
expect(uriConnections[1],
196-
Uri(scheme:'ws', host:'[fe80::1:2%25eno2]', port:1, path:'/ws'));
197-
expect(uriConnections[2],
198-
Uri(scheme:'ws', host:'[fe80::1:2%25eno2]', port:2, path:'/ws'));
245+
Uri(scheme: 'ws', host: '[fe80::1:2%25eno2]', port: 0, path: '/ws'));
199246

200247
final List<FlutterView> views = await connection.getFlutterViews();
201248
expect(views, isNot(null));
202-
expect(views.length, 3);
249+
expect(views.length, 1);
203250
// Since name can be null, check for the ID on all of them.
204251
expect(views[0].id, 'flutterView0');
205-
expect(views[1].id, 'flutterView1');
206-
expect(views[2].id, 'flutterView2');
207252

208253
expect(views[0].name, equals(null));
209-
expect(views[1].name, 'file://flutterBinary1');
210-
expect(views[2].name, 'file://flutterBinary2');
211254

212255
// Ensure the ports are all closed after stop was called.
213256
await connection.stop();
214257
expect(forwardedPorts[0].stopped, true);
215-
expect(forwardedPorts[1].stopped, true);
216-
expect(forwardedPorts[2].stopped, true);
217258
});
218259

219-
test('end-to-end with three vms and ipv4', () async {
260+
test('end-to-end with one vm and ipv4', () async {
220261
int port = 0;
221262
Future<PortForwarder> fakePortForwardingFunction(
222263
String address,
@@ -236,8 +277,44 @@ void main() {
236277
fuchsiaPortForwardingFunction = fakePortForwardingFunction;
237278
final FakeSshCommandRunner fakeRunner = FakeSshCommandRunner();
238279
// Adds some extra junk to make sure the strings will be cleaned up.
239-
fakeRunner.findResponse = <String>['/hub/blah/blah/blah/vmservice-port\n'];
240-
fakeRunner.lsResponse = <String>['123\n\n\n', '456 ', '789'];
280+
fakeRunner.iqueryResponse = <String>[
281+
'[',
282+
' {',
283+
' "data_source": "Inspect",',
284+
' "metadata": {',
285+
' "filename": "fuchsia.inspect.Tree",',
286+
' "component_url": "fuchsia-pkg://fuchsia.com/flutter_aot_runner#meta/flutter_runner.cm",',
287+
' "timestamp": 12345678901234',
288+
' },',
289+
' "moniker": "core/session-manager/session\:session/flutter_runner",',
290+
' "payload": {',
291+
' "root": {',
292+
' "vm_service_port": "12345",',
293+
' "16859221": {',
294+
' "empty_tree": "this semantic tree is empty"',
295+
' },',
296+
' "build_info": {',
297+
' "dart_sdk_git_revision": "77e83fcc14fa94049f363d554579f48fbd6bb7a1",',
298+
' "dart_sdk_semantic_version": "2.19.0-317.0.dev",',
299+
' "flutter_engine_git_revision": "563b8e830c697a543bf0a8a9f4ae3edfad86ea86",',
300+
' "fuchsia_sdk_version": "10.20221018.0.1"',
301+
' },',
302+
' "vm": {',
303+
' "dst_status": 1,',
304+
' "get_profile_status": 0,',
305+
' "num_get_profile_calls": 1,',
306+
' "num_intl_provider_errors": 0,',
307+
' "num_on_change_calls": 0,',
308+
' "timezone_content_status": 0,',
309+
' "tz_data_close_status": -1,',
310+
' "tz_data_status": -1',
311+
' }',
312+
' }',
313+
' },',
314+
' "version": 1',
315+
' }',
316+
' ]'
317+
];
241318
fakeRunner.address = '196.168.1.4';
242319

243320
final FuchsiaRemoteConnection connection =
@@ -246,39 +323,25 @@ void main() {
246323
// [fakePortForwardingFunction] will have returned three different
247324
// forwarded ports, incrementing the port each time by one. (Just a sanity
248325
// check that the forwarding port was called).
249-
expect(forwardedPorts.length, 3);
250-
expect(forwardedPorts[0].remotePort, 123);
251-
expect(forwardedPorts[1].remotePort, 456);
252-
expect(forwardedPorts[2].remotePort, 789);
326+
expect(forwardedPorts.length, 1);
327+
expect(forwardedPorts[0].remotePort, 12345);
253328
expect(forwardedPorts[0].port, 0);
254-
expect(forwardedPorts[1].port, 1);
255-
expect(forwardedPorts[2].port, 2);
256329

257330
// VMs should be accessed via the ipv4 loopback.
258331
expect(uriConnections[0],
259-
Uri(scheme:'ws', host:'127.0.0.1', port:0, path:'/ws'));
260-
expect(uriConnections[1],
261-
Uri(scheme:'ws', host:'127.0.0.1', port:1, path:'/ws'));
262-
expect(uriConnections[2],
263-
Uri(scheme:'ws', host:'127.0.0.1', port:2, path:'/ws'));
332+
Uri(scheme: 'ws', host: '127.0.0.1', port: 0, path: '/ws'));
264333

265334
final List<FlutterView> views = await connection.getFlutterViews();
266335
expect(views, isNot(null));
267-
expect(views.length, 3);
336+
expect(views.length, 1);
268337
// Since name can be null, check for the ID on all of them.
269338
expect(views[0].id, 'flutterView0');
270-
expect(views[1].id, 'flutterView1');
271-
expect(views[2].id, 'flutterView2');
272339

273340
expect(views[0].name, equals(null));
274-
expect(views[1].name, 'file://flutterBinary1');
275-
expect(views[2].name, 'file://flutterBinary2');
276341

277342
// Ensure the ports are all closed after stop was called.
278343
await connection.stop();
279344
expect(forwardedPorts[0].stopped, true);
280-
expect(forwardedPorts[1].stopped, true);
281-
expect(forwardedPorts[2].stopped, true);
282345
});
283346

284347
test('env variable test without remote addr', () async {
@@ -287,22 +350,17 @@ void main() {
287350
}
288351

289352
// Should fail as no env variable has been passed.
290-
expect(failingFunction,
291-
throwsA(isA<FuchsiaRemoteConnectionError>()));
353+
expect(failingFunction, throwsA(isA<FuchsiaRemoteConnectionError>()));
292354
});
293355
});
294356
}
295357

296358
class FakeSshCommandRunner extends Fake implements SshCommandRunner {
297-
List<String>? findResponse;
298-
List<String>? lsResponse;
359+
List<String>? iqueryResponse;
299360
@override
300361
Future<List<String>> run(String command) async {
301-
if (command.startsWith('/bin/find')) {
302-
return findResponse!;
303-
}
304-
if (command.startsWith('/bin/ls')) {
305-
return lsResponse!;
362+
if (command.startsWith('iquery --format json show')) {
363+
return iqueryResponse!;
306364
}
307365
throw UnimplementedError(command);
308366
}

0 commit comments

Comments
 (0)