Skip to content

Commit

Permalink
Add --serve-observatory flag to run, attach, and test (#118402)
Browse files Browse the repository at this point in the history
This flag will allow for Observatory to be served by the VM service once it is disabled by default in the Dart SDK.
  • Loading branch information
bkonyi authored Jan 25, 2023
1 parent cd34fa6 commit 6cd4fa4
Show file tree
Hide file tree
Showing 16 changed files with 308 additions and 20 deletions.
4 changes: 4 additions & 0 deletions packages/flutter_tools/lib/src/base/dds.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,8 @@ class DartDevelopmentService {
}

Future<void> shutdown() async => _ddsInstance?.shutdown();

void setExternalDevToolsUri(Uri uri) {
_ddsInstance?.setExternalDevToolsUri(uri);
}
}
4 changes: 4 additions & 0 deletions packages/flutter_tools/lib/src/commands/attach.dart
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class AttachCommand extends FlutterCommand {
usesTrackWidgetCreation(verboseHelp: verboseHelp);
addDdsOptions(verboseHelp: verboseHelp);
addDevToolsOptions(verboseHelp: verboseHelp);
addServeObservatoryOptions(verboseHelp: verboseHelp);
usesDeviceTimeoutOption();
}

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

bool get serveObservatory => boolArg('serve-observatory') ?? false;

String? get appId {
return stringArgDeprecated('app-id');
}
Expand Down Expand Up @@ -514,6 +517,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
enableDds: enableDds,
ddsPort: ddsPort,
devToolsServerAddress: devToolsServerAddress,
serveObservatory: serveObservatory,
);

return buildInfo.isDebug
Expand Down
2 changes: 2 additions & 0 deletions packages/flutter_tools/lib/src/commands/run.dart
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
usesDeviceTimeoutOption();
addDdsOptions(verboseHelp: verboseHelp);
addDevToolsOptions(verboseHelp: verboseHelp);
addServeObservatoryOptions(verboseHelp: verboseHelp);
addAndroidSpecificBuildOptions(hide: !verboseHelp);
usesFatalWarningsOption(verboseHelp: verboseHelp);
addEnableImpellerFlag(verboseHelp: verboseHelp);
Expand Down Expand Up @@ -279,6 +280,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
nativeNullAssertions: boolArgDeprecated('native-null-assertions'),
enableImpeller: enableImpeller,
uninstallFirst: uninstallFirst,
serveObservatory: boolArgDeprecated('serve-observatory'),
enableDartProfiling: enableDartProfiling,
);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/flutter_tools/lib/src/commands/test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
'or as the string "none" to disable the timeout entirely.',
);
addDdsOptions(verboseHelp: verboseHelp);
addServeObservatoryOptions(verboseHelp: verboseHelp);
usesFatalWarningsOption(verboseHelp: verboseHelp);
}

Expand Down Expand Up @@ -404,6 +405,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
buildInfo,
startPaused: startPaused,
disableServiceAuthCodes: boolArgDeprecated('disable-service-auth-codes'),
serveObservatory: boolArgDeprecated('serve-observatory'),
// On iOS >=14, keeping this enabled will leave a prompt on the screen.
disablePortPublication: true,
enableDds: enableDds,
Expand Down
8 changes: 7 additions & 1 deletion packages/flutter_tools/lib/src/device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ class DebuggingOptions {
this.nativeNullAssertions = false,
this.enableImpeller = false,
this.uninstallFirst = false,
this.serveObservatory = true,
this.enableDartProfiling = true,
}) : debuggingEnabled = true;

Expand Down Expand Up @@ -799,7 +800,8 @@ class DebuggingOptions {
fastStart = false,
webEnableExpressionEvaluation = false,
nullAssertions = false,
nativeNullAssertions = false;
nativeNullAssertions = false,
serveObservatory = false;

DebuggingOptions._({
required this.buildInfo,
Expand Down Expand Up @@ -844,6 +846,7 @@ class DebuggingOptions {
required this.nativeNullAssertions,
required this.enableImpeller,
required this.uninstallFirst,
required this.serveObservatory,
required this.enableDartProfiling,
});

Expand Down Expand Up @@ -880,6 +883,7 @@ class DebuggingOptions {
final bool webUseSseForDebugBackend;
final bool webUseSseForInjectedClient;
final bool enableImpeller;
final bool serveObservatory;
final bool enableDartProfiling;

/// Whether the tool should try to uninstall a previously installed version of the app.
Expand Down Expand Up @@ -1008,6 +1012,7 @@ class DebuggingOptions {
'nullAssertions': nullAssertions,
'nativeNullAssertions': nativeNullAssertions,
'enableImpeller': enableImpeller,
'serveObservatory': serveObservatory,
'enableDartProfiling': enableDartProfiling,
};

Expand Down Expand Up @@ -1055,6 +1060,7 @@ class DebuggingOptions {
nativeNullAssertions: json['nativeNullAssertions']! as bool,
enableImpeller: (json['enableImpeller'] as bool?) ?? false,
uninstallFirst: (json['uninstallFirst'] as bool?) ?? false,
serveObservatory: (json['serveObservatory'] as bool?) ?? false,
enableDartProfiling: (json['enableDartProfiling'] as bool?) ?? true,
);
}
Expand Down
10 changes: 10 additions & 0 deletions packages/flutter_tools/lib/src/resident_devtools_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
final List<FlutterDevice?> devicesWithExtension = await _devicesWithExtensions(flutterDevices);
await _maybeCallDevToolsUriServiceExtension(devicesWithExtension);
await _callConnectedVmServiceUriExtension(devicesWithExtension);

for (final FlutterDevice? device in devicesWithExtension) {
if (device == null) {
continue;
}
// Notify the DDS instances that there's a DevTools instance available so they can correctly
// redirect DevTools related requests.
device.device?.dds.setExternalDevToolsUri(_devToolsLauncher!.devToolsUrl!);
}

if (_shutdown) {
// If we're shutting down, no point reporting the debugger list.
return;
Expand Down
20 changes: 20 additions & 0 deletions packages/flutter_tools/lib/src/resident_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,26 @@ abstract class ResidentRunner extends ResidentHandlers {
_finished.complete(0);
}

Future<void> enableObservatory() async {
assert(debuggingOptions.serveObservatory);
final List<Future<vm_service.Response?>> serveObservatoryRequests = <Future<vm_service.Response?>>[];
for (final FlutterDevice? device in flutterDevices) {
if (device == null) {
continue;
}
// Notify the VM service if the user wants Observatory to be served.
serveObservatoryRequests.add(
device.vmService?.callMethodWrapper('_serveObservatory') ??
Future<vm_service.Response?>.value(),
);
}
try {
await Future.wait(serveObservatoryRequests);
} on vm_service.RPCError catch(e) {
globals.printWarning('Unable to enable Observatory: $e');
}
}

void appFinished() {
if (_finished.isCompleted) {
return;
Expand Down
34 changes: 22 additions & 12 deletions packages/flutter_tools/lib/src/run_cold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,17 @@ class ColdRunner extends ResidentRunner {
}
}

if (enableDevTools && debuggingEnabled) {
// The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
flutterDevices: flutterDevices,
));
if (debuggingEnabled) {
if (enableDevTools) {
// The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
flutterDevices: flutterDevices,
));
}
if (debuggingOptions.serveObservatory) {
await enableObservatory();
}
}

if (flutterDevices.first.observatoryUris != null) {
Expand Down Expand Up @@ -162,12 +167,17 @@ class ColdRunner extends ResidentRunner {
}
}

if (enableDevTools && debuggingEnabled) {
// The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
flutterDevices: flutterDevices,
));
if (debuggingEnabled) {
if (enableDevTools) {
// The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
devToolsServerAddress: debuggingOptions.devToolsServerAddress,
flutterDevices: flutterDevices,
));
}
if (debuggingOptions.serveObservatory) {
await enableObservatory();
}
}

appStartedCompleter?.complete();
Expand Down
4 changes: 4 additions & 0 deletions packages/flutter_tools/lib/src/run_hot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ class HotRunner extends ResidentRunner {
return 2;
}

if (debuggingOptions.serveObservatory) {
await enableObservatory();
}

if (enableDevTools) {
// The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
Expand Down
8 changes: 8 additions & 0 deletions packages/flutter_tools/lib/src/runner/flutter_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,14 @@ abstract class FlutterCommand extends Command<void> {
);
}

void addServeObservatoryOptions({required bool verboseHelp}) {
argParser.addFlag('serve-observatory',
hide: !verboseHelp,
defaultsTo: true,
help: 'Serve the legacy Observatory developer tooling through the VM service.',
);
}

late final bool enableDds = () {
bool ddsEnabled = false;
if (argResults?.wasParsed('disable-dds') ?? false) {
Expand Down
11 changes: 10 additions & 1 deletion packages/flutter_tools/lib/src/test/flutter_tester_device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:dds/dds.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'package:stream_channel/stream_channel.dart';
import 'package:vm_service/vm_service.dart' as vm_service;

import '../base/file_system.dart';
import '../base/io.dart';
Expand Down Expand Up @@ -180,8 +181,15 @@ class FlutterTesterTestDevice extends TestDevice {
compileExpression: compileExpression,
logger: logger,
);
unawaited(localVmService.then((FlutterVmService vmservice) {
unawaited(localVmService.then((FlutterVmService vmservice) async {
logger.printTrace('test $id: Successfully connected to service protocol: $forwardingUri');
if (debuggingOptions.serveObservatory) {
try {
await vmservice.callMethodWrapper('_serveObservatory');
} on vm_service.RPCError {
logger.printWarning('Unable to enable Observatory');
}
}
}));

if (debuggingOptions.startPaused && !machine!) {
Expand All @@ -190,6 +198,7 @@ class FlutterTesterTestDevice extends TestDevice {
logger.printStatus(' $forwardingUri');
logger.printStatus('You should first set appropriate breakpoints, then resume the test in the debugger.');
}

_gotProcessObservatoryUri.complete(forwardingUri);
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async';

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

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

testWithoutContext('serveAndAnnounceDevTools with invokes devtools and vm_service setter', () async {
final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler(
FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080),
FakeDevtoolsLauncher()
..activeDevToolsServer = DevToolsServerAddress('localhost', 8080)
..devToolsUrl = Uri.parse('http://localhost:8080'),
FakeResidentRunner(),
BufferLogger.test(),
);
Expand Down Expand Up @@ -194,7 +199,9 @@ void main() {

testWithoutContext('serveAndAnnounceDevTools with web device', () async {
final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler(
FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080),
FakeDevtoolsLauncher()
..activeDevToolsServer = DevToolsServerAddress('localhost', 8080)
..devToolsUrl = Uri.parse('http://localhost:8080'),
FakeResidentRunner(),
BufferLogger.test(),
);
Expand Down Expand Up @@ -278,7 +285,9 @@ void main() {

testWithoutContext('serveAndAnnounceDevTools with multiple devices and VM service disappears on one', () async {
final ResidentDevtoolsHandler handler = FlutterResidentDevtoolsHandler(
FakeDevtoolsLauncher()..activeDevToolsServer = DevToolsServerAddress('localhost', 8080),
FakeDevtoolsLauncher()
..activeDevToolsServer = DevToolsServerAddress('localhost', 8080)
..devToolsUrl = Uri.parse('http://localhost:8080'),
FakeResidentRunner(),
BufferLogger.test(),
);
Expand Down Expand Up @@ -442,6 +451,9 @@ class FakeResidentRunner extends Fake implements ResidentRunner {

@override
bool reportedDebuggers = false;

@override
DebuggingOptions debuggingOptions = DebuggingOptions.disabled(BuildInfo.debug);
}

class FakeFlutterDevice extends Fake implements FlutterDevice {
Expand All @@ -458,4 +470,35 @@ class FakeFlutterDevice extends Fake implements FlutterDevice {
// Unfortunately Device, despite not being immutable, has an `operator ==`.
// Until we fix that, we have to also ignore related lints here.
// ignore: avoid_implementing_value_types
class FakeDevice extends Fake implements Device { }
class FakeDevice extends Fake implements Device {
@override
DartDevelopmentService get dds => FakeDartDevelopmentService();
}

class FakeDartDevelopmentService extends Fake implements DartDevelopmentService {
bool started = false;
bool disposed = false;

@override
final Uri uri = Uri.parse('http://127.0.0.1:1234/');

@override
Future<void> startDartDevelopmentService(
Uri observatoryUri, {
required Logger logger,
int? hostPort,
bool? ipv6,
bool? disableServiceAuthCodes,
bool cacheStartupProfile = false,
}) async {
started = true;
}

@override
Future<void> shutdown() async {
disposed = true;
}

@override
void setExternalDevToolsUri(Uri uri) {}
}
Loading

0 comments on commit 6cd4fa4

Please sign in to comment.