Skip to content

Commit 6cd4fa4

Browse files
authored
Add --serve-observatory flag to run, attach, and test (#118402)
This flag will allow for Observatory to be served by the VM service once it is disabled by default in the Dart SDK.
1 parent cd34fa6 commit 6cd4fa4

16 files changed

+308
-20
lines changed

packages/flutter_tools/lib/src/base/dds.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,8 @@ class DartDevelopmentService {
9696
}
9797

9898
Future<void> shutdown() async => _ddsInstance?.shutdown();
99+
100+
void setExternalDevToolsUri(Uri uri) {
101+
_ddsInstance?.setExternalDevToolsUri(uri);
102+
}
99103
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class AttachCommand extends FlutterCommand {
139139
usesTrackWidgetCreation(verboseHelp: verboseHelp);
140140
addDdsOptions(verboseHelp: verboseHelp);
141141
addDevToolsOptions(verboseHelp: verboseHelp);
142+
addServeObservatoryOptions(verboseHelp: verboseHelp);
142143
usesDeviceTimeoutOption();
143144
}
144145

@@ -200,6 +201,8 @@ known, it can be explicitly provided to attach via the command-line, e.g.
200201
return uri;
201202
}
202203

204+
bool get serveObservatory => boolArg('serve-observatory') ?? false;
205+
203206
String? get appId {
204207
return stringArgDeprecated('app-id');
205208
}
@@ -514,6 +517,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
514517
enableDds: enableDds,
515518
ddsPort: ddsPort,
516519
devToolsServerAddress: devToolsServerAddress,
520+
serveObservatory: serveObservatory,
517521
);
518522

519523
return buildInfo.isDebug

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
179179
usesDeviceTimeoutOption();
180180
addDdsOptions(verboseHelp: verboseHelp);
181181
addDevToolsOptions(verboseHelp: verboseHelp);
182+
addServeObservatoryOptions(verboseHelp: verboseHelp);
182183
addAndroidSpecificBuildOptions(hide: !verboseHelp);
183184
usesFatalWarningsOption(verboseHelp: verboseHelp);
184185
addEnableImpellerFlag(verboseHelp: verboseHelp);
@@ -279,6 +280,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
279280
nativeNullAssertions: boolArgDeprecated('native-null-assertions'),
280281
enableImpeller: enableImpeller,
281282
uninstallFirst: uninstallFirst,
283+
serveObservatory: boolArgDeprecated('serve-observatory'),
282284
enableDartProfiling: enableDartProfiling,
283285
);
284286
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
215215
'or as the string "none" to disable the timeout entirely.',
216216
);
217217
addDdsOptions(verboseHelp: verboseHelp);
218+
addServeObservatoryOptions(verboseHelp: verboseHelp);
218219
usesFatalWarningsOption(verboseHelp: verboseHelp);
219220
}
220221

@@ -404,6 +405,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
404405
buildInfo,
405406
startPaused: startPaused,
406407
disableServiceAuthCodes: boolArgDeprecated('disable-service-auth-codes'),
408+
serveObservatory: boolArgDeprecated('serve-observatory'),
407409
// On iOS >=14, keeping this enabled will leave a prompt on the screen.
408410
disablePortPublication: true,
409411
enableDds: enableDds,

packages/flutter_tools/lib/src/device.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ class DebuggingOptions {
754754
this.nativeNullAssertions = false,
755755
this.enableImpeller = false,
756756
this.uninstallFirst = false,
757+
this.serveObservatory = true,
757758
this.enableDartProfiling = true,
758759
}) : debuggingEnabled = true;
759760

@@ -799,7 +800,8 @@ class DebuggingOptions {
799800
fastStart = false,
800801
webEnableExpressionEvaluation = false,
801802
nullAssertions = false,
802-
nativeNullAssertions = false;
803+
nativeNullAssertions = false,
804+
serveObservatory = false;
803805

804806
DebuggingOptions._({
805807
required this.buildInfo,
@@ -844,6 +846,7 @@ class DebuggingOptions {
844846
required this.nativeNullAssertions,
845847
required this.enableImpeller,
846848
required this.uninstallFirst,
849+
required this.serveObservatory,
847850
required this.enableDartProfiling,
848851
});
849852

@@ -880,6 +883,7 @@ class DebuggingOptions {
880883
final bool webUseSseForDebugBackend;
881884
final bool webUseSseForInjectedClient;
882885
final bool enableImpeller;
886+
final bool serveObservatory;
883887
final bool enableDartProfiling;
884888

885889
/// Whether the tool should try to uninstall a previously installed version of the app.
@@ -1008,6 +1012,7 @@ class DebuggingOptions {
10081012
'nullAssertions': nullAssertions,
10091013
'nativeNullAssertions': nativeNullAssertions,
10101014
'enableImpeller': enableImpeller,
1015+
'serveObservatory': serveObservatory,
10111016
'enableDartProfiling': enableDartProfiling,
10121017
};
10131018

@@ -1055,6 +1060,7 @@ class DebuggingOptions {
10551060
nativeNullAssertions: json['nativeNullAssertions']! as bool,
10561061
enableImpeller: (json['enableImpeller'] as bool?) ?? false,
10571062
uninstallFirst: (json['uninstallFirst'] as bool?) ?? false,
1063+
serveObservatory: (json['serveObservatory'] as bool?) ?? false,
10581064
enableDartProfiling: (json['enableDartProfiling'] as bool?) ?? true,
10591065
);
10601066
}

packages/flutter_tools/lib/src/resident_devtools_handler.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
9191
final List<FlutterDevice?> devicesWithExtension = await _devicesWithExtensions(flutterDevices);
9292
await _maybeCallDevToolsUriServiceExtension(devicesWithExtension);
9393
await _callConnectedVmServiceUriExtension(devicesWithExtension);
94+
95+
for (final FlutterDevice? device in devicesWithExtension) {
96+
if (device == null) {
97+
continue;
98+
}
99+
// Notify the DDS instances that there's a DevTools instance available so they can correctly
100+
// redirect DevTools related requests.
101+
device.device?.dds.setExternalDevToolsUri(_devToolsLauncher!.devToolsUrl!);
102+
}
103+
94104
if (_shutdown) {
95105
// If we're shutting down, no point reporting the debugger list.
96106
return;

packages/flutter_tools/lib/src/resident_runner.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,26 @@ abstract class ResidentRunner extends ResidentHandlers {
14021402
_finished.complete(0);
14031403
}
14041404

1405+
Future<void> enableObservatory() async {
1406+
assert(debuggingOptions.serveObservatory);
1407+
final List<Future<vm_service.Response?>> serveObservatoryRequests = <Future<vm_service.Response?>>[];
1408+
for (final FlutterDevice? device in flutterDevices) {
1409+
if (device == null) {
1410+
continue;
1411+
}
1412+
// Notify the VM service if the user wants Observatory to be served.
1413+
serveObservatoryRequests.add(
1414+
device.vmService?.callMethodWrapper('_serveObservatory') ??
1415+
Future<vm_service.Response?>.value(),
1416+
);
1417+
}
1418+
try {
1419+
await Future.wait(serveObservatoryRequests);
1420+
} on vm_service.RPCError catch(e) {
1421+
globals.printWarning('Unable to enable Observatory: $e');
1422+
}
1423+
}
1424+
14051425
void appFinished() {
14061426
if (_finished.isCompleted) {
14071427
return;

packages/flutter_tools/lib/src/run_cold.dart

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,17 @@ class ColdRunner extends ResidentRunner {
8080
}
8181
}
8282

83-
if (enableDevTools && debuggingEnabled) {
84-
// The method below is guaranteed never to return a failing future.
85-
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
86-
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
87-
flutterDevices: flutterDevices,
88-
));
83+
if (debuggingEnabled) {
84+
if (enableDevTools) {
85+
// The method below is guaranteed never to return a failing future.
86+
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
87+
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
88+
flutterDevices: flutterDevices,
89+
));
90+
}
91+
if (debuggingOptions.serveObservatory) {
92+
await enableObservatory();
93+
}
8994
}
9095

9196
if (flutterDevices.first.observatoryUris != null) {
@@ -162,12 +167,17 @@ class ColdRunner extends ResidentRunner {
162167
}
163168
}
164169

165-
if (enableDevTools && debuggingEnabled) {
166-
// The method below is guaranteed never to return a failing future.
167-
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
168-
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
169-
flutterDevices: flutterDevices,
170-
));
170+
if (debuggingEnabled) {
171+
if (enableDevTools) {
172+
// The method below is guaranteed never to return a failing future.
173+
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
174+
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
175+
flutterDevices: flutterDevices,
176+
));
177+
}
178+
if (debuggingOptions.serveObservatory) {
179+
await enableObservatory();
180+
}
171181
}
172182

173183
appStartedCompleter?.complete();

packages/flutter_tools/lib/src/run_hot.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ class HotRunner extends ResidentRunner {
237237
return 2;
238238
}
239239

240+
if (debuggingOptions.serveObservatory) {
241+
await enableObservatory();
242+
}
243+
240244
if (enableDevTools) {
241245
// The method below is guaranteed never to return a failing future.
242246
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(

packages/flutter_tools/lib/src/runner/flutter_command.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,14 @@ abstract class FlutterCommand extends Command<void> {
458458
);
459459
}
460460

461+
void addServeObservatoryOptions({required bool verboseHelp}) {
462+
argParser.addFlag('serve-observatory',
463+
hide: !verboseHelp,
464+
defaultsTo: true,
465+
help: 'Serve the legacy Observatory developer tooling through the VM service.',
466+
);
467+
}
468+
461469
late final bool enableDds = () {
462470
bool ddsEnabled = false;
463471
if (argResults?.wasParsed('disable-dds') ?? false) {

packages/flutter_tools/lib/src/test/flutter_tester_device.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:dds/dds.dart';
1111
import 'package:meta/meta.dart';
1212
import 'package:process/process.dart';
1313
import 'package:stream_channel/stream_channel.dart';
14+
import 'package:vm_service/vm_service.dart' as vm_service;
1415

1516
import '../base/file_system.dart';
1617
import '../base/io.dart';
@@ -180,8 +181,15 @@ class FlutterTesterTestDevice extends TestDevice {
180181
compileExpression: compileExpression,
181182
logger: logger,
182183
);
183-
unawaited(localVmService.then((FlutterVmService vmservice) {
184+
unawaited(localVmService.then((FlutterVmService vmservice) async {
184185
logger.printTrace('test $id: Successfully connected to service protocol: $forwardingUri');
186+
if (debuggingOptions.serveObservatory) {
187+
try {
188+
await vmservice.callMethodWrapper('_serveObservatory');
189+
} on vm_service.RPCError {
190+
logger.printWarning('Unable to enable Observatory');
191+
}
192+
}
185193
}));
186194

187195
if (debuggingOptions.startPaused && !machine!) {
@@ -190,6 +198,7 @@ class FlutterTesterTestDevice extends TestDevice {
190198
logger.printStatus(' $forwardingUri');
191199
logger.printStatus('You should first set appropriate breakpoints, then resume the test in the debugger.');
192200
}
201+
193202
_gotProcessObservatoryUri.complete(forwardingUri);
194203
},
195204
);

packages/flutter_tools/test/general.shard/resident_devtools_handler_test.dart

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66

7+
import 'package:flutter_tools/src/base/dds.dart';
78
import 'package:flutter_tools/src/base/logger.dart';
89
import 'package:flutter_tools/src/build_info.dart';
910
import 'package:flutter_tools/src/cache.dart';
@@ -110,7 +111,9 @@ void main() {
110111

111112
testWithoutContext('serveAndAnnounceDevTools with attached device does not fail on null vm service', () async {
112113
final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler(
113-
FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080),
114+
FakeDevtoolsLauncher()
115+
..activeDevToolsServer = DevToolsServerAddress('localhost', 8080)
116+
..devToolsUrl = Uri.parse('http://localhost:8080'),
114117
FakeResidentRunner(),
115118
BufferLogger.test(),
116119
);
@@ -125,7 +128,9 @@ void main() {
125128

126129
testWithoutContext('serveAndAnnounceDevTools with invokes devtools and vm_service setter', () async {
127130
final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler(
128-
FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080),
131+
FakeDevtoolsLauncher()
132+
..activeDevToolsServer = DevToolsServerAddress('localhost', 8080)
133+
..devToolsUrl = Uri.parse('http://localhost:8080'),
129134
FakeResidentRunner(),
130135
BufferLogger.test(),
131136
);
@@ -194,7 +199,9 @@ void main() {
194199

195200
testWithoutContext('serveAndAnnounceDevTools with web device', () async {
196201
final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler(
197-
FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080),
202+
FakeDevtoolsLauncher()
203+
..activeDevToolsServer = DevToolsServerAddress('localhost', 8080)
204+
..devToolsUrl = Uri.parse('http://localhost:8080'),
198205
FakeResidentRunner(),
199206
BufferLogger.test(),
200207
);
@@ -278,7 +285,9 @@ void main() {
278285

279286
testWithoutContext('serveAndAnnounceDevTools with multiple devices and VM service disappears on one', () async {
280287
final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler(
281-
FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080),
288+
FakeDevtoolsLauncher()
289+
..activeDevToolsServer = DevToolsServerAddress('localhost', 8080)
290+
..devToolsUrl = Uri.parse('http://localhost:8080'),
282291
FakeResidentRunner(),
283292
BufferLogger.test(),
284293
);
@@ -442,6 +451,9 @@ class FakeResidentRunner extends Fake implements ResidentRunner {
442451

443452
@override
444453
bool reportedDebuggers = false;
454+
455+
@override
456+
DebuggingOptions debuggingOptions = DebuggingOptions.disabled(BuildInfo.debug);
445457
}
446458

447459
class FakeFlutterDevice extends Fake implements FlutterDevice {
@@ -458,4 +470,35 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
458470
// Unfortunately Device, despite not being immutable, has an `operator ==`.
459471
// Until we fix that, we have to also ignore related lints here.
460472
// ignore: avoid_implementing_value_types
461-
class FakeDevice extends Fake implements Device { }
473+
class FakeDevice extends Fake implements Device {
474+
@override
475+
DartDevelopmentService get dds => FakeDartDevelopmentService();
476+
}
477+
478+
class FakeDartDevelopmentService extends Fake implements DartDevelopmentService {
479+
bool started = false;
480+
bool disposed = false;
481+
482+
@override
483+
final Uri uri = Uri.parse('http://127.0.0.1:1234/');
484+
485+
@override
486+
Future<void> startDartDevelopmentService(
487+
Uri observatoryUri, {
488+
required Logger logger,
489+
int? hostPort,
490+
bool? ipv6,
491+
bool? disableServiceAuthCodes,
492+
bool cacheStartupProfile = false,
493+
}) async {
494+
started = true;
495+
}
496+
497+
@override
498+
Future<void> shutdown() async {
499+
disposed = true;
500+
}
501+
502+
@override
503+
void setExternalDevToolsUri(Uri uri) {}
504+
}

0 commit comments

Comments
 (0)