Change in dart/sdk[master]: [ VM / DDS / CLI ] Add DevTools support to the standalone VM

104 views
Skip to first unread message

Ben Konyi (Gerrit)

unread,
Mar 1, 2021, 5:21:25 PM3/1/21
to rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

Attention is currently required from: Ryan Macnak, Siva Annamalai.

View Change

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 2
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Mon, 01 Mar 2021 22:21:21 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Ben Konyi (Gerrit)

    unread,
    Mar 1, 2021, 5:21:25 PM3/1/21
    to Ryan Macnak, Siva Annamalai, rev...@dartlang.org, vm-...@dartlang.org, Jacob Richman, Devon Carew, Kenzie Schmoll

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    Ben Konyi would like Ryan Macnak and Siva Annamalai to review this change.

    View Change

    [ VM / DDS / CLI ] Add DevTools support to the standalone VM

    Passing --devtools alongside either --enable-vm-service or --observe
    will result in a DevTools instance being served by DDS. By default,
    DevTools is hosted at localhost:8182, but the bind address and port can
    be configured with optional parameters to --devtools, similar to those
    available for --observe.

    Example output on stdout when DevTools is enabled:

    Observatory listening on http://127.0.0.1:8181/CzkZzZaONW4=/
    The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8182?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FCzkZzZaONW4%3D%2Fws
    hello world!

    vm-service: isolate(1674461414267555) 'main' has no debugger attached and is paused at exit. Connect to Observatory at http://127.0.0.1:8181/CzkZzZaONW4=/ to debug.
    Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    ---
    M .dart_tool/package_config.json
    M .packages
    M DEPS
    M pkg/dartdev/lib/dartdev.dart
    M pkg/dartdev/lib/src/commands/run.dart
    M pkg/dartdev/lib/src/sdk.dart
    M pkg/dartdev/test/commands/run_test.dart
    M pkg/dds/CHANGELOG.md
    M pkg/dds/bin/dds.dart
    M pkg/dds/lib/dds.dart
    M pkg/dds/lib/src/dds_impl.dart
    M pkg/dds/pubspec.yaml
    M runtime/bin/main_options.cc
    M runtime/bin/main_options.h
    M sdk/BUILD.gn
    M tools/generate_package_config.dart
    M utils/dartdev/BUILD.gn
    17 files changed, 388 insertions(+), 32 deletions(-)

    diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
    index 45febc4..a26c902 100644
    --- a/.dart_tool/package_config.json
    +++ b/.dart_tool/package_config.json
    @@ -11,7 +11,7 @@
    "constraint, update this by running tools/generate_package_config.dart."
    ],
    "configVersion": 2,
    - "generated": "2021-03-01T09:26:17.118461",
    + "generated": "2021-03-01T14:13:13.790109",
    "generator": "tools/generate_package_config.dart",
    "packages": [
    {
    @@ -139,6 +139,12 @@
    "languageVersion": "2.10"
    },
    {
    + "name": "browser_launcher",
    + "rootUri": "../third_party/pkg/browser_launcher",
    + "packageUri": "lib/",
    + "languageVersion": "2.2"
    + },
    + {
    "name": "build_integration",
    "rootUri": "../pkg/build_integration",
    "packageUri": "lib/",
    @@ -232,7 +238,7 @@
    "name": "dartdoc",
    "rootUri": "../third_party/pkg/dartdoc",
    "packageUri": "lib/",
    - "languageVersion": "2.10"
    + "languageVersion": "2.11"
    },
    {
    "name": "dds",
    @@ -247,6 +253,18 @@
    "languageVersion": "2.3"
    },
    {
    + "name": "devtools_server",
    + "rootUri": "../third_party/devtools/devtools_server",
    + "packageUri": "lib/",
    + "languageVersion": "2.6"
    + },
    + {
    + "name": "devtools_shared",
    + "rootUri": "../third_party/devtools/devtools_shared",
    + "packageUri": "lib/",
    + "languageVersion": "2.3"
    + },
    + {
    "name": "diagnostic",
    "rootUri": "../pkg/diagnostic",
    "packageUri": "lib/",
    @@ -788,6 +806,12 @@
    "languageVersion": "2.0"
    },
    {
    + "name": "webkit_inspection_protocol",
    + "rootUri": "../third_party/pkg/webkit_inspection_protocol",
    + "packageUri": "lib/",
    + "languageVersion": "2.12"
    + },
    + {
    "name": "yaml",
    "rootUri": "../third_party/pkg/yaml",
    "packageUri": "lib/",
    diff --git a/.packages b/.packages
    index 3587c4f..f6517f3 100644
    --- a/.packages
    +++ b/.packages
    @@ -21,6 +21,7 @@
    benchmark_harness:third_party/pkg/benchmark_harness/lib
    boolean_selector:third_party/pkg/boolean_selector/lib
    build_integration:pkg/build_integration/lib
    +browser_launcher:third_party/pkg/browser_launcher/lib
    charcode:third_party/pkg/charcode/lib
    cli_util:third_party/pkg/cli_util/lib
    collection:third_party/pkg/collection/lib
    @@ -37,6 +38,8 @@
    dartdoc:third_party/pkg/dartdoc/lib
    dds:pkg/dds/lib
    dev_compiler:pkg/dev_compiler/lib
    +devtools_server:third_party/devtools/devtools_server/lib
    +devtools_shared:third_party/devtools/devtools_shared/lib
    diagnostic:pkg/diagnostic/lib
    expect:pkg/expect/lib
    ffi:third_party/pkg/ffi/lib
    @@ -118,6 +121,7 @@
    wasm:pkg/wasm/lib
    watcher:third_party/pkg/watcher/lib
    webdriver:third_party/pkg/webdriver/lib
    +webkit_inspection_protocol: third_party/pkg/webkit_inspection_protocol.dart/lib
    web_components:third_party/pkg/web_components/lib
    web_socket_channel:third_party/pkg/web_socket_channel/lib
    yaml:third_party/pkg/yaml/lib
    diff --git a/DEPS b/DEPS
    index 383b118..678a837 100644
    --- a/DEPS
    +++ b/DEPS
    @@ -76,6 +76,7 @@
    "boringssl_gen_rev": "7322fc15cc065d8d2957fccce6b62a509dc4d641",
    "boringssl_rev" : "1607f54fed72c6589d560254626909a64124f091",
    "browser-compat-data_tag": "v1.0.22",
    + "browser_launcher_rev": "3e1677b20fd3267a5d1ae217ece3d58bb08c8938",
    "charcode_rev": "bcd8a12c315b7a83390e4865ad847ecd9344cba2",
    "chrome_rev" : "19997",
    "cli_util_rev" : "fd1b716e8a350a454e01ae56df540293d31ff6c8",
    @@ -165,6 +166,7 @@
    "vector_math_rev": "0c9f5d68c047813a6dcdeb88ba7a42daddf25025",
    "watcher_rev": "3924194385fb215cef483193ed2879a618a3d69c",
    "webdriver_rev": "5a8d6805d9cf8a3cbb4fcd64849b538b7491e50e",
    + "webkit_inspection_protocol_rev": "dd6fb5d8b536e19cedb384d0bbf1f5631923f1e8",
    "web_components_rev": "8f57dac273412a7172c8ade6f361b407e2e4ed02",
    "web_socket_channel_rev": "76931ea1b81ba71e8319330c35285d3e88566315",
    "WebCore_rev": "fb11e887f77919450e497344da570d780e078bc8",
    @@ -232,7 +234,7 @@
    Var("dart_root") + "/third_party/devtools": {
    "packages": [{
    "package": "dart/third_party/flutter/devtools",
    - "version": "revision:6729ec62c3548839018c32fa711756202431ccf7",
    + "version": "revision:76865807f83f728756ee1b122119bfc64db4601b",
    }],
    "dep_type": "cipd",
    },
    @@ -305,6 +307,9 @@
    Var('chromium_git') + '/external/github.com/mdn/browser-compat-data' +
    "@" + Var("browser-compat-data_tag"),

    + Var("dart_root") + "/third_party/pkg/browser_launcher":
    + Var("dart_git") + "browser_launcher.git" + "@" + Var("browser_launcher_rev"),
    +
    Var("dart_root") + "/third_party/tcmalloc/gperftools":
    Var('chromium_git') + '/external/github.com/gperftools/gperftools.git' +
    "@" + Var("gperftools_revision"),
    @@ -469,6 +474,9 @@
    Var("dart_root") + "/third_party/pkg/webdriver":
    Var("dart_git") + "external/github.com/google/webdriver.dart.git" +
    "@" + Var("webdriver_rev"),
    + Var("dart_root") + "/third_party/pkg/webkit_inspection_protocol":
    + Var("dart_git") + "external/github.com/google/webkit_inspection_protocol.dart" +
    + "@" + Var("webkit_inspection_protocol_rev"),

    Var("dart_root") + "/third_party/pkg/web_socket_channel":
    Var("dart_git") + "web_socket_channel.git" +
    diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
    index a8f9780..ab6c921 100644
    --- a/pkg/dartdev/lib/dartdev.dart
    +++ b/pkg/dartdev/lib/dartdev.dart
    @@ -40,7 +40,8 @@
    args = args
    .where(
    (element) => !(element.contains('--observe') ||
    - element.contains('--enable-vm-service')),
    + element.contains('--enable-vm-service') ||
    + element.contains('--devtools')),
    )
    .toList();
    }
    diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
    index 45bfd1e..71602e6 100644
    --- a/pkg/dartdev/lib/src/commands/run.dart
    +++ b/pkg/dartdev/lib/src/commands/run.dart
    @@ -51,12 +51,19 @@
    'Debugging options:',
    )
    ..addOption(
    + 'devtools',
    + help: 'Allows for debugging with a Dart DevTools instance when '
    + 'combined with --observe or --enable-vm-service.',
    + valueHelp: '[<port>[/<bind-address>]]',
    + )
    + ..addOption(
    'observe',
    help: 'The observe flag is a convenience flag used to run a program '
    'with a set of common options useful for debugging.',
    valueHelp: '[<port>[/<bind-address>]]',
    )
    ..addOption('launch-dds', hide: true, help: 'Launch DDS.')
    + ..addOption('launch-devtools', hide: true, help: 'Launch DevTools.')
    ..addSeparator(
    'Options implied by --observe are currently:',
    )
    @@ -179,12 +186,21 @@
    String launchDdsArg = argResults['launch-dds'];
    String ddsHost = '';
    String ddsPort = '';
    + bool launchDevTools = false;
    + String devToolsHost = '';
    + String devToolsPort = '';
    bool launchDds = false;
    if (launchDdsArg != null) {
    launchDds = true;
    - final ddsUrl = launchDdsArg.split(':');
    + final ddsUrl = launchDdsArg.split('\\:');
    ddsHost = ddsUrl[0];
    ddsPort = ddsUrl[1];
    + if (argResults.wasParsed('launch-devtools')) {
    + launchDevTools = true;
    + final devToolsUrl = argResults['launch-devtools'].split('\\:');
    + devToolsHost = devToolsUrl[0];
    + devToolsPort = devToolsUrl[1];
    + }
    }

    bool disableServiceAuthCodes = argResults['disable-service-auth-codes'];
    @@ -198,7 +214,13 @@
    if (launchDds) {
    debugSession = _DebuggingSession();
    if (!await debugSession.start(
    - ddsHost, ddsPort, disableServiceAuthCodes)) {
    + ddsHost,
    + ddsPort,
    + disableServiceAuthCodes,
    + launchDevTools,
    + devToolsHost,
    + devToolsPort,
    + )) {
    return errorExitCode;
    }
    }
    @@ -242,39 +264,58 @@

    class _DebuggingSession {
    Future<bool> start(
    - String host, String port, bool disableServiceAuthCodes) async {
    + String host,
    + String port,
    + bool disableServiceAuthCodes,
    + bool enableDevTools,
    + String devToolsHost,
    + String devToolsPort,
    + ) async {
    final serviceInfo = await Service.getInfo();
    - final ddsSnapshot = (dirname(sdk.dart).endsWith('bin'))
    + final fullSdk = dirname(sdk.dart).endsWith('bin');
    + final ddsSnapshot = fullSdk
    ? sdk.ddsSnapshot
    : absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot');
    + final devToolsBinaries = fullSdk
    + ? sdk.devToolsBinaries
    + : absolute(dirname(sdk.dart), 'devtools');
    if (!Sdk.checkArtifactExists(ddsSnapshot)) {
    return false;
    }
    final process = await Process.start(
    - sdk.dart,
    - [
    - if (dirname(sdk.dart).endsWith('bin'))
    - sdk.ddsSnapshot
    - else
    - absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot'),
    - serviceInfo.serverUri.toString(),
    - host,
    - port,
    - disableServiceAuthCodes.toString(),
    - ],
    - mode: ProcessStartMode.detachedWithStdio);
    + sdk.dart,
    + [
    + ddsSnapshot,
    + serviceInfo.serverUri.toString(),
    + host,
    + port,
    + disableServiceAuthCodes.toString(),
    + enableDevTools.toString(),
    + devToolsHost,
    + devToolsPort,
    + devToolsBinaries,
    + ],
    + mode: ProcessStartMode.detachedWithStdio,
    + );
    final completer = Completer<void>();
    StreamSubscription sub;
    sub = process.stderr.transform(utf8.decoder).listen((event) {
    - if (event == 'DDS started') {
    + final result = json.decode(event) as Map<String, dynamic>;
    + final state = result['state'];
    + if (state == 'started') {
    + if (result.containsKey('devToolsUri')) {
    + final devToolsUri = result['devToolsUri'];
    + print(
    + 'The Dart DevTools debugger and profiler is available at: $devToolsUri',
    + );
    + }
    sub.cancel();
    completer.complete();
    - } else if (event.contains('Failed to start DDS')) {
    + } else {
    sub.cancel();
    - completer.completeError(event.replaceAll(
    - 'Failed to start DDS',
    + completer.completeError(
    'Could not start Observatory HTTP server',
    - ));
    + );
    }
    });
    try {
    diff --git a/pkg/dartdev/lib/src/sdk.dart b/pkg/dartdev/lib/src/sdk.dart
    index 3e8a12a..426f810 100644
    --- a/pkg/dartdev/lib/src/sdk.dart
    +++ b/pkg/dartdev/lib/src/sdk.dart
    @@ -68,6 +68,13 @@
    'dds.dart.snapshot',
    );

    + String get devToolsBinaries => path.absolute(
    + sdkPath,
    + 'bin',
    + 'resources',
    + 'devtools',
    + );
    +
    String get pubSnapshot => path.absolute(
    sdkPath,
    'bin',
    diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
    index b8cc5e8..1174158 100644
    --- a/pkg/dartdev/test/commands/run_test.dart
    +++ b/pkg/dartdev/test/commands/run_test.dart
    @@ -300,4 +300,94 @@
    expect(result.stderr, isEmpty);
    expect(result.exitCode, 0);
    });
    +
    + group('DevTools', () {
    + const devToolsMessagePrefix =
    + 'The Dart DevTools debugger and profiler is available at: ';
    +
    + Future<int> findOpenPort() async {
    + final server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
    + final port = server.port;
    + await server.close();
    + return port;
    + }
    +
    + test('spawn simple', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + ProcessResult result = p.runSync([
    + 'run',
    + '--enable-vm-service',
    + '--devtools',
    + p.relativeFilePath,
    + ]);
    + expect(
    + result.stdout, contains(devToolsMessagePrefix + 'http://127.0.0.1:'));
    + });
    +
    + test('implicit spawn', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + ProcessResult result = p.runSync([
    + '--enable-vm-service',
    + '--devtools',
    + p.relativeFilePath,
    + ]);
    + expect(
    + result.stdout, contains(devToolsMessagePrefix + 'http://127.0.0.1:'));
    + });
    +
    + test('custom port', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + final port = await findOpenPort();
    + ProcessResult result = p.runSync([
    + 'run',
    + '--enable-vm-service',
    + '--devtools=$port',
    + p.relativeFilePath,
    + ]);
    + expect(result.stdout,
    + contains(devToolsMessagePrefix + 'http://127.0.0.1:$port'));
    + });
    +
    + test('custom port with IPv4 bind address', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + final port = await findOpenPort();
    + ProcessResult result = p.runSync([
    + 'run',
    + '--enable-vm-service',
    + '--devtools=$port/127.0.0.1',
    + p.relativeFilePath,
    + ]);
    + expect(result.stdout,
    + contains(devToolsMessagePrefix + 'http://127.0.0.1:$port'));
    + });
    +
    + test('custom port with IPv6 bind address', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + final port = await findOpenPort();
    + ProcessResult result = p.runSync([
    + 'run',
    + '--enable-vm-service',
    + '--devtools=$port/::1',
    + p.relativeFilePath,
    + ]);
    + expect(result.stdout,
    + contains(devToolsMessagePrefix + 'http://[::1]:$port'));
    + });
    +
    + test('- prints warning when --disable-dart-dev is provided', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + final port = await findOpenPort();
    + ProcessResult result = p.runSync([
    + '--disable-dart-dev',
    + '--enable-vm-service',
    + '--devtools=$port',
    + p.relativeFilePath,
    + ]);
    + expect(
    + result.stderr,
    + contains(
    + 'Warning: DevTools cannot be launched when --disable-dart-dev is provided.'),
    + );
    + });
    + });
    }
    diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
    index 62904a1..86d4d29 100644
    --- a/pkg/dds/CHANGELOG.md
    +++ b/pkg/dds/CHANGELOG.md
    @@ -1,3 +1,6 @@
    +# 1.8.0-dev
    +- Add support for launching DevTools from DDS.
    +
    # 1.7.5
    - Add 30 second keep alive period for SSE connections.

    diff --git a/pkg/dds/bin/dds.dart b/pkg/dds/bin/dds.dart
    index 3ac9a09..8ca4a66 100644
    --- a/pkg/dds/bin/dds.dart
    +++ b/pkg/dds/bin/dds.dart
    @@ -2,6 +2,7 @@
    // for details. All rights reserved. Use of this source code is governed by a
    // BSD-style license that can be found in the LICENSE file.

    +import 'dart:convert';
    import 'dart:io';

    import 'package:dds/dds.dart';
    @@ -14,6 +15,10 @@
    /// - DDS bind address
    /// - DDS port
    /// - Disable service authentication codes
    +/// - Start DevTools
    +/// - DevTools bind address
    +/// - DevTools port
    +/// - DevTools build directory
    Future<void> main(List<String> args) async {
    if (args.isEmpty) return;

    @@ -35,16 +40,48 @@
    port: int.parse(args[2]),
    );
    final disableServiceAuthCodes = args[3] == 'true';
    +
    + final startDevTools = args[4] == 'true';
    + InternetAddress devToolsAddress;
    + int devToolsPort;
    + Uri devToolsBuildDirectory;
    + if (args[5].isNotEmpty) {
    + final devToolsAddresses = await InternetAddress.lookup(args[5]);
    + // Prefer IPv4 addresses.
    + for (int i = 0; i < devToolsAddresses.length; i++) {
    + devToolsAddress = devToolsAddresses[i];
    + if (devToolsAddress.type == InternetAddressType.IPv4) {
    + break;
    + }
    + }
    + devToolsPort = int.parse(args[6]);
    + devToolsBuildDirectory = Uri.parse(args[7]);
    + }
    try {
    // TODO(bkonyi): add retry logic similar to that in vmservice_server.dart
    // See https://github.com/dart-lang/sdk/issues/43192.
    - await DartDevelopmentService.startDartDevelopmentService(
    + final dds = await DartDevelopmentService.startDartDevelopmentService(
    remoteVmServiceUri,
    serviceUri: serviceUri,
    enableAuthCodes: !disableServiceAuthCodes,
    + devToolsConfiguration: startDevTools
    + ? DevToolsConfiguration(
    + enable: startDevTools,
    + hostname: devToolsAddress?.address,
    + port: devToolsPort,
    + customBuildDirectoryPath: devToolsBuildDirectory,
    + )
    + : null,
    );
    - stderr.write('DDS started');
    - } catch (e) {
    - stderr.writeln('Failed to start DDS:\n$e');
    + stderr.write(json.encode({
    + 'state': 'started',
    + if (dds.devToolsUri != null) 'devToolsUri': dds.devToolsUri.toString(),
    + }));
    + } catch (e, st) {
    + stderr.write(json.encode({
    + 'state': 'error',
    + 'error': '$e',
    + 'stacktrace': '$st',
    + }));
    }
    }
    diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart
    index a9024dd..d4fd156 100644
    --- a/pkg/dds/lib/dds.dart
    +++ b/pkg/dds/lib/dds.dart
    @@ -42,6 +42,7 @@
    Uri serviceUri,
    bool enableAuthCodes = true,
    bool ipv6 = false,
    + DevToolsConfiguration devToolsConfiguration,
    }) async {
    if (remoteVmServiceUri == null) {
    throw ArgumentError.notNull('remoteVmServiceUri');
    @@ -78,6 +79,7 @@
    serviceUri,
    enableAuthCodes,
    ipv6,
    + devToolsConfiguration,
    );
    await service.startService();
    return service;
    @@ -123,6 +125,11 @@
    /// Returns `null` if the service is not running.
    Uri get wsUri;

    + /// The HTTP [Uri] of the hosted DevTools instance.
    + ///
    + /// Returns `null` if DevTools is not running.
    + Uri get devToolsUri;
    +
    /// Set to `true` if this instance of [DartDevelopmentService] is accepting
    /// requests.
    bool get isRunning;
    @@ -166,3 +173,17 @@
    final int errorCode;
    final String message;
    }
    +
    +class DevToolsConfiguration {
    + DevToolsConfiguration({
    + this.enable = false,
    + this.customBuildDirectoryPath,
    + this.hostname,
    + this.port = 0,
    + });
    +
    + final bool enable;
    + final Uri customBuildDirectoryPath;
    + final String hostname;
    + final int port;
    +}
    diff --git a/pkg/dds/lib/src/dds_impl.dart b/pkg/dds/lib/src/dds_impl.dart
    index 6daaedd..2dc17be 100644
    --- a/pkg/dds/lib/src/dds_impl.dart
    +++ b/pkg/dds/lib/src/dds_impl.dart
    @@ -8,6 +8,7 @@
    import 'dart:math';
    import 'dart:typed_data';

    +import 'package:devtools_server/devtools_server.dart';
    import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
    import 'package:meta/meta.dart';
    import 'package:pedantic/pedantic.dart';
    @@ -49,7 +50,12 @@

    class DartDevelopmentServiceImpl implements DartDevelopmentService {
    DartDevelopmentServiceImpl(
    - this._remoteVmServiceUri, this._uri, this._authCodesEnabled, this._ipv6) {
    + this._remoteVmServiceUri,
    + this._uri,
    + this._authCodesEnabled,
    + this._ipv6,
    + this._devToolsConfiguration,
    + ) {
    _clientManager = ClientManager(this);
    _expressionEvaluator = ExpressionEvaluator(this);
    _isolateManager = IsolateManager(this);
    @@ -96,6 +102,11 @@
    // Once we have a connection to the VM service, we're ready to spawn the intermediary.
    await _startDDSServer();
    started = true;
    +
    + // Startup DevTools if requested.
    + if (_devToolsConfiguration?.enable ?? false) {
    + await _serveDevTools();
    + }
    completer.complete();
    } on StateError {
    /* Ignore json-rpc state errors */
    @@ -147,6 +158,29 @@
    _uri = tmpUri;
    }

    + Future<void> _serveDevTools() async {
    + final buildDir =
    + _devToolsConfiguration.customBuildDirectoryPath?.toFilePath();
    + _devtoolsServer = await serveDevTools(
    + customDevToolsPath: buildDir,
    + hostname: _devToolsConfiguration.hostname,
    + port: _devToolsConfiguration.port,
    + machineMode: true,
    + enableStdinCommands: false,
    + );
    +
    + final queryParams = <String, String>{
    + 'uri': wsUri.toString(),
    + };
    +
    + _devToolsUri = Uri(
    + scheme: 'http',
    + host: _devtoolsServer.address.host,
    + port: _devtoolsServer.port,
    + queryParameters: queryParams,
    + );
    + }
    +
    /// Stop accepting requests after gracefully handling existing requests.
    @override
    Future<void> shutdown() async {
    @@ -157,6 +191,7 @@
    _shuttingDown = true;
    // Don't accept anymore HTTP requests.
    await _server?.close();
    + await _devtoolsServer?.close();

    // Close connections to clients.
    await clientManager.shutdown();
    @@ -318,10 +353,15 @@
    Uri get wsUri => _toWebSocket(_uri);
    Uri _uri;

    + Uri get devToolsUri => _devToolsUri;
    + Uri _devToolsUri;
    +
    final bool _ipv6;

    bool get isRunning => _uri != null;

    + final DevToolsConfiguration _devToolsConfiguration;
    +
    Future<void> get done => _done.future;
    Completer _done = Completer<void>();
    bool _shuttingDown = false;
    @@ -343,4 +383,5 @@
    json_rpc.Peer vmServiceClient;
    WebSocketChannel _vmServiceSocket;
    HttpServer _server;
    + HttpServer _devtoolsServer;
    }
    diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
    index 469fc0e..3e067bd 100644
    --- a/pkg/dds/pubspec.yaml
    +++ b/pkg/dds/pubspec.yaml
    @@ -3,7 +3,7 @@
    A library used to spawn the Dart Developer Service, used to communicate with
    a Dart VM Service instance.

    -version: 1.7.5
    +version: 1.8.0-dev

    homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds

    @@ -12,6 +12,8 @@

    dependencies:
    async: ^2.4.1
    + devtools_server: ^2.0.0
    + devtools_shared: ^2.0.0
    json_rpc_2: ^2.2.0
    meta: ^1.1.8
    pedantic: ^1.7.0
    diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
    index e60f6c8..0f2a76d 100644
    --- a/runtime/bin/main_options.cc
    +++ b/runtime/bin/main_options.cc
    @@ -42,6 +42,7 @@
    SnapshotKind Options::gen_snapshot_kind_ = kNone;
    VerbosityLevel Options::verbosity_ = kAll;
    bool Options::enable_vm_service_ = false;
    +bool Options::enable_devtools_ = false;

    #define OPTION_FIELD(variable) Options::variable##_

    @@ -365,6 +366,26 @@
    return true;
    }

    +const char* Options::devtools_server_ip_ = DEFAULT_DEVTOOLS_SERVER_IP;
    +int Options::devtools_server_port_ = DEFAULT_DEVTOOLS_SERVER_PORT;
    +bool Options::ProcessDevToolsOption(const char* arg,
    + CommandLineOptions* vm_options) {
    + const char* value = OptionProcessor::ProcessOption(arg, "--devtools");
    + if (value == NULL) {
    + return false;
    + }
    + if (!ExtractPortAndAddress(value, &devtools_server_port_,
    + &devtools_server_ip_, DEFAULT_DEVTOOLS_SERVER_PORT,
    + DEFAULT_DEVTOOLS_SERVER_IP)) {
    + Syslog::PrintErr(
    + "unrecognized --devtools option syntax. "
    + "Use --devtools[=<port number>[/<bind address>]]\n");
    + return false;
    + }
    + enable_devtools_ = true;
    + return true;
    +}
    +
    // Explicitly handle VM flags that can be parsed by DartDev's run command.
    bool Options::ProcessVMDebuggingOptions(const char* arg,
    CommandLineOptions* vm_options) {
    @@ -583,7 +604,7 @@
    run_command = true;
    }
    if (!Options::disable_dart_dev() && enable_vm_service_ && run_command) {
    - const char* dds_format_str = "--launch-dds=%s:%d";
    + const char* dds_format_str = "--launch-dds=%s\\:%d";
    size_t size =
    snprintf(nullptr, 0, dds_format_str, vm_service_server_ip(),
    vm_service_server_port());
    @@ -594,6 +615,18 @@
    vm_service_server_port());
    dart_options->AddArgument(dds_uri);

    + if (enable_devtools_) {
    + const char* devtools_format_str = "--launch-devtools=%s\\:%d";
    + size = snprintf(nullptr, 0, devtools_format_str, devtools_server_ip(),
    + devtools_server_port());
    + // Make room for '\0'
    + ++size;
    + char* devtools_uri = new char[size];
    + snprintf(devtools_uri, size, devtools_format_str,
    + devtools_server_ip(), devtools_server_port());
    + dart_options->AddArgument(devtools_uri);
    + }
    +
    // Only add --disable-service-auth-codes if dartdev is being run
    // implicitly. Otherwise it will already be forwarded.
    if (implicitly_use_dart_dev && Options::vm_service_auth_disabled()) {
    @@ -603,6 +636,12 @@
    first_option = false;
    }
    }
    + if (Options::disable_dart_dev() && enable_devtools_) {
    + Syslog::PrintErr(
    + "Warning: DevTools cannot be launched when --disable-dart-dev is "
    + "provided.\n");
    + }
    +
    // Verify consistency of arguments.

    // snapshot_depfile is an alias for depfile. Passing them both is an error.
    diff --git a/runtime/bin/main_options.h b/runtime/bin/main_options.h
    index adec23c..4fa1aec 100644
    --- a/runtime/bin/main_options.h
    +++ b/runtime/bin/main_options.h
    @@ -72,6 +72,7 @@
    V(ProcessEnvironmentOption) \
    V(ProcessEnableVmServiceOption) \
    V(ProcessObserveOption) \
    + V(ProcessDevToolsOption) \
    V(ProcessVMDebuggingOptions)

    // This enum must match the strings in kSnapshotKindNames in main_options.cc.
    @@ -92,6 +93,8 @@
    static constexpr const char* DEFAULT_VM_SERVICE_SERVER_IP = "localhost";
    static constexpr int DEFAULT_VM_SERVICE_SERVER_PORT = 8181;
    static constexpr int INVALID_VM_SERVICE_SERVER_PORT = -1;
    +static constexpr const char* DEFAULT_DEVTOOLS_SERVER_IP = "localhost";
    +static constexpr int DEFAULT_DEVTOOLS_SERVER_PORT = 8182;

    class Options {
    public:
    @@ -141,6 +144,9 @@
    static const char* vm_service_server_ip() { return vm_service_server_ip_; }
    static int vm_service_server_port() { return vm_service_server_port_; }

    + static const char* devtools_server_ip() { return devtools_server_ip_; }
    + static int devtools_server_port() { return devtools_server_port_; }
    +
    static Dart_KernelCompilationVerbosityLevel verbosity_level() {
    return VerbosityLevelToDartAPI(verbosity_);
    }
    @@ -207,6 +213,9 @@
    const char** out_ip,
    int default_port,
    const char* default_ip);
    + static bool enable_devtools_;
    + static const char* devtools_server_ip_;
    + static int devtools_server_port_;

    #define OPTION_FRIEND(flag, variable) friend class OptionProcessor_##flag;
    STRING_OPTIONS_LIST(OPTION_FRIEND)
    diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
    index b6091dc..16ec25d 100644
    --- a/sdk/BUILD.gn
    +++ b/sdk/BUILD.gn
    @@ -254,6 +254,18 @@
    },
    ]

    +# This rule copies the pre-built DevTools application to
    +# bin/resources/devtools/
    +copy_tree_specs += [
    + {
    + target = "copy_prebuilt_devtools"
    + visibility = [ ":create_common_sdk" ]
    + source = "../third_party/devtools/web"
    + dest = "$root_out_dir/dart-sdk/bin/resources/devtools"
    + ignore_patterns = "{}"
    + },
    +]
    +
    # This loop generates rules to copy libraries to lib/
    foreach(library, _full_sdk_libraries) {
    copy_tree_specs += [
    @@ -836,6 +848,7 @@
    ":copy_libraries_dart",
    ":copy_libraries_specification",
    ":copy_license",
    + ":copy_prebuilt_devtools",
    ":copy_readme",
    ":copy_vm_dill_files",
    ":write_dartdoc_options",
    diff --git a/tools/generate_package_config.dart b/tools/generate_package_config.dart
    index babc89d..4cf47e0 100644
    --- a/tools/generate_package_config.dart
    +++ b/tools/generate_package_config.dart
    @@ -57,6 +57,8 @@
    packageDirectory(
    'runtime/observatory_2/tests/service_2/observatory_test_package_2'),
    packageDirectory('sdk/lib/_internal/sdk_library_metadata'),
    + packageDirectory('third_party/devtools/devtools_server'),
    + packageDirectory('third_party/devtools/devtools_shared'),
    packageDirectory('third_party/pkg/protobuf/protobuf'),
    packageDirectory('tools/package_deps'),
    ];
    diff --git a/utils/dartdev/BUILD.gn b/utils/dartdev/BUILD.gn
    index c7d8c12..5bcbc61 100644
    --- a/utils/dartdev/BUILD.gn
    +++ b/utils/dartdev/BUILD.gn
    @@ -2,6 +2,7 @@
    # for details. All rights reserved. Use of this source code is governed by a
    # BSD-style license that can be found in the LICENSE file.

    +import("../../build/dart/copy_tree.gni")
    import("../application_snapshot.gni")

    dartdev_files = exec_script("../../tools/list_dart_files.py",
    @@ -15,6 +16,7 @@
    public_deps = [
    ":copy_dartdev_kernel",
    ":copy_dartdev_snapshot",
    + ":copy_prebuilt_devtools",
    ]
    }

    @@ -48,3 +50,15 @@
    inputs = dartdev_files
    output = "$root_gen_dir/dartdev.dart.snapshot"
    }
    +
    +copy_trees("copy_prebuilt_devtools") {
    + sources = [
    + {
    + target = "copy_prebuilt_devtools"
    + visibility = [ ":dartdev" ]
    + source = "../../third_party/devtools/web"
    + dest = "$root_out_dir/devtools"
    + ignore_patterns = "{}"
    + },
    + ]
    +}

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 2
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-MessageType: newchange

    Siva Annamalai (Gerrit)

    unread,
    Mar 1, 2021, 6:18:13 PM3/1/21
    to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Ben Konyi.

    View Change

    3 comments:

    • File pkg/dartdev/lib/src/commands/run.dart:

      • Patch Set #3, Line 56: 'combined with --observe or --enable-vm-service.',

        why should --observe or --enable-vm-service be combine with --devtools, can we not imply --observe when --devtools is specified.

    • File pkg/dartdev/test/commands/run_test.dart:

      • Patch Set #3, Line 344: '--devtools=$port',

        what happens if --devtools=$port and --observe=$port are specified in the same run command ?

    • File runtime/bin/main_options.h:

      • Patch Set #3, Line 97: static constexpr int DEFAULT_DEVTOOLS_SERVER_PORT = 8182;

        I am a little confused here, why do we want a devtools server and an observatory vm_service server running at the same time ?

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 3
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Ben Konyi <bko...@google.com>
    Gerrit-Comment-Date: Mon, 01 Mar 2021 23:18:09 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Ben Konyi (Gerrit)

    unread,
    Mar 1, 2021, 6:57:11 PM3/1/21
    to rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    View Change

    3 comments:

    • File pkg/dartdev/lib/src/commands/run.dart:

      • why should --observe or --enable-vm-service be combine with --devtools, can we not imply --observe w […]

        That's an option as well, but we don't necessarily want to imply --observe with --devtools since --observe includes debugging options that users won't necessarily always want (e.g., --pause-isolates-on-exit). We have the opposite problem if we decide to imply --enable-vm-service when --devtools is provided.

        Basically, this allows for a bit more control over the debugging flags provided to the VM rather than making assumptions about flags one way or the other.

    • File pkg/dartdev/test/commands/run_test.dart:

      • Patch Set #3, Line 344: '--devtools=$port',

        what happens if --devtools=$port and --observe=$port are specified in the same run command ?

      • I'm 99% sure the VM service will take $port and DevTools will try and listen on the next available port (e.g., $port + 1). We should test this behavior.

    • File runtime/bin/main_options.h:

      • I am a little confused here, why do we want a devtools server and an observatory vm_service server r […]

        Observatory is served by the VM service, and to use DevTools we still need a VM service present as a target as DevTools isn't served by the VM service.

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 3
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Mon, 01 Mar 2021 23:57:07 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Siva Annamalai <as...@google.com>
    Gerrit-MessageType: comment

    Siva Annamalai (Gerrit)

    unread,
    Mar 7, 2021, 10:21:27 PM3/7/21
    to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Ben Konyi.

    View Change

    1 comment:

    • Patchset:

      • Patch Set #5:

        Based on the offline discussion is this CL being reworked on ?

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 5
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Ben Konyi <bko...@google.com>
    Gerrit-Comment-Date: Mon, 08 Mar 2021 03:21:23 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Ben Konyi (Gerrit)

    unread,
    Mar 8, 2021, 2:15:17 PM3/8/21
    to rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    View Change

    1 comment:

    • Patchset:

      • Patch Set #5:

        Based on the offline discussion is this CL being reworked on ?

      • It's on hold until at least end of week after I've sat down with the DevTools folks to get a better idea of what package:devtools_server is responsible for and whether or not we can host DevTools without it or migrate some of its functionality into DDS.

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 5
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Mon, 08 Mar 2021 19:15:13 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No

    Ben Konyi (Gerrit)

    unread,
    Apr 20, 2021, 7:03:57 PM4/20/21
    to rev...@dartlang.org, vm-...@dartlang.org

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    Ben Konyi uploaded patch set #11 to this change.

    View Change

    [ VM / DDS / CLI ] Add DevTools support to the standalone VM

    Example output on stdout when DevTools is enabled:

    Observatory listening on http://127.0.0.1:8181/CzkZzZaONW4=/
    The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8181/devtools/#/?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FCzkZzZaONW4%3D%2Fws

    hello world!

    vm-service: isolate(1674461414267555) 'main' has no debugger attached and is paused at exit. Connect to Observatory at http://127.0.0.1:8181/CzkZzZaONW4=/ to debug.
    Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    ---
    M .dart_tool/package_config.json
    M .packages
    M DEPS
    M pkg/dartdev/lib/dartdev.dart
    M pkg/dartdev/lib/src/commands/run.dart
    M pkg/dartdev/lib/src/sdk.dart
    M pkg/dartdev/test/commands/run_test.dart
    M pkg/dds/CHANGELOG.md
    M pkg/dds/bin/dds.dart
    M pkg/dds/lib/dds.dart
    M pkg/dds/lib/src/client.dart
    M pkg/dds/lib/src/constants.dart
    M pkg/dds/lib/src/dds_impl.dart
    M pkg/dds/pubspec.yaml
    M runtime/bin/main.cc
    M runtime/bin/main_options.cc
    M sdk/BUILD.gn
    M sdk/lib/_internal/vm/bin/vmservice_io.dart
    M sdk/lib/_internal/vm/bin/vmservice_server.dart
    M sdk/lib/vmservice/vmservice.dart
    M third_party/devtools/update.sh
    M tools/bots/test_matrix.json
    M tools/generate_package_config.dart
    M utils/dartdev/BUILD.gn
    24 files changed, 435 insertions(+), 102 deletions(-)

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 11
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-MessageType: newpatchset

    Ben Konyi (Gerrit)

    unread,
    Apr 20, 2021, 7:04:34 PM4/20/21
    to rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    Patch set 11:Commit-Queue +1

    View Change

    3 comments:

    • Patchset:

    • File pkg/dartdev/lib/src/commands/run.dart:

      • That's an option as well, but we don't necessarily want to imply --observe with --devtools since --o […]

        Ack

    • File pkg/dartdev/test/commands/run_test.dart:

      • I'm 99% sure the VM service will take $port and DevTools will try and listen on the next available p […]

        Ack

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 11
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Tue, 20 Apr 2021 23:04:31 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Comment-In-Reply-To: Ben Konyi <bko...@google.com>

    Ben Konyi (Gerrit)

    unread,
    Apr 20, 2021, 7:09:26 PM4/20/21
    to rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    View Change

    1 comment:

    • File .packages:

      • Patch Set #12, Line 42:

        devtools_server:third_party/devtools/devtools_server/lib
        devtools_shared:third_party/devtools/devtools_shared/lib

        Ideally we can drop these deps by copying package:devtools_server/src/server_api.dart into DDS.

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 12
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Tue, 20 Apr 2021 23:09:23 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Ben Konyi (Gerrit)

    unread,
    Apr 20, 2021, 7:13:20 PM4/20/21
    to rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    View Change

    1 comment:

    • File sdk/lib/_internal/vm/bin/vmservice_io.dart:

      • Patch Set #12, Line 61:


        /// Responsible for launching a DevTools instance when the service is started
        /// via SIGQUIT.
        class _DebuggingSession {

        If we want to support SIGQUIT, we'll need to launch DDS from the VM service itself. At this point, maybe it makes more sense for the service to spawn DDS rather than the CLI isolate?

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 12
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Tue, 20 Apr 2021 23:13:17 +0000

    Ben Konyi (Gerrit)

    unread,
    Apr 26, 2021, 2:06:37 PM4/26/21
    to rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Siva Annamalai.

    View Change

    1 comment:

    • File sdk/lib/_internal/vm/bin/vmservice_io.dart:

      • Patch Set #12, Line 61:


        /// Responsible for launching a DevTools instance when the service is started
        /// via SIGQUIT.
        class _DebuggingSession {

      • If we want to support SIGQUIT, we'll need to launch DDS from the VM service itself. […]

        Gave this some more thought, we'd have to make this configurable by the embedder if we just wanted to start DDS from the VM service (e.g., Flutter wouldn't want to start DDS on device as flutter_tools would spawn its own instance on the host). Maybe something to think about in the future.

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 15
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Mon, 26 Apr 2021 18:06:32 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Ben Konyi <bko...@google.com>
    Gerrit-MessageType: comment

    Siva Annamalai (Gerrit)

    unread,
    Apr 27, 2021, 7:58:47 PM4/27/21
    to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Ryan Macnak, Devon Carew, Kenzie Schmoll, Jacob Richman, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Ben Konyi.

    Patch set 15:Code-Review +1

    View Change

    7 comments:

    • File .packages:

      • Patch Set #12, Line 42:

        devtools_server:third_party/devtools/devtools_server/lib
        devtools_shared:third_party/devtools/devtools_shared/lib

        Ideally we can drop these deps by copying package:devtools_server/src/server_api.dart into DDS.

      • Do we need a TODO here for that change ?

    • Patchset:

      • Patch Set #15:

        lgtm with some comments. I think we should have Kenzie or Jacob also review the code in devtools_client.dart and devtools_handler.dart

    • File pkg/dartdev/lib/src/commands/run.dart:

      • Patch Set #15, Line 165: hide: true,

        default value for this would be false correct also no help text ?
        Should this be visible in verbose mode? i.e hide: !verbose

      • Patch Set #15, Line 187: // TODO(bkonyi): remove?

        Can we have issue numbers instead of ldaps for TODO.

      • Patch Set #15, Line 270: : absolute(dirname(sdk.dart), 'devtools');

        should you hoist 'dirname(sdk.dart)' into a temp ?

      • Patch Set #15, Line 303: 'A DevTools debugger for DDS is available at: $ddsDebuggingUri',

        why not just
        'A DevTools debugger and profiler is available at ...."

    • File runtime/bin/main.cc:

      • Patch Set #15, Line 561: bool wait_for_dds_to_advertise_service = !Options::disable_dart_dev();

        Why are we dropping Options::enable_vm_service() now, I remember this change being made as part of a issue raised earlier.

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 15
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Jacob Richman <jac...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-CC: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Ben Konyi <bko...@google.com>
    Gerrit-Comment-Date: Tue, 27 Apr 2021 23:58:42 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes

    Ben Konyi (Gerrit)

    unread,
    Apr 27, 2021, 9:38:53 PM4/27/21
    to rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

    View Change

    6 comments:

    • File .packages:

      • Patch Set #12, Line 42:

        devtools_server:third_party/devtools/devtools_server/lib
        devtools_shared:third_party/devtools/devtools_shared/lib

      • Do we need a TODO here for that change ?

        I'd like to do that as part of this CL, just need some input from DevTools folks to confirm.

    • Patchset:

    • File pkg/dartdev/lib/src/commands/run.dart:

      • default value for this would be false correct also no help text ? […]

        Default value is false since it's a flag. It's just completely hidden at this point since it's not meant to be used by anyone who's not working on DDS.

      • This is more of a note for myself. It'll be removed before this lands.

      • why not just […]

        This is only handling the DDS case, so I figured I'd make it more explicit so it's clear which process the URI is from.

    • File runtime/bin/main.cc:

      • Why are we dropping Options::enable_vm_service() now, I remember this change being made as part of a […]

        We're dropping this now to support the SIGQUIT case (that's actually why this was added in before). The VM service will launch DDS when started via SIGQUIT, so we want the service to wait for DDS to connect before advertising its URI.

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 15
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Jacob Richman <jac...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Wed, 28 Apr 2021 01:38:49 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Ben Konyi <bko...@google.com>

    Ben Konyi (Gerrit)

    unread,
    Apr 27, 2021, 9:38:53 PM4/27/21
    to Jacob Richman, Kenzie Schmoll, rev...@dartlang.org, vm-...@dartlang.org, Siva Annamalai, Ryan Macnak

    Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

    Ben Konyi would like Jacob Richman and Kenzie Schmoll to review this change.

    View Change

    [ VM / DDS / CLI ] Add DevTools support to the standalone VM

    Example output on stdout when DevTools is enabled:

    Observatory listening on http://127.0.0.1:8181/CzkZzZaONW4=/
    The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8181/devtools/#/?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FCzkZzZaONW4%3D%2Fws
    hello world!

    vm-service: isolate(1674461414267555) 'main' has no debugger attached and is paused at exit. Connect to Observatory at http://127.0.0.1:8181/CzkZzZaONW4=/ to debug.
    Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    ---
    M .dart_tool/package_config.json
    M .packages
    M DEPS
    M pkg/dartdev/lib/dartdev.dart
    M pkg/dartdev/lib/src/commands/run.dart
    M pkg/dartdev/lib/src/sdk.dart
    M pkg/dartdev/test/commands/run_test.dart
    M pkg/dds/CHANGELOG.md
    M pkg/dds/bin/dds.dart
    M pkg/dds/lib/dds.dart
    M pkg/dds/lib/src/client.dart
    M pkg/dds/lib/src/constants.dart
    M pkg/dds/lib/src/dds_impl.dart
    A pkg/dds/lib/src/devtools/devtools_client.dart
    A pkg/dds/lib/src/devtools/devtools_handler.dart

    M pkg/dds/pubspec.yaml
    M runtime/bin/main.cc
    M runtime/bin/main_options.cc
    M sdk/BUILD.gn
    M sdk/lib/_internal/vm/bin/vmservice_io.dart
    M sdk/lib/_internal/vm/bin/vmservice_server.dart
    M sdk/lib/vmservice/vmservice.dart
    M third_party/devtools/update.sh
    M tools/bots/test_matrix.json
    M tools/generate_package_config.dart
    M utils/dartdev/BUILD.gn
    26 files changed, 611 insertions(+), 103 deletions(-)

    diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
    index 5bd7c51..1ae3a58 100644

    --- a/.dart_tool/package_config.json
    +++ b/.dart_tool/package_config.json
    @@ -11,7 +11,7 @@
    "constraint, update this by running tools/generate_package_config.dart."
    ],
    "configVersion": 2,
    -  "generated": "2021-04-16T13:34:20.183158",
    + "generated": "2021-04-21T11:18:31.921159",
    "generator": "tools/generate_package_config.dart",
    "packages": [
    {
    @@ -253,6 +253,18 @@

    "languageVersion": "2.3"
    },
    {
    + "name": "devtools_server",
    + "rootUri": "../third_party/devtools/devtools_server",
    + "packageUri": "lib/",
    + "languageVersion": "2.6"
    + },
    + {
    + "name": "devtools_shared",
    + "rootUri": "../third_party/devtools/devtools_shared",
    + "packageUri": "lib/",
    + "languageVersion": "2.3"
    + },
    + {
    "name": "diagnostic",
    "rootUri": "../pkg/diagnostic",
    "packageUri": "lib/",
    diff --git a/.packages b/.packages
    index af07227..873baad 100644
    --- a/.packages
    +++ b/.packages
    @@ -22,6 +22,7 @@
    boolean_selector:third_party/pkg/boolean_selector/lib
    browser_launcher:third_party/pkg/browser_launcher/lib

    build_integration:pkg/build_integration/lib
    +browser_launcher:third_party/pkg/browser_launcher/lib
    charcode:third_party/pkg/charcode/lib
    cli_util:third_party/pkg/cli_util/lib
    collection:third_party/pkg/collection/lib
    @@ -38,6 +39,8 @@

    dartdoc:third_party/pkg/dartdoc/lib
    dds:pkg/dds/lib
    dev_compiler:pkg/dev_compiler/lib
    +devtools_server:third_party/devtools/devtools_server/lib
    +devtools_shared:third_party/devtools/devtools_shared/lib
    diagnostic:pkg/diagnostic/lib
    expect:pkg/expect/lib
    ffi:third_party/pkg/ffi/lib
    diff --git a/DEPS b/DEPS
    index 7c4b97d..10276eb 100644
    --- a/DEPS
    +++ b/DEPS
    @@ -80,6 +80,7 @@

    "boringssl_gen_rev": "7322fc15cc065d8d2957fccce6b62a509dc4d641",
    "boringssl_rev" : "1607f54fed72c6589d560254626909a64124f091",
    "browser-compat-data_tag": "v1.0.22",
    +  "browser_launcher_rev": "12ab9f351a44ac803de9bc17bb2180bb312a9dd7",

    "charcode_rev": "bcd8a12c315b7a83390e4865ad847ecd9344cba2",
    "chrome_rev" : "19997",
    "cli_util_rev" : "fd1b716e8a350a454e01ae56df540293d31ff6c8",
    @@ -105,7 +106,6 @@
    "dart_style_rev": "f17c23e0eea9a870601c19d904e2a9c1a7c81470",

    "chromedriver_tag": "83.0.4103.39",
    - "browser_launcher_rev": "12ab9f351a44ac803de9bc17bb2180bb312a9dd7",
    "dartdoc_rev" : "505f163f7cb48e917503e4a23fbff1227e08b263",
    "ffi_rev": "f3346299c55669cc0db48afae85b8110088bf8da",
    "fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
    @@ -228,7 +228,7 @@

    Var("dart_root") + "/third_party/devtools": {
    "packages": [{
    "package": "dart/third_party/flutter/devtools",
    - "version": "revision:6729ec62c3548839018c32fa711756202431ccf7",
    +          "version": "git_revision:12ad5341ae0a275042c84a4e7be9a6c98db65612",

    }],
    "dep_type": "cipd",
    },
    @@ -301,6 +301,9 @@

    Var('chromium_git') + '/external/github.com/mdn/browser-compat-data' +
    "@" + Var("browser-compat-data_tag"),

    + Var("dart_root") + "/third_party/pkg/browser_launcher":
    + Var("dart_git") + "browser_launcher.git" + "@" + Var("browser_launcher_rev"),
    +
    Var("dart_root") + "/third_party/tcmalloc/gperftools":
    Var('chromium_git') + '/external/github.com/gperftools/gperftools.git' +
    "@" + Var("gperftools_revision"),
    @@ -317,9 +320,6 @@
    Var("dart_root") + "/third_party/pkg/boolean_selector":
    Var("dart_git") + "boolean_selector.git" +
    "@" + Var("boolean_selector_rev"),
    - Var("dart_root") + "/third_party/pkg/browser_launcher":
    - Var("dart_git") + "browser_launcher.git" +
    - "@" + Var("browser_launcher_rev"),
    Var("dart_root") + "/third_party/pkg/charcode":
    Var("dart_git") + "charcode.git" + "@" + Var("charcode_rev"),
    Var("dart_root") + "/third_party/pkg/cli_util":
    diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
    index b72fbba..5e581c5 100644

    --- a/pkg/dartdev/lib/dartdev.dart
    +++ b/pkg/dartdev/lib/dartdev.dart
    @@ -40,7 +40,8 @@
    args = args
    .where(
    (element) => !(element.contains('--observe') ||
    - element.contains('--enable-vm-service')),
    + element.contains('--enable-vm-service') ||
    + element.contains('--devtools')),
    )
    .toList();
    }
    diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
    index db32bfe..052d372 100644
    --- a/pkg/dartdev/lib/src/commands/run.dart
    +++ b/pkg/dartdev/lib/src/commands/run.dart
    @@ -57,6 +57,7 @@

    valueHelp: '[<port>[/<bind-address>]]',
    )
    ..addOption('launch-dds', hide: true, help: 'Launch DDS.')
    + ..addOption('launch-devtools', hide: true, help: 'Launch DevTools.')
    ..addSeparator(
    'Options implied by --observe are currently:',
    )
    @@ -158,6 +159,10 @@
    hide: !verbose,
    negatable: false,
    help: 'Enables tracing of library and script loading.',
    + )
    + ..addFlag(
    + 'debug-dds',
    + hide: true,
    );
    addExperimentalFlags(argParser, verbose);
    }
    @@ -179,13 +184,16 @@

    String launchDdsArg = argResults['launch-dds'];
    String ddsHost = '';
    String ddsPort = '';
    +    // TODO(bkonyi): remove?
    + const bool launchDevTools = true;

    bool launchDds = false;
    if (launchDdsArg != null) {
    launchDds = true;
    - final ddsUrl = launchDdsArg.split(':');
    + final ddsUrl = launchDdsArg.split('\\:');
    ddsHost = ddsUrl[0];
    ddsPort = ddsUrl[1];
    }
    +    final bool debugDds = argResults['debug-dds'];


    bool disableServiceAuthCodes = argResults['disable-service-auth-codes'];

    @@ -198,7 +206,12 @@

    if (launchDds) {
    debugSession = _DebuggingSession();
    if (!await debugSession.start(
    - ddsHost, ddsPort, disableServiceAuthCodes)) {
    + ddsHost,
    + ddsPort,
    + disableServiceAuthCodes,
    + launchDevTools,
    +        debugDds,
    + )) {
    return errorExitCode;
    }
    }
    @@ -242,10 +255,19 @@


    class _DebuggingSession {
    Future<bool> start(
    - String host, String port, bool disableServiceAuthCodes) async {
    -    final ddsSnapshot = (dirname(sdk.dart).endsWith('bin'))
    +    String host,
    + String port,
    + bool disableServiceAuthCodes,
    + bool enableDevTools,
    +    bool debugDds,
    + ) async {

    + final fullSdk = dirname(sdk.dart).endsWith('bin');
    + final ddsSnapshot = fullSdk
    ? sdk.ddsSnapshot
    : absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot');
    + final devToolsBinaries = fullSdk
    + ? sdk.devToolsBinaries
    + : absolute(dirname(sdk.dart), 'devtools');
    if (!Sdk.checkArtifactExists(ddsSnapshot)) {
    return false;
    }
    @@ -256,30 +278,50 @@
    serviceInfo = await Service.getInfo();

    }
    final process = await Process.start(
    - sdk.dart,
    - [
    - if (dirname(sdk.dart).endsWith('bin'))
    - sdk.ddsSnapshot
    - else
    - absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot'),
    - serviceInfo.serverUri.toString(),
    - host,
    - port,
    - disableServiceAuthCodes.toString(),
    - ],
    - mode: ProcessStartMode.detachedWithStdio);
    + sdk.dart,
    + [
    +        if (debugDds) '--enable-vm-service=0',

    + ddsSnapshot,
    + serviceInfo.serverUri.toString(),
    + host,
    + port,
    + disableServiceAuthCodes.toString(),
    + enableDevTools.toString(),
    +        devToolsBinaries,
    + ],
    + mode: ProcessStartMode.detachedWithStdio,
    + );
    final completer = Completer<void>();
    -    StreamSubscription sub;
    - sub = process.stderr.transform(utf8.decoder).listen((event) {

    - if (event == 'DDS started') {
    -        sub.cancel();
    + const devToolsMessagePrefix =
    + 'The Dart DevTools debugger and profiler is available at:';
    + if (debugDds) {
    + StreamSubscription stdoutSub;
    + stdoutSub = process.stdout.transform(utf8.decoder).listen((event) {
    + if (event.startsWith(devToolsMessagePrefix)) {
    + final ddsDebuggingUri = event.split(' ').last;
    + print(
    + 'A DevTools debugger for DDS is available at: $ddsDebuggingUri',
    + );
    + stdoutSub.cancel();
    + }
    + });
    + }
    + StreamSubscription stderrSub;
    + stderrSub = process.stderr.transform(utf8.decoder).listen((event) {

    + final result = json.decode(event) as Map<String, dynamic>;
    + final state = result['state'];
    + if (state == 'started') {
    + if (result.containsKey('devToolsUri')) {
    + final devToolsUri = result['devToolsUri'];
    +          print('$devToolsMessagePrefix $devToolsUri');
    + }
    + stderrSub.cancel();

    completer.complete();
    - } else if (event.contains('Failed to start DDS')) {
    -        sub.cancel();

    - completer.completeError(event.replaceAll(
    - 'Failed to start DDS',
    +      } else {
    + stderrSub.cancel();

    + completer.completeError(
    'Could not start Observatory HTTP server',
    - ));
    + );
    }
    });
    try {
    diff --git a/pkg/dartdev/lib/src/sdk.dart b/pkg/dartdev/lib/src/sdk.dart
    index 3e8a12a..426f810 100644
    --- a/pkg/dartdev/lib/src/sdk.dart
    +++ b/pkg/dartdev/lib/src/sdk.dart
    @@ -68,6 +68,13 @@
    'dds.dart.snapshot',
    );

    + String get devToolsBinaries => path.absolute(
    + sdkPath,
    + 'bin',
    + 'resources',
    + 'devtools',
    + );
    +
    String get pubSnapshot => path.absolute(
    sdkPath,
    'bin',
    diff --git a/pkg/dartdev/test/commands/run_test.dart b/pkg/dartdev/test/commands/run_test.dart
    index b8cc5e8..58a4d56 100644
    --- a/pkg/dartdev/test/commands/run_test.dart
    +++ b/pkg/dartdev/test/commands/run_test.dart
    @@ -2,6 +2,8 @@

    // for details. All rights reserved. Use of this source code is governed by a
    // BSD-style license that can be found in the LICENSE file.

    +import 'dart:async';

    +import 'dart:convert';
    import 'dart:io';

     import 'package:path/path.dart' as path;
    @@ -300,4 +302,61 @@

    expect(result.stderr, isEmpty);
    expect(result.exitCode, 0);
    });
    +
    + group('DevTools', () {
    + const devToolsMessagePrefix =
    +        'The Dart DevTools debugger and profiler is available at: http://127.0.0.1:';

    +
    + test('spawn simple', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + ProcessResult result = p.runSync([
    + 'run',
    + '--enable-vm-service',
    +        p.relativeFilePath,
    + ]);
    + expect(result.stdout, contains(devToolsMessagePrefix));

    + });
    +
    + test('implicit spawn', () async {
    + p = project(mainSrc: "void main() { print('Hello World'); }");
    + ProcessResult result = p.runSync([
    + '--enable-vm-service',
    +        p.relativeFilePath,
    + ]);
    + expect(result.stdout, contains(devToolsMessagePrefix));

    + });
    +
    + test(
    +      'spawn via SIGQUIT',
    + () async {
    + p = project(
    + mainSrc:
    + 'void main() { print("ready"); int i = 0; while(true) { i++; } }',
    + );
    + Process process = await p.start([

    + p.relativeFilePath,
    + ]);
    +
    +        final readyCompleter = Completer<void>();
    + final completer = Completer<void>();
    +
    + StreamSubscription sub;
    + sub = process.stdout.transform(utf8.decoder).listen((event) async {
    + if (event.contains('ready')) {
    + readyCompleter.complete();
    + } else if (event.contains(devToolsMessagePrefix)) {
    + await sub.cancel();
    + completer.complete();
    + }
    + });
    + // Wait for process to start.
    + await readyCompleter.future;
    + process.kill(ProcessSignal.sigquit);
    + await completer.future;
    + process.kill();
    + },
    + // No support for SIGQUIT on Windows.
    + skip: Platform.isWindows,

    + );
    + });
    }
    diff --git a/pkg/dds/CHANGELOG.md b/pkg/dds/CHANGELOG.md
    index 3db7549..b39156e 100644
    --- a/pkg/dds/CHANGELOG.md
    +++ b/pkg/dds/CHANGELOG.md
    @@ -1,4 +1,5 @@
    -# 1.7.7-dev

    +# 1.8.0-dev
    +- Add support for launching DevTools from DDS.
     - Fixed issue where two clients subscribing to the same stream in close succession
    could result in DDS sending multiple `streamListen` requests to the VM service.

    diff --git a/pkg/dds/bin/dds.dart b/pkg/dds/bin/dds.dart
    index 9937d26..b240af3 100644
    --- a/pkg/dds/bin/dds.dart
    +++ b/pkg/dds/bin/dds.dart
    @@ -4,6 +4,7 @@

    // @dart=2.10


    +import 'dart:convert';
    import 'dart:io';

    import 'package:dds/dds.dart';
    @@ -16,6 +17,8 @@

    /// - DDS bind address
    /// - DDS port
    /// - Disable service authentication codes
    +/// - Start DevTools
    +///   - DevTools build directory
    Future<void> main(List<String> args) async {
    if (args.isEmpty) return;

    @@ -37,16 +40,35 @@

    port: int.parse(args[2]),
    );
    final disableServiceAuthCodes = args[3] == 'true';
    +
    + final startDevTools = args[4] == 'true';
    +  Uri devToolsBuildDirectory;
    + if (args[5].isNotEmpty) {
    +    devToolsBuildDirectory = Uri.parse(args[5]);

    + }
    try {
    // TODO(bkonyi): add retry logic similar to that in vmservice_server.dart
    // See https://github.com/dart-lang/sdk/issues/43192.
    - await DartDevelopmentService.startDartDevelopmentService(
    + final dds = await DartDevelopmentService.startDartDevelopmentService(
    remoteVmServiceUri,
    serviceUri: serviceUri,
    enableAuthCodes: !disableServiceAuthCodes,
    + devToolsConfiguration: startDevTools
    + ? DevToolsConfiguration(
    + enable: startDevTools,
    +              customBuildDirectoryPath: devToolsBuildDirectory,
    + )
    + : null,
    );
    - stderr.write('DDS started');
    - } catch (e) {
    - stderr.writeln('Failed to start DDS:\n$e');
    + stderr.write(json.encode({
    + 'state': 'started',
    + if (dds.devToolsUri != null) 'devToolsUri': dds.devToolsUri.toString(),
    + }));
    + } catch (e, st) {
    + stderr.write(json.encode({
    + 'state': 'error',
    + 'error': '$e',
    + 'stacktrace': '$st',
    + }));
    }
    }
    diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart
    index f7c7a05..8dba361 100644
    --- a/pkg/dds/lib/dds.dart
    +++ b/pkg/dds/lib/dds.dart
    @@ -44,6 +44,7 @@

    Uri serviceUri,
    bool enableAuthCodes = true,
    bool ipv6 = false,
    +    DevToolsConfiguration devToolsConfiguration = const DevToolsConfiguration(),

    }) async {
    if (remoteVmServiceUri == null) {
    throw ArgumentError.notNull('remoteVmServiceUri');
    @@ -80,6 +81,7 @@

    serviceUri,
    enableAuthCodes,
    ipv6,
    + devToolsConfiguration,
    );
    await service.startService();
    return service;
    @@ -125,6 +127,11 @@

    /// Returns `null` if the service is not running.
    Uri get wsUri;

    + /// The HTTP [Uri] of the hosted DevTools instance.
    + ///
    + /// Returns `null` if DevTools is not running.
    + Uri get devToolsUri;
    +
    /// Set to `true` if this instance of [DartDevelopmentService] is accepting
    /// requests.
    bool get isRunning;
    @@ -168,3 +175,13 @@

    final int errorCode;
    final String message;
    }
    +
    +class DevToolsConfiguration {
    +  const DevToolsConfiguration({

    + this.enable = false,
    + this.customBuildDirectoryPath,
    +  });
    +
    + final bool enable;
    + final Uri customBuildDirectoryPath;
    +}
    diff --git a/pkg/dds/lib/src/client.dart b/pkg/dds/lib/src/client.dart
    index f81bd25..9ceb162 100644
    --- a/pkg/dds/lib/src/client.dart
    +++ b/pkg/dds/lib/src/client.dart
    @@ -21,27 +21,25 @@
    /// Representation of a single DDS client which manages the connection and
    /// DDS request intercepting / forwarding.
    class DartDevelopmentServiceClient {
    - factory DartDevelopmentServiceClient.fromWebSocket(
    + DartDevelopmentServiceClient.fromWebSocket(
    DartDevelopmentService dds,
    WebSocketChannel ws,
    json_rpc.Peer vmServicePeer,
    - ) =>
    - DartDevelopmentServiceClient._(
    - dds,
    - ws,
    - vmServicePeer,
    - );
    + ) : this._(
    + dds,
    + ws,
    + vmServicePeer,
    + );

    - factory DartDevelopmentServiceClient.fromSSEConnection(
    + DartDevelopmentServiceClient.fromSSEConnection(
    DartDevelopmentService dds,
    SseConnection sse,
    json_rpc.Peer vmServicePeer,
    - ) =>
    - DartDevelopmentServiceClient._(
    - dds,
    - sse,
    - vmServicePeer,
    - );
    + ) : this._(
    + dds,
    + sse,
    + vmServicePeer,
    + );

    DartDevelopmentServiceClient._(
    this.dds,
    diff --git a/pkg/dds/lib/src/constants.dart b/pkg/dds/lib/src/constants.dart
    index 2466390..b69ae7c 100644
    --- a/pkg/dds/lib/src/constants.dart
    +++ b/pkg/dds/lib/src/constants.dart
    @@ -16,6 +16,10 @@
    };
    }

    +// Give connections time to reestablish before considering them closed.
    +// Required to reestablish connections killed by UberProxy.
    +const sseKeepAlive = Duration(seconds: 30);
    +
    abstract class PauseTypeMasks {
    static const pauseOnStartMask = 1 << 0;
    static const pauseOnReloadMask = 1 << 1;
    diff --git a/pkg/dds/lib/src/dds_impl.dart b/pkg/dds/lib/src/dds_impl.dart
    index db355fb..5d24ec1 100644
    --- a/pkg/dds/lib/src/dds_impl.dart
    +++ b/pkg/dds/lib/src/dds_impl.dart
    @@ -24,6 +24,8 @@
    import 'binary_compatible_peer.dart';
    import 'client.dart';
    import 'client_manager.dart';
    +import 'constants.dart';
    +import 'devtools/devtools_handler.dart';
    import 'expression_evaluator.dart';
    import 'isolate_manager.dart';
    import 'stream_manager.dart';
    @@ -51,12 +53,17 @@


    class DartDevelopmentServiceImpl implements DartDevelopmentService {
    DartDevelopmentServiceImpl(
    - this._remoteVmServiceUri, this._uri, this._authCodesEnabled, this._ipv6) {
    + this._remoteVmServiceUri,
    + this._uri,
    + this._authCodesEnabled,
    + this._ipv6,
    + this._devToolsConfiguration,
    + ) {
    _clientManager = ClientManager(this);
    _expressionEvaluator = ExpressionEvaluator(this);
    _isolateManager = IsolateManager(this);
         _streamManager = StreamManager(this);
    - _authCode = _authCodesEnabled ? _makeAuthToken() : '';
    + authCode = _authCodesEnabled ? _makeAuthToken() : '';
    }

    Future<void> startService() async {
    @@ -117,6 +124,9 @@
    // Start the DDS server.
    _server = await io.serve(
    const Pipeline()
    + .addMiddleware(logRequests(logger: (String message, bool isError) {
    + print('Log: $message');
    + }))
    .addMiddleware(_authCodeMiddleware)
    .addHandler(_handlers().handler),
    host,
    @@ -126,7 +136,7 @@
    scheme: 'http',
    host: host,
    port: _server.port,
    - path: '$_authCode/',
    + path: '$authCode/',
    );

    // Notify the VM service that this client is DDS and that it should close
    @@ -157,7 +167,7 @@
    return;
    }
    _shuttingDown = true;
    - // Don't accept anymore HTTP requests.
    + // Don't accept any more HTTP requests.
    await _server?.close();


    // Close connections to clients.
    @@ -197,7 +207,7 @@
    return forbidden;
    }
    final authToken = pathSegments[0];
    - if (authToken != _authCode) {
    + if (authToken != authCode) {
    return forbidden;
    }
    // Creates a new request with the authentication code stripped from
    @@ -233,18 +243,12 @@
    });

    Handler _sseHandler() {
    - // Give connections time to reestablish before considering them closed.
    - // Required to reestablish connections killed by UberProxy.
    - const keepAlive = Duration(seconds: 30);
    - final handler = authCodesEnabled
    - ? SseHandler(
    - Uri.parse('/$_authCode/$_kSseHandlerPath'),
    - keepAlive: keepAlive,
    - )
    - : SseHandler(
    - Uri.parse('/$_kSseHandlerPath'),
    - keepAlive: keepAlive,
    - );
    + final handler = SseHandler(
    + authCodesEnabled
    + ? Uri.parse('/$authCode/$_kSseHandlerPath')
    + : Uri.parse('/$_kSseHandlerPath'),
    + keepAlive: sseKeepAlive,
    + );

    handler.connections.rest.listen((sseConnection) {
    final client = DartDevelopmentServiceClient.fromSSEConnection(
    @@ -259,10 +263,18 @@
    }

    Handler _httpHandler() {
    - // DDS doesn't support any HTTP requests itself, so we just forward all of
    - // them to the VM service.
    - final cascade = Cascade().add(proxyHandler(remoteVmServiceUri));
    - return cascade.handler;
    + if (_devToolsConfiguration != null && _devToolsConfiguration.enable) {
    + // Install the DevTools handlers and forward any unhandled HTTP requests to
    + // the VM service.

    + final buildDir =
    + _devToolsConfiguration.customBuildDirectoryPath?.toFilePath();
    +      return devtoolsHandler(
    + dds: this,
    + buildDir: buildDir,
    + notFoundHandler: proxyHandler(remoteVmServiceUri),
    + );
    + }
    + return proxyHandler(remoteVmServiceUri);
    }

    List<String> _cleanupPathSegments(Uri uri) {
    @@ -296,13 +308,39 @@
    return uri.replace(scheme: 'sse', pathSegments: pathSegments);
    }

    + Uri _toDevTools(Uri uri) {
    + // The DevTools URI is a bit strange as the query parameters appear after
    + // the fragment. There's no nice way to encode the query parameters
    + // properly, so we create another Uri just to grab the formatted query.
    + // The result will need to have '/?' prepended when being used as the
    + // fragment to get the correct format.
    + final query = Uri(
    + queryParameters: {
    + 'uri': wsUri.toString(),
    + },
    + ).query;
    + return Uri(
    + scheme: 'http',
    + host: uri.host,
    + port: uri.port,
    + pathSegments: [
    + ...uri.pathSegments.where(
    + (e) => e.isNotEmpty,
    + ),
    + 'devtools',
    + '',
    + ],
    + fragment: '/?$query',
    + );
    + }
    +
    String getNamespace(DartDevelopmentServiceClient client) =>
    clientManager.clients.keyOf(client);

    @override
    bool get authCodesEnabled => _authCodesEnabled;
    final bool _authCodesEnabled;
    - String _authCode;
    + String authCode;

    @override
    Uri get remoteVmServiceUri => _remoteVmServiceUri;
    @@ -313,17 +351,21 @@

    @override
    Uri get uri => _uri;
    + Uri _uri;

    @override
    Uri get sseUri => _toSse(_uri);


    Uri get wsUri => _toWebSocket(_uri);
    -  Uri _uri;
    +
    + Uri get devToolsUri => _toDevTools(_uri);


    final bool _ipv6;

    bool get isRunning => _uri != null;

    + final DevToolsConfiguration _devToolsConfiguration;
    +
    Future<void> get done => _done.future;
    Completer _done = Completer<void>();
    bool _shuttingDown = false;
    diff --git a/pkg/dds/lib/src/devtools/devtools_client.dart b/pkg/dds/lib/src/devtools/devtools_client.dart
    new file mode 100644
    index 0000000..72bff09
    --- /dev/null
    +++ b/pkg/dds/lib/src/devtools/devtools_client.dart
    @@ -0,0 +1,88 @@
    +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
    +// for details. All rights reserved. Use of this source code is governed by a
    +// BSD-style license that can be found in the LICENSE file.
    +
    +// @dart=2.9
    +
    +import 'dart:async';
    +
    +import 'package:devtools_server/src/server_api.dart';
    +import 'package:json_rpc_2/src/server.dart' as json_rpc;
    +import 'package:sse/src/server/sse_handler.dart';
    +import 'package:stream_channel/stream_channel.dart';
    +
    +class LoggingMiddlewareSink<S> implements StreamSink<S> {
    + LoggingMiddlewareSink(this.sink);
    +
    + @override
    + void add(S event) {
    + print('DevTools SSE response: $event');
    + sink.add(event);
    + }
    +
    + @override
    + void addError(Object error, [StackTrace stackTrace]) {
    + print('DevTools SSE error response: $error');
    + sink.addError(error);
    + }
    +
    + @override
    + Future addStream(Stream<S> stream) {
    + return sink.addStream(stream);
    + }
    +
    + @override
    + Future close() => sink.close();
    +
    + @override
    + Future get done => sink.done;
    +
    + final StreamSink sink;
    +}
    +
    +/// Represents a DevTools client connection to the DevTools server API.
    +class DevToolsClient {
    + DevToolsClient.fromSSEConnection(
    + SseConnection sse,
    + ) : _server = json_rpc.Server(
    + StreamChannel(
    + sse.stream.map<String>((String e) {
    + print('DevTools SSE event: $e');
    + return e;
    + }),
    + LoggingMiddlewareSink(sse.sink),
    + ),
    + strictProtocolChecks: false,
    + ) {
    + _registerJsonRpcMethods();
    + _server.listen();
    + }
    +
    + void _registerJsonRpcMethods() {
    + _server.registerMethod('connected', (parameters) {
    + // TODO: implement
    + });
    +
    + _server.registerMethod('currentPage', (parameters) {
    + // TODO: implement
    + });
    +
    + _server.registerMethod('disconnected', (parameters) {
    + // TODO: implement
    + });
    +
    + _server.registerMethod('getPreferenceValue', (parameters) {
    + final key = parameters['key'].asString;
    + final value = ServerApi.devToolsPreferences.properties[key];
    + return value;
    + });
    +
    + _server.registerMethod('setPreferenceValue', (parameters) {
    + final key = parameters['key'].asString;
    + final value = parameters['value'].value;
    + ServerApi.devToolsPreferences.properties[key] = value;
    + });
    + }
    +
    + final json_rpc.Server _server;
    +}
    diff --git a/pkg/dds/lib/src/devtools/devtools_handler.dart b/pkg/dds/lib/src/devtools/devtools_handler.dart
    new file mode 100644
    index 0000000..ec9230b
    --- /dev/null
    +++ b/pkg/dds/lib/src/devtools/devtools_handler.dart
    @@ -0,0 +1,86 @@
    +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
    +// for details. All rights reserved. Use of this source code is governed by a
    +// BSD-style license that can be found in the LICENSE file.
    +
    +// @dart=2.9
    +
    +import 'dart:async';
    +
    +import 'package:dds/src/constants.dart';
    +import 'package:devtools_server/src/server_api.dart';
    +import 'package:meta/meta.dart';
    +import 'package:shelf/shelf.dart';
    +import 'package:shelf_static/shelf_static.dart';
    +import 'package:sse/server/sse_handler.dart';
    +
    +import '../dds_impl.dart';
    +import 'devtools_client.dart';
    +
    +/// Returns a [Handler] which handles serving DevTools and the DevTools server
    +/// API under $DDS_URI/devtools/.
    +///
    +/// [buildDir] is the path to the pre-compiled DevTools instance to be served.
    +///
    +/// [notFoundHandler] is a [Handler] to which requests that could not be handled
    +/// by the DevTools handler are forwarded (e.g., a proxy to the VM service).
    +FutureOr<Handler> devtoolsHandler({
    + @required DartDevelopmentServiceImpl dds,
    + @required String buildDir,
    + @required Handler notFoundHandler,
    +}) {
    + // Serves the web assets for DevTools.
    + final devtoolsAssetHandler = createStaticHandler(
    + buildDir,
    + defaultDocument: 'index.html',
    + );
    +
    + // Support DevTools client-server interface via SSE.
    + // Note: the handler path needs to match the full *original* path, not the
    + // current request URL (we remove '/devtools' in the initial router but we
    + // need to include it here).
    + const devToolsSseHandlerPath = '/devtools/api/sse';
    + final devToolsApiHandler = SseHandler(
    + dds.authCodesEnabled
    + ? Uri.parse('/${dds.authCode}$devToolsSseHandlerPath')
    + : Uri.parse(devToolsSseHandlerPath),
    + keepAlive: sseKeepAlive,
    + );
    +
    + devToolsApiHandler.connections.rest.listen(
    + (sseConnection) => DevToolsClient.fromSSEConnection(
    + sseConnection,
    + ),
    + );
    +
    + final devtoolsHandler = (Request request) {
    + // If the request isn't of the form api/<method> assume it's a request for
    + // DevTools assets.
    + if (request.url.pathSegments.length < 2 ||
    + request.url.pathSegments.first != 'api') {
    + return devtoolsAssetHandler(request);
    + }
    + final method = request.url.pathSegments[1];
    + if (method == 'ping') {
    + // Note: we have an 'OK' body response, otherwise the response has an
    + // incorrect status code (204 instead of 200).
    + return Response.ok('OK');
    + }
    + if (method == 'sse') {
    + return devToolsApiHandler.handler(request);
    + }
    + if (!ServerApi.canHandle(request)) {
    + return Response.notFound('$method is not a valid API');
    + }
    + return ServerApi.handle(request);
    + };
    +
    + return (request) {
    + final pathSegments = request.url.pathSegments;
    + if (pathSegments.isEmpty || pathSegments.first != 'devtools') {
    + return notFoundHandler(request);
    + }
    + // Forward all requests to /devtools/* to the DevTools handler.
    + request = request.change(path: 'devtools');
    + return devtoolsHandler(request);
    + };
    +}
    diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
    index 221e3df..38d647b 100644

    --- a/pkg/dds/pubspec.yaml
    +++ b/pkg/dds/pubspec.yaml
    @@ -3,7 +3,7 @@
    A library used to spawn the Dart Developer Service, used to communicate with
    a Dart VM Service instance.

    -version: 1.7.6
    @@ -12,11 +12,13 @@


    dependencies:
    async: ^2.4.1
    + devtools_server: ^2.0.0
       json_rpc_2: ^2.2.0
    meta: ^1.1.8
    pedantic: ^1.7.0
       shelf: ^1.0.0
    shelf_proxy: ^1.0.0
    + shelf_static: ^1.0.0-dev
    shelf_web_socket: ^1.0.0
    sse: ^3.7.0
    stream_channel: ^2.0.0
    @@ -24,6 +26,5 @@
    web_socket_channel: ^2.0.0

    dev_dependencies:
    - shelf_static: ^1.0.0
    test: ^1.0.0
    webdriver: ^3.0.0
    diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
    index 67d9c2d..95c7166 100644
    --- a/runtime/bin/main.cc
    +++ b/runtime/bin/main.cc
    @@ -553,13 +553,12 @@
    vm_service_server_port = 0;
    }

    - // We do not want to wait for DDS to advertise availability of VM service in the
    - // following scenarios:
    - // - When the VM service is disabled (can be started at a later time via SIGQUIT).
    - // - The DartDev CLI is disabled (CLI isolate starts DDS) and VM service is enabled.
    - bool wait_for_dds_to_advertise_service =
    - !Options::disable_dart_dev() && Options::enable_vm_service();
    -
    + // We do not want to wait for DDS to advertise availability of VM service in
    + // the following scenarios:
    + // - The DartDev CLI is disabled (CLI isolate starts DDS) and VM service is
    + // enabled.
    + // TODO(bkonyi): do we want to tie DevTools / DDS to the CLI in the long run?
    + bool wait_for_dds_to_advertise_service = !Options::disable_dart_dev();
    // Load embedder specific bits and return.
    if (!VmService::Setup(
    Options::disable_dart_dev() ? Options::vm_service_server_ip()
    diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
    index e60f6c8..77b794c 100644
    --- a/runtime/bin/main_options.cc
    +++ b/runtime/bin/main_options.cc
    @@ -583,7 +583,7 @@

    run_command = true;
    }
    if (!Options::disable_dart_dev() && enable_vm_service_ && run_command) {
    - const char* dds_format_str = "--launch-dds=%s:%d";
    + const char* dds_format_str = "--launch-dds=%s\\:%d";
    size_t size =
    snprintf(nullptr, 0, dds_format_str, vm_service_server_ip(),
    vm_service_server_port());
    @@ -603,6 +603,7 @@
    first_option = false;
    }
    }
    +

    // Verify consistency of arguments.

    // snapshot_depfile is an alias for depfile. Passing them both is an error.
    diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
    index 15a1abf..1390092 100644
    --- a/sdk/BUILD.gn
    +++ b/sdk/BUILD.gn
    @@ -252,6 +252,18 @@

    },
    ]

    +# This rule copies the pre-built DevTools application to
    +# bin/resources/devtools/
    +copy_tree_specs += [
    + {
    + target = "copy_prebuilt_devtools"
    + visibility = [ ":create_common_sdk" ]
    + source = "../third_party/devtools/web"
    + dest = "$root_out_dir/dart-sdk/bin/resources/devtools"
    + ignore_patterns = "{}"
    + },
    +]
    +
    # This loop generates rules to copy libraries to lib/
    foreach(library, _full_sdk_libraries) {
    copy_tree_specs += [
    @@ -811,6 +823,7 @@

    ":copy_libraries_dart",
    ":copy_libraries_specification",
    ":copy_license",
    + ":copy_prebuilt_devtools",
    ":copy_readme",
    ":copy_vm_dill_files",
    ":write_dartdoc_options",
    diff --git a/sdk/lib/_internal/vm/bin/vmservice_io.dart b/sdk/lib/_internal/vm/bin/vmservice_io.dart
    index d1f8a5d..9610f3c 100644
    --- a/sdk/lib/_internal/vm/bin/vmservice_io.dart
    +++ b/sdk/lib/_internal/vm/bin/vmservice_io.dart
    @@ -43,6 +43,7 @@
    // HTTP server.
    Server? server;
    Future<Server>? serverFuture;
    +_DebuggingSession? ddsInstance;

    Server _lazyServerBoot() {
    var localServer = server;
    @@ -58,6 +59,88 @@
    return localServer;
    }

    +/// Responsible for launching a DevTools instance when the service is started
    +/// via SIGQUIT.
    +class _DebuggingSession {
    + Future<bool> start(

    + String host,
    + String port,
    + bool disableServiceAuthCodes,
    + bool enableDevTools,
    +  ) async {
    + final dartPath = Uri.parse(Platform.resolvedExecutable);
    + final dartDir = [
    + '', // Include leading '/'
    + ...dartPath.pathSegments.sublist(
    + 0,
    + dartPath.pathSegments.length - 1,
    + ),
    + ].join('/');
    +
    + final fullSdk = dartDir.endsWith('bin');
    +
    + final ddsSnapshot = [
    + dartDir,
    + fullSdk ? 'snapshots' : 'gen',
    + 'dds.dart.snapshot',
    + ].join('/');
    +
    + final devToolsBinaries = [
    + dartDir,
    + if (fullSdk) 'bin/resources',
    + 'devtools',
    + ].join('/');
    +
    + _process = await Process.start(
    + dartPath.toString(),
    + [
    + ddsSnapshot,
    + server!.serverAddress!.toString(),

    + host,
    + port,
    + disableServiceAuthCodes.toString(),
    + enableDevTools.toString(),
    +        devToolsBinaries,
    + ],
    + mode: ProcessStartMode.detachedWithStdio,
    + );
    +    final completer = Completer<void>();
    + late StreamSubscription stderrSub;
    + stderrSub = _process!.stderr.transform(utf8.decoder).listen((event) {

    + final result = json.decode(event) as Map<String, dynamic>;
    + final state = result['state'];
    + if (state == 'started') {
    + if (result.containsKey('devToolsUri')) {
    +          // NOTE: update pkg/dartdev/lib/src/commands/run.dart if this message
    + // is changed to ensure consistency.
    + const devToolsMessagePrefix =
    + 'The Dart DevTools debugger and profiler is available at:';

    + final devToolsUri = result['devToolsUri'];
    +          print('$devToolsMessagePrefix $devToolsUri');
    + }
    + stderrSub.cancel();
    + completer.complete();
    + } else {
    + stderrSub.cancel();
    + completer.completeError(
    + 'Could not start Observatory HTTP server',
    + );
    + }
    + });
    + try {
    + await completer.future;
    + return true;
    + } catch (e) {
    + stderr.write(e);

    + return false;
    + }
    + }
    +
    + void shutdown() => _process!.kill();
    +
    + Process? _process;
    +}
    +
    Future cleanupCallback() async {
    // Cancel the sigquit subscription.
    if (_signalSubscription != null) {
    @@ -221,10 +304,6 @@
    _server.acceptNewWebSocketConnections = enable;
    }

    -void _clearFuture(_) {
    - serverFuture = null;
    -}
    -
    _onSignal(ProcessSignal signal) {
    if (serverFuture != null) {
    // Still waiting.
    @@ -233,9 +312,21 @@
    final _server = _lazyServerBoot();
    // Toggle HTTP server.
    if (_server.running) {
    - _server.shutdown(true).then(_clearFuture);
    + _server.shutdown(true).then((_) async {
    + ddsInstance?.shutdown();
    + await VMService().clearState();
    + serverFuture = null;
    + });
    } else {
    - _server.startup().then(_clearFuture);
    + _server.startup().then((_) {
    + ddsInstance = _DebuggingSession()
    + ..start(
    + _server._ip,
    + _server._port.toString(),
    + false,
    + true,
    + );
    + });
    }
    }

    diff --git a/sdk/lib/_internal/vm/bin/vmservice_server.dart b/sdk/lib/_internal/vm/bin/vmservice_server.dart
    index 69aa7f8..f5742ed 100644
    --- a/sdk/lib/_internal/vm/bin/vmservice_server.dart
    +++ b/sdk/lib/_internal/vm/bin/vmservice_server.dart
    @@ -26,9 +26,9 @@
    socket.done.then((_) => close());
    }

    - disconnect() {
    + Future<void> disconnect() async {
    if (socket != null) {
    - socket.close();
    + await socket.close();
    }
    }

    @@ -102,8 +102,8 @@
    HttpRequestClient(this.request, VMService service)
    : super(service, sendEvents: false);

    - disconnect() {
    - request.response.close();
    + Future<void> disconnect() async {
    + await request.response.close();
    close();
    }

    diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
    index a3f7e8b..d492dcf 100644
    --- a/sdk/lib/vmservice/vmservice.dart
    +++ b/sdk/lib/vmservice/vmservice.dart
    @@ -411,6 +411,16 @@
    replyPort.send(bytes);
    }

    + Future<void> clearState() async {
    + // Create a copy of the set as a list because client.disconnect() will
    + // alter the connected clients set.
    + final clientsList = clients.toList();
    + for (final client in clientsList) {
    + await client.disconnect();
    + }
    + devfs.cleanup();
    + }
    +
    Future _exit() async {
    isExiting = true;

    @@ -423,14 +433,7 @@
    // Close receive ports.
    isolateControlPort.close();
    scriptLoadPort.close();
    -
    - // Create a copy of the set as a list because client.disconnect() will
    - // alter the connected clients set.
    - final clientsList = clients.toList();
    - for (final client in clientsList) {
    - client.disconnect();
    - }
    - devfs.cleanup();
    + await clearState();
    final cleanup = VMServiceEmbedderHooks.cleanup;
    if (cleanup != null) {
    await cleanup();
    diff --git a/third_party/devtools/update.sh b/third_party/devtools/update.sh
    index a69f6ee..55591be 100755
    --- a/third_party/devtools/update.sh
    +++ b/third_party/devtools/update.sh
    @@ -37,5 +37,5 @@
    -name dart/third_party/flutter/devtools \
    -in cipd_package \
    -install-mode copy \
    - -tag revision:$1
    + -tag git_revision:$1

    diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
    index 7f33648..c0bc00f 100644
    --- a/tools/bots/test_matrix.json
    +++ b/tools/bots/test_matrix.json
    @@ -322,6 +322,7 @@
    "xcodebuild/ReleaseSIMARM64C/",
    "xcodebuild/ReleaseX64/",
    "xcodebuild/ReleaseX64C/",
    + "pkg/",
    "samples/",
    "samples_2/",
    "samples-dev/",
    @@ -329,6 +330,7 @@
    "third_party/android_tools/sdk/platform-tools/adb",
    "third_party/android_tools/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-strip",
    "third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-strip",
    + "third_party/devtools/",
    "third_party/webdriver/",
    "third_party/pkg/",
    "third_party/pkg_tested/",

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 15
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Jacob Richman <jac...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-MessageType: newchange

    Jacob Richman (Gerrit)

    unread,
    Apr 28, 2021, 12:04:28 AM4/28/21
    to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Ben Konyi, Kenzie Schmoll, Siva Annamalai.

    View Change

    6 comments:

    • File .packages:

      • Patch Set #12, Line 42:

        devtools_server:third_party/devtools/devtools_server/lib
        devtools_shared:third_party/devtools/devtools_shared/lib

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 15
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Ben Konyi <bko...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Wed, 28 Apr 2021 04:04:24 +0000

    Jacob Richman (Gerrit)

    unread,
    Apr 28, 2021, 12:16:46 AM4/28/21
    to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Ben Konyi, Kenzie Schmoll, Siva Annamalai.

    View Change

    3 comments:

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 15
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Ben Konyi <bko...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Wed, 28 Apr 2021 04:16:41 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    Ben Konyi (Gerrit)

    unread,
    Apr 29, 2021, 6:30:04 PM4/29/21
    to rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

    Patch set 16:Commit-Queue +1

    View Change

    9 comments:

    • File .packages:

      • Patch Set #12, Line 42:

        devtools_server:third_party/devtools/devtools_server/lib
        devtools_shared:third_party/devtools/devtools_shared/lib

      • I would prefer if we create a thin devtools_server_api package instead of forking the code.

        As discussed offline, we'll just fork what we need for now to remove these dependencies until we have a dedicated server_api package.

    • File pkg/dartdev/lib/src/commands/run.dart:

    • File pkg/dds/bin/dds.dart:

      • why is json being written to STDERR? Is the protocol documented somewhere and why stderr instead of […]

        This was more of an internal protocol used by the CLI, so there's currently no documentation. We might start launching a DDS snapshot bundled with the SDK from flutter_tools, at which point we'd want this documented.

        We use stderr since the VM service URI is output on stdout. If --debug-dds is provided to the VM, it will launch DDS with --observe and write to stdout.

    • File pkg/dds/lib/src/dds_impl.dart:

      • Done

    • File pkg/dds/lib/src/devtools/devtools_client.dart:

      • Consider enabling and disabling debug logging based on a top level field in this file (e.g. […]

        I'll probably wire this up to --debug-dds. The logs aren't visible to users anyway since they're in the DDS process, but it doesn't make sense to scream into the void if there's nobody listening... 😊

      • Patch Set #15, Line 50: print('DevTools SSE event: $e');

        Did you mean to enable the logging middleware sink by default and include this log message?

      • Added some logic so this needs to be explicitly enabled.

      • do connected and disconnected even make sense for the DDS embedded case? Will this devtools server c […]

        Not at this point, but I can envision DDS having a long-running mode in the future. I'll no-op these for now.

      • this one should be easy to implement reusing the implementation in https://github. […]

        Took a look at the code and I'm thinking this should just be another no-op for now. We don't have a use for this functionality in the SDK at this point.

    • File sdk/lib/_internal/vm/bin/vmservice_io.dart:

      • Lets align this message with our docs. […]

        Pretty sure this is copied right from flutter_tools output which is:

        The Flutter DevTools debugger and profiler on macOS is available at: http://127.0.0.1:9101?uri=http%3A%2F%2F127.0.0.1%3A51840%2Fx6KHW4Z8J8I%3D%2F

        I think we should stay consistent. If that means we change the message in flutter_tools as well, that's fine with me 😊.

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 16
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Jacob Richman <jac...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Thu, 29 Apr 2021 22:30:00 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Comment-In-Reply-To: Jacob Richman <jac...@google.com>

    Ben Konyi (Gerrit)

    unread,
    Apr 29, 2021, 6:32:41 PM4/29/21
    to rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

    View Change

    3 comments:

    • File .packages:

      • Patch Set #12, Line 42:

        devtools_server:third_party/devtools/devtools_server/lib
        devtools_shared:third_party/devtools/devtools_shared/lib

      • As discussed offline, we'll just fork what we need for now to remove these dependencies until we hav […]

        Done

    • File pkg/dartdev/lib/src/commands/run.dart:

      • This is more of a note for myself. It'll be removed before this lands.

      • Done

    • File pkg/dds/lib/src/devtools/devtools_client.dart:

      • I'll probably wire this up to --debug-dds. […]

        Done

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 17
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Jacob Richman <jac...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-Comment-Date: Thu, 29 Apr 2021 22:32:37 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No

    Ben Konyi (Gerrit)

    unread,
    Apr 29, 2021, 6:33:10 PM4/29/21
    to rev...@dartlang.org, vm-...@dartlang.org

    Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

    Ben Konyi uploaded patch set #18 to this change.

    View Change

    [ VM / DDS / CLI ] Add DevTools support to the standalone VM

    Example output on stdout when DevTools is enabled:

    Observatory listening on http://127.0.0.1:8181/CzkZzZaONW4=/
    The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8181/devtools/#/?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FCzkZzZaONW4%3D%2Fws
    hello world!

    vm-service: isolate(1674461414267555) 'main' has no debugger attached and is paused at exit. Connect to Observatory at http://127.0.0.1:8181/CzkZzZaONW4=/ to debug.

    TEST=pkg/dartdev/test/commands/run_test.dart


    Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    ---
    M .dart_tool/package_config.json
    M .packages
    M DEPS
    M pkg/dartdev/lib/dartdev.dart
    M pkg/dartdev/lib/src/commands/run.dart
    M pkg/dartdev/lib/src/sdk.dart
    M pkg/dartdev/test/commands/run_test.dart
    M pkg/dds/CHANGELOG.md
    M pkg/dds/bin/dds.dart
    M pkg/dds/lib/dds.dart
    M pkg/dds/lib/src/client.dart
    M pkg/dds/lib/src/constants.dart
    M pkg/dds/lib/src/dds_impl.dart
    A pkg/dds/lib/src/devtools/devtools_client.dart
    A pkg/dds/lib/src/devtools/devtools_handler.dart
    A pkg/dds/lib/src/devtools/file_system.dart
    A pkg/dds/lib/src/devtools/server_api.dart
    A pkg/dds/lib/src/devtools/usage.dart

    M pkg/dds/pubspec.yaml
    M runtime/bin/main.cc
    M runtime/bin/main_options.cc
    M sdk/BUILD.gn
    M sdk/lib/_internal/vm/bin/vmservice_io.dart
    M sdk/lib/_internal/vm/bin/vmservice_server.dart
    M sdk/lib/vmservice/vmservice.dart
    M third_party/devtools/update.sh
    M tools/bots/test_matrix.json
    M tools/generate_package_config.dart
    M utils/dartdev/BUILD.gn
    29 files changed, 1,191 insertions(+), 109 deletions(-)

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 18
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Jacob Richman <jac...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-MessageType: newpatchset

    Ben Konyi (Gerrit)

    unread,
    Apr 29, 2021, 7:44:32 PM4/29/21
    to rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

    Ben Konyi removed a vote from this change.

    View Change

    Removed Commit-Queue+1 by Ben Konyi <bko...@google.com>

    To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: master
    Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
    Gerrit-Change-Number: 188361
    Gerrit-PatchSet: 19
    Gerrit-Owner: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Ben Konyi <bko...@google.com>
    Gerrit-Reviewer: Jacob Richman <jac...@google.com>
    Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
    Gerrit-Reviewer: Siva Annamalai <as...@google.com>
    Gerrit-CC: Devon Carew <devon...@google.com>
    Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
    Gerrit-Attention: Ryan Macnak <rma...@google.com>
    Gerrit-Attention: Jacob Richman <jac...@google.com>
    Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
    Gerrit-Attention: Siva Annamalai <as...@google.com>
    Gerrit-MessageType: deleteVote

    Ben Konyi (Gerrit)

    unread,
    Apr 29, 2021, 7:44:37 PM4/29/21
    to rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

    Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

    Patch set 19:Commit-Queue +2

    View Change

      To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: sdk
      Gerrit-Branch: master
      Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
      Gerrit-Change-Number: 188361
      Gerrit-PatchSet: 19
      Gerrit-Owner: Ben Konyi <bko...@google.com>
      Gerrit-Reviewer: Ben Konyi <bko...@google.com>
      Gerrit-Reviewer: Jacob Richman <jac...@google.com>
      Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
      Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
      Gerrit-Reviewer: Siva Annamalai <as...@google.com>
      Gerrit-CC: Devon Carew <devon...@google.com>
      Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
      Gerrit-Attention: Ryan Macnak <rma...@google.com>
      Gerrit-Attention: Jacob Richman <jac...@google.com>
      Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
      Gerrit-Attention: Siva Annamalai <as...@google.com>
      Gerrit-Comment-Date: Thu, 29 Apr 2021 23:44:33 +0000
      Gerrit-HasComments: No
      Gerrit-Has-Labels: Yes
      Gerrit-MessageType: comment

      Ben Konyi (Gerrit)

      unread,
      Apr 29, 2021, 7:44:40 PM4/29/21
      to rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

      Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

      Ben Konyi removed a vote from this change.

      View Change

      Removed Commit-Queue+2 by Ben Konyi <bko...@google.com>

      To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: sdk
      Gerrit-Branch: master
      Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
      Gerrit-Change-Number: 188361
      Gerrit-PatchSet: 19
      Gerrit-Owner: Ben Konyi <bko...@google.com>
      Gerrit-Reviewer: Ben Konyi <bko...@google.com>
      Gerrit-Reviewer: Jacob Richman <jac...@google.com>
      Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
      Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
      Gerrit-Reviewer: Siva Annamalai <as...@google.com>
      Gerrit-CC: Devon Carew <devon...@google.com>
      Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
      Gerrit-Attention: Ryan Macnak <rma...@google.com>
      Gerrit-Attention: Jacob Richman <jac...@google.com>
      Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
      Gerrit-Attention: Siva Annamalai <as...@google.com>
      Gerrit-MessageType: deleteVote

      Dart CI (Gerrit)

      unread,
      Apr 30, 2021, 3:26:49 AM4/30/21
      to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

      Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

      go/dart-cbuild result: FAILURE (REGRESSIONS DETECTED)

      Details: https://goto.google.com/dart-cbuild/find/91eb593a0117ffb0f401ed707716a2967bbefee0
      Bugs: go/dart-cbuild-bug/91eb593a0117ffb0f401ed707716a2967bbefee0

      View Change

        To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: sdk
        Gerrit-Branch: master
        Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
        Gerrit-Change-Number: 188361
        Gerrit-PatchSet: 20
        Gerrit-Owner: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Jacob Richman <jac...@google.com>
        Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
        Gerrit-Reviewer: Siva Annamalai <as...@google.com>
        Gerrit-CC: Devon Carew <devon...@google.com>
        Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
        Gerrit-Attention: Ryan Macnak <rma...@google.com>
        Gerrit-Attention: Jacob Richman <jac...@google.com>
        Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Attention: Siva Annamalai <as...@google.com>
        Gerrit-Comment-Date: Fri, 30 Apr 2021 07:26:44 +0000

        Ivan Inozemtsev (Gerrit)

        unread,
        Apr 30, 2021, 3:56:04 AM4/30/21
        to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Dart CI, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

        Attention is currently required from: Ryan Macnak, Jacob Richman, Ben Konyi, Kenzie Schmoll, Siva Annamalai.

        View Change

        1 comment:

          • The detected regression is an increase of helloflutter binary size in bytes by 20095 (from 1501740 to 1521835), or 1.3%, which increases 1 percent threshold. If that is expected, this regression can be ignored

        To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: sdk
        Gerrit-Branch: master
        Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
        Gerrit-Change-Number: 188361
        Gerrit-PatchSet: 20
        Gerrit-Owner: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Jacob Richman <jac...@google.com>
        Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
        Gerrit-Reviewer: Siva Annamalai <as...@google.com>
        Gerrit-CC: Devon Carew <devon...@google.com>
        Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
        Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
        Gerrit-Attention: Ryan Macnak <rma...@google.com>
        Gerrit-Attention: Jacob Richman <jac...@google.com>
        Gerrit-Attention: Ben Konyi <bko...@google.com>
        Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Attention: Siva Annamalai <as...@google.com>
        Gerrit-Comment-Date: Fri, 30 Apr 2021 07:55:58 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        Gerrit-MessageType: comment

        Siva Annamalai (Gerrit)

        unread,
        Apr 30, 2021, 2:14:17 PM4/30/21
        to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Ivan Inozemtsev, Dart CI, Kenzie Schmoll, Jacob Richman, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

        Attention is currently required from: Ryan Macnak, Jacob Richman, Ben Konyi, Ivan Inozemtsev, Kenzie Schmoll.

        Patch set 20:Code-Review +1

        View Change

        1 comment:

        • Patchset:

          • Patch Set #20:

            > Patch Set 20: […]

            Is the size regression test building hello_world release or profile builds ?

        To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: sdk
        Gerrit-Branch: master
        Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
        Gerrit-Change-Number: 188361
        Gerrit-PatchSet: 20
        Gerrit-Owner: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Jacob Richman <jac...@google.com>
        Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
        Gerrit-Reviewer: Siva Annamalai <as...@google.com>
        Gerrit-CC: Devon Carew <devon...@google.com>
        Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
        Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
        Gerrit-Attention: Ryan Macnak <rma...@google.com>
        Gerrit-Attention: Jacob Richman <jac...@google.com>
        Gerrit-Attention: Ben Konyi <bko...@google.com>
        Gerrit-Attention: Ivan Inozemtsev <iinoz...@google.com>
        Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Comment-Date: Fri, 30 Apr 2021 18:14:13 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: Yes
        Comment-In-Reply-To: Ivan Inozemtsev <iinoz...@google.com>
        Gerrit-MessageType: comment

        Ivan Inozemtsev (Gerrit)

        unread,
        Apr 30, 2021, 2:29:54 PM4/30/21
        to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Dart CI, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

        Attention is currently required from: Ryan Macnak, Jacob Richman, Ben Konyi, Kenzie Schmoll, Siva Annamalai.

        View Change

        1 comment:

        • Patchset:

          • Patch Set #20:

            Is the size regression test building hello_world release or profile builds ?

            release, more details at b/155337225#comment19

        To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: sdk
        Gerrit-Branch: master
        Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
        Gerrit-Change-Number: 188361
        Gerrit-PatchSet: 20
        Gerrit-Owner: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Ben Konyi <bko...@google.com>
        Gerrit-Reviewer: Jacob Richman <jac...@google.com>
        Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
        Gerrit-Reviewer: Siva Annamalai <as...@google.com>
        Gerrit-CC: Devon Carew <devon...@google.com>
        Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
        Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
        Gerrit-Attention: Ryan Macnak <rma...@google.com>
        Gerrit-Attention: Jacob Richman <jac...@google.com>
        Gerrit-Attention: Ben Konyi <bko...@google.com>
        Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
        Gerrit-Attention: Siva Annamalai <as...@google.com>
        Gerrit-Comment-Date: Fri, 30 Apr 2021 18:29:49 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        Comment-In-Reply-To: Ivan Inozemtsev <iinoz...@google.com>

        Ben Konyi (Gerrit)

        unread,
        May 3, 2021, 12:50:57 PM5/3/21
        to rev...@dartlang.org, vm-...@dartlang.org, Ivan Inozemtsev, Dart CI, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

        Attention is currently required from: Ryan Macnak, Jacob Richman, Ben Konyi, Kenzie Schmoll, Siva Annamalai.

        Set Ready For Review

        View Change

          To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-Project: sdk
          Gerrit-Branch: master
          Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
          Gerrit-Change-Number: 188361
          Gerrit-PatchSet: 22
          Gerrit-Owner: Ben Konyi <bko...@google.com>
          Gerrit-Reviewer: Ben Konyi <bko...@google.com>
          Gerrit-Reviewer: Jacob Richman <jac...@google.com>
          Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
          Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
          Gerrit-Reviewer: Siva Annamalai <as...@google.com>
          Gerrit-CC: Devon Carew <devon...@google.com>
          Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
          Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
          Gerrit-Attention: Ryan Macnak <rma...@google.com>
          Gerrit-Attention: Jacob Richman <jac...@google.com>
          Gerrit-Attention: Ben Konyi <bko...@google.com>
          Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
          Gerrit-Attention: Siva Annamalai <as...@google.com>
          Gerrit-Comment-Date: Mon, 03 May 2021 16:50:55 +0000

          Ben Konyi (Gerrit)

          unread,
          May 3, 2021, 2:23:56 PM5/3/21
          to rev...@dartlang.org, vm-...@dartlang.org, Ivan Inozemtsev, Dart CI, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, commi...@chromium.org, Keerti Parthasarathy

          Attention is currently required from: Ryan Macnak, Jacob Richman, Kenzie Schmoll, Siva Annamalai.

          Patch set 22:Commit-Queue +2

          View Change

            To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

            Gerrit-Project: sdk
            Gerrit-Branch: master
            Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
            Gerrit-Change-Number: 188361
            Gerrit-PatchSet: 22
            Gerrit-Owner: Ben Konyi <bko...@google.com>
            Gerrit-Reviewer: Ben Konyi <bko...@google.com>
            Gerrit-Reviewer: Jacob Richman <jac...@google.com>
            Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
            Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
            Gerrit-Reviewer: Siva Annamalai <as...@google.com>
            Gerrit-CC: Devon Carew <devon...@google.com>
            Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
            Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
            Gerrit-Attention: Ryan Macnak <rma...@google.com>
            Gerrit-Attention: Jacob Richman <jac...@google.com>
            Gerrit-Attention: Kenzie Schmoll <kenzie...@google.com>
            Gerrit-Attention: Siva Annamalai <as...@google.com>
            Gerrit-Comment-Date: Mon, 03 May 2021 18:23:52 +0000

            commit-bot@chromium.org (Gerrit)

            unread,
            May 3, 2021, 2:24:15 PM5/3/21
            to Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Ivan Inozemtsev, Dart CI, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, Keerti Parthasarathy

            commi...@chromium.org submitted this change.

            View Change

            Approvals: Siva Annamalai: Looks good to me, approved Ben Konyi: Commit
            [ VM / DDS / CLI ] Add DevTools support to the standalone VM

            Example output on stdout when DevTools is enabled:

            Observatory listening on http://127.0.0.1:8181/CzkZzZaONW4=/
            The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8181/devtools/#/?uri=ws%3A%2F%2F127.0.0.1%3A8181%2FCzkZzZaONW4%3D%2Fws
            hello world!

            vm-service: isolate(1674461414267555) 'main' has no debugger attached and is paused at exit. Connect to Observatory at http://127.0.0.1:8181/CzkZzZaONW4=/ to debug.

            TEST=pkg/dartdev/test/commands/run_test.dart

            Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
            Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/188361
            Commit-Queue: Ben Konyi <bko...@google.com>
            Reviewed-by: Siva Annamalai <as...@google.com>
            29 files changed, 1,199 insertions(+), 110 deletions(-)

            diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
            index 99dc94b..6787873 100644

            --- a/.dart_tool/package_config.json
            +++ b/.dart_tool/package_config.json
            @@ -11,7 +11,7 @@
            "constraint, update this by running tools/generate_package_config.dart."
            ],
            "configVersion": 2,
            -  "generated": "2021-04-30T16:02:33.294454",
            + "generated": "2021-05-03T09:47:39.938400",

            "generator": "tools/generate_package_config.dart",
            "packages": [
            {
            @@ -253,6 +253,18 @@
            "languageVersion": "2.3"
            },
            {
            + "name": "devtools_server",
            + "rootUri": "../third_party/devtools/devtools_server",
            + "packageUri": "lib/",
            + "languageVersion": "2.6"
            + },
            + {
            + "name": "devtools_shared",
            + "rootUri": "../third_party/devtools/devtools_shared",
            + "packageUri": "lib/",
            + "languageVersion": "2.3"
            + },
            + {
            "name": "diagnostic",
            "rootUri": "../pkg/diagnostic",
            "packageUri": "lib/",
            @@ -728,6 +740,12 @@
            "languageVersion": "2.12"
            },
            {
            + "name": "uuid",
            + "rootUri": "../third_party/pkg/uuid",
            + "packageUri": "lib/",
            + "languageVersion": "2.0"
            + },
            + {
            "name": "vector_math",
            "rootUri": "../third_party/pkg/vector_math",

            "packageUri": "lib/",
            diff --git a/.packages b/.packages
            index af07227..124a2a3 100644

            --- a/.packages
            +++ b/.packages
            @@ -22,6 +22,7 @@
            boolean_selector:third_party/pkg/boolean_selector/lib
            browser_launcher:third_party/pkg/browser_launcher/lib
            build_integration:pkg/build_integration/lib
            +browser_launcher:third_party/pkg/browser_launcher/lib
            charcode:third_party/pkg/charcode/lib
            cli_util:third_party/pkg/cli_util/lib
            collection:third_party/pkg/collection/lib
            @@ -38,6 +39,7 @@

            dartdoc:third_party/pkg/dartdoc/lib
            dds:pkg/dds/lib
            dev_compiler:pkg/dev_compiler/lib
            +devtools_shared:third_party/devtools/devtools_shared/lib
            diagnostic:pkg/diagnostic/lib
            expect:pkg/expect/lib
            ffi:third_party/pkg/ffi/lib
            diff --git a/DEPS b/DEPS
            index 2c75fde..83e3cd0 100644

            --- a/DEPS
            +++ b/DEPS
            @@ -80,6 +80,7 @@
            "boringssl_gen_rev": "7322fc15cc065d8d2957fccce6b62a509dc4d641",
            "boringssl_rev" : "1607f54fed72c6589d560254626909a64124f091",
            "browser-compat-data_tag": "v1.0.22",
            + "browser_launcher_rev": "12ab9f351a44ac803de9bc17bb2180bb312a9dd7",
            "charcode_rev": "bcd8a12c315b7a83390e4865ad847ecd9344cba2",
            "chrome_rev" : "19997",
            "cli_util_rev" : "fd1b716e8a350a454e01ae56df540293d31ff6c8",
            @@ -105,7 +106,6 @@
            "dart_style_rev": "f17c23e0eea9a870601c19d904e2a9c1a7c81470",

            "chromedriver_tag": "83.0.4103.39",
            - "browser_launcher_rev": "12ab9f351a44ac803de9bc17bb2180bb312a9dd7",
            "dartdoc_rev" : "505f163f7cb48e917503e4a23fbff1227e08b263",
               "jsshell_tag": "version:88.0",
            "ffi_rev": "f3346299c55669cc0db48afae85b8110088bf8da",
            @@ -246,7 +246,7 @@

            Var("dart_root") + "/third_party/devtools": {
            "packages": [{
            "package": "dart/third_party/flutter/devtools",
            - "version": "revision:6729ec62c3548839018c32fa711756202431ccf7",
            + "version": "git_revision:12ad5341ae0a275042c84a4e7be9a6c98db65612",
            }],
            "dep_type": "cipd",
            },
            @@ -319,6 +319,9 @@

            Var('chromium_git') + '/external/github.com/mdn/browser-compat-data' +
            "@" + Var("browser-compat-data_tag"),

            + Var("dart_root") + "/third_party/pkg/browser_launcher":
            + Var("dart_git") + "browser_launcher.git" + "@" + Var("browser_launcher_rev"),
            +
            Var("dart_root") + "/third_party/tcmalloc/gperftools":
            Var('chromium_git') + '/external/github.com/gperftools/gperftools.git' +
            "@" + Var("gperftools_revision"),
            @@ -335,9 +338,6 @@

            Var("dart_root") + "/third_party/pkg/boolean_selector":
            Var("dart_git") + "boolean_selector.git" +
            "@" + Var("boolean_selector_rev"),
            - Var("dart_root") + "/third_party/pkg/browser_launcher":
            - Var("dart_git") + "browser_launcher.git" +
            - "@" + Var("browser_launcher_rev"),
            Var("dart_root") + "/third_party/pkg/charcode":
            Var("dart_git") + "charcode.git" + "@" + Var("charcode_rev"),
            Var("dart_root") + "/third_party/pkg/cli_util":
            diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
            index b72fbba..5e581c5 100644
            --- a/pkg/dartdev/lib/dartdev.dart
            +++ b/pkg/dartdev/lib/dartdev.dart
            @@ -40,7 +40,8 @@
            args = args
            .where(
            (element) => !(element.contains('--observe') ||
            - element.contains('--enable-vm-service')),
            + element.contains('--enable-vm-service') ||
            + element.contains('--devtools')),
            )
            .toList();
            }
            diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
            index db32bfe..d996c3c 100644
            --- a/pkg/dartdev/lib/src/commands/run.dart
            +++ b/pkg/dartdev/lib/src/commands/run.dart
            @@ -158,6 +158,10 @@

            hide: !verbose,
            negatable: false,
            help: 'Enables tracing of library and script loading.',
            + )
            + ..addFlag(
            + 'debug-dds',
            + hide: true,
            );
            addExperimentalFlags(argParser, verbose);
            }
            @@ -179,13 +183,18 @@

            String launchDdsArg = argResults['launch-dds'];
            String ddsHost = '';
            String ddsPort = '';
            +
            +    // TODO(bkonyi): allow for users to choose not to launch DevTools
            + // See https://github.com/dart-lang/sdk/issues/45867.

            + const bool launchDevTools = true;
            bool launchDds = false;
            if (launchDdsArg != null) {
            launchDds = true;
            - final ddsUrl = launchDdsArg.split(':');
            + final ddsUrl = launchDdsArg.split('\\:');
            ddsHost = ddsUrl[0];
            ddsPort = ddsUrl[1];
            }
            + final bool debugDds = argResults['debug-dds'];

            bool disableServiceAuthCodes = argResults['disable-service-auth-codes'];

            @@ -198,7 +207,12 @@

            if (launchDds) {
            debugSession = _DebuggingSession();
            if (!await debugSession.start(
            - ddsHost, ddsPort, disableServiceAuthCodes)) {
            + ddsHost,
            + ddsPort,
            + disableServiceAuthCodes,
            + launchDevTools,
            + debugDds,
            + )) {
            return errorExitCode;
            }
            }
            @@ -242,10 +256,19 @@


            class _DebuggingSession {
            Future<bool> start(
            - String host, String port, bool disableServiceAuthCodes) async {
            - final ddsSnapshot = (dirname(sdk.dart).endsWith('bin'))
            + String host,
            + String port,
            + bool disableServiceAuthCodes,
            + bool enableDevTools,
            + bool debugDds,
            + ) async {
            +    final sdkDir = dirname(sdk.dart);
            + final fullSdk = sdkDir.endsWith('bin');

            + final ddsSnapshot = fullSdk
            ? sdk.ddsSnapshot
            -        : absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot');
            + : absolute(sdkDir, 'gen', 'dds.dart.snapshot');
            + final devToolsBinaries =
            + fullSdk ? sdk.devToolsBinaries : absolute(sdkDir, 'devtools');
            if (!Sdk.checkArtifactExists(ddsSnapshot)) {
            return false;
            }
            @@ -256,30 +279,51 @@

            serviceInfo = await Service.getInfo();
            }
            final process = await Process.start(
            - sdk.dart,
            - [
            - if (dirname(sdk.dart).endsWith('bin'))
            - sdk.ddsSnapshot
            - else
            - absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot'),
            - serviceInfo.serverUri.toString(),
            - host,
            - port,
            - disableServiceAuthCodes.toString(),
            - ],
            - mode: ProcessStartMode.detachedWithStdio);
            + sdk.dart,
            + [
            + if (debugDds) '--enable-vm-service=0',
            + ddsSnapshot,
            + serviceInfo.serverUri.toString(),
            + host,
            + port,
            + disableServiceAuthCodes.toString(),
            + enableDevTools.toString(),
            + devToolsBinaries,
            +        debugDds.toString(),
            index 9937d26..a8c72ee 100644

            --- a/pkg/dds/bin/dds.dart
            +++ b/pkg/dds/bin/dds.dart
            @@ -4,6 +4,7 @@

            // @dart=2.10

            +import 'dart:convert';
            import 'dart:io';

            import 'package:dds/dds.dart';
            @@ -16,6 +17,9 @@

            /// - DDS bind address
            /// - DDS port
            /// - Disable service authentication codes
            +/// - Start DevTools
            +/// - DevTools build directory
            +///   - Enable logging

            Future<void> main(List<String> args) async {
            if (args.isEmpty) return;

            @@ -37,16 +41,37 @@

            port: int.parse(args[2]),
            );
            final disableServiceAuthCodes = args[3] == 'true';
            +
            + final startDevTools = args[4] == 'true';
            + Uri devToolsBuildDirectory;
            + if (args[5].isNotEmpty) {
            + devToolsBuildDirectory = Uri.parse(args[5]);
            + }
            +  final logRequests = args[6] == 'true';

            try {
            // TODO(bkonyi): add retry logic similar to that in vmservice_server.dart
            // See https://github.com/dart-lang/sdk/issues/43192.
            - await DartDevelopmentService.startDartDevelopmentService(
            + final dds = await DartDevelopmentService.startDartDevelopmentService(
            remoteVmServiceUri,
            serviceUri: serviceUri,
            enableAuthCodes: !disableServiceAuthCodes,
            + devToolsConfiguration: startDevTools
            + ? DevToolsConfiguration(
            + enable: startDevTools,
            + customBuildDirectoryPath: devToolsBuildDirectory,
            + )
            + : null,
            +      logRequests: logRequests,

            );
            - stderr.write('DDS started');
            - } catch (e) {
            - stderr.writeln('Failed to start DDS:\n$e');
            + stderr.write(json.encode({
            + 'state': 'started',
            + if (dds.devToolsUri != null) 'devToolsUri': dds.devToolsUri.toString(),
            + }));
            + } catch (e, st) {
            + stderr.write(json.encode({
            + 'state': 'error',
            + 'error': '$e',
            + 'stacktrace': '$st',
            + }));
            }
            }
            diff --git a/pkg/dds/lib/dds.dart b/pkg/dds/lib/dds.dart
            index f7c7a05..f0e913b 100644
            --- a/pkg/dds/lib/dds.dart
            +++ b/pkg/dds/lib/dds.dart
            @@ -44,6 +44,8 @@

            Uri serviceUri,
            bool enableAuthCodes = true,
            bool ipv6 = false,
            + DevToolsConfiguration devToolsConfiguration = const DevToolsConfiguration(),
            +    bool logRequests = false,

            }) async {
            if (remoteVmServiceUri == null) {
            throw ArgumentError.notNull('remoteVmServiceUri');
            @@ -80,6 +82,8 @@

            serviceUri,
            enableAuthCodes,
            ipv6,
            + devToolsConfiguration,
            +      logRequests,

            );
            await service.startService();
            return service;
            @@ -125,6 +129,11 @@

            /// Returns `null` if the service is not running.
            Uri get wsUri;

            + /// The HTTP [Uri] of the hosted DevTools instance.
            + ///
            + /// Returns `null` if DevTools is not running.
            + Uri get devToolsUri;
            +
            /// Set to `true` if this instance of [DartDevelopmentService] is accepting
            /// requests.
            bool get isRunning;
            @@ -168,3 +177,13 @@
            index db355fb..85be647 100644

            --- a/pkg/dds/lib/src/dds_impl.dart
            +++ b/pkg/dds/lib/src/dds_impl.dart
            @@ -24,6 +24,8 @@
            import 'binary_compatible_peer.dart';
            import 'client.dart';
            import 'client_manager.dart';
            +import 'constants.dart';
            +import 'devtools/devtools_handler.dart';
            import 'expression_evaluator.dart';
            import 'isolate_manager.dart';
            import 'stream_manager.dart';
            @@ -51,7 +53,13 @@


            class DartDevelopmentServiceImpl implements DartDevelopmentService {
            DartDevelopmentServiceImpl(
            - this._remoteVmServiceUri, this._uri, this._authCodesEnabled, this._ipv6) {
            + this._remoteVmServiceUri,
            + this._uri,
            + this._authCodesEnabled,
            + this._ipv6,
            + this._devToolsConfiguration,
            +    this.shouldLogRequests,

            + ) {
            _clientManager = ClientManager(this);
            _expressionEvaluator = ExpressionEvaluator(this);
            _isolateManager = IsolateManager(this);
            @@ -113,20 +121,26 @@
            (_ipv6 ? InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv4)
            .host;
            final port = uri?.port ?? 0;
            -
            + final pipeline = const Pipeline();
            + if (shouldLogRequests) {
            + pipeline.addMiddleware(
            + logRequests(
            + logger: (String message, bool isError) {

            + print('Log: $message');
            +          },

            + ),
            + );
            + }
            +    pipeline.addMiddleware(_authCodeMiddleware);
            + final handler = pipeline.addHandler(_handlers().handler);

            // Start the DDS server.
            -    _server = await io.serve(
            - const Pipeline()
            - .addMiddleware(_authCodeMiddleware)
            - .addHandler(_handlers().handler),
            - host,
            - port);
            + _server = await io.serve(handler, host, port);

            final tmpUri = Uri(

            scheme: 'http',
            host: host,
            port: _server.port,
            - path: '$_authCode/',
            + path: '$authCode/',
            );

            // Notify the VM service that this client is DDS and that it should close
            @@ -157,7 +171,7 @@

            return;
            }
            _shuttingDown = true;
            - // Don't accept anymore HTTP requests.
            + // Don't accept any more HTTP requests.
            await _server?.close();

            // Close connections to clients.
            @@ -197,7 +211,7 @@

            return forbidden;
            }
            final authToken = pathSegments[0];
            - if (authToken != _authCode) {
            + if (authToken != authCode) {
            return forbidden;
            }
            // Creates a new request with the authentication code stripped from
            @@ -233,18 +247,12 @@

            });

            Handler _sseHandler() {
            - // Give connections time to reestablish before considering them closed.
            - // Required to reestablish connections killed by UberProxy.
            - const keepAlive = Duration(seconds: 30);
            - final handler = authCodesEnabled
            - ? SseHandler(
            - Uri.parse('/$_authCode/$_kSseHandlerPath'),
            - keepAlive: keepAlive,
            - )
            - : SseHandler(
            - Uri.parse('/$_kSseHandlerPath'),
            - keepAlive: keepAlive,
            - );
            + final handler = SseHandler(
            + authCodesEnabled
            + ? Uri.parse('/$authCode/$_kSseHandlerPath')
            + : Uri.parse('/$_kSseHandlerPath'),
            + keepAlive: sseKeepAlive,
            + );

            handler.connections.rest.listen((sseConnection) {
            final client = DartDevelopmentServiceClient.fromSSEConnection(
            @@ -259,10 +267,18 @@

            }

            Handler _httpHandler() {
            - // DDS doesn't support any HTTP requests itself, so we just forward all of
            - // them to the VM service.
            - final cascade = Cascade().add(proxyHandler(remoteVmServiceUri));
            - return cascade.handler;
            + if (_devToolsConfiguration != null && _devToolsConfiguration.enable) {
            + // Install the DevTools handlers and forward any unhandled HTTP requests to
            + // the VM service.
            + final buildDir =
            + _devToolsConfiguration.customBuildDirectoryPath?.toFilePath();
            + return devtoolsHandler(
            + dds: this,
            + buildDir: buildDir,
            + notFoundHandler: proxyHandler(remoteVmServiceUri),
            + );
            + }
            + return proxyHandler(remoteVmServiceUri);
            }

            List<String> _cleanupPathSegments(Uri uri) {
            @@ -296,14 +312,43 @@
            +  String get authCode => _authCode;
            String _authCode;

            + final bool shouldLogRequests;
            +

            @override
            Uri get remoteVmServiceUri => _remoteVmServiceUri;

            @@ -313,17 +358,21 @@


            @override
            Uri get uri => _uri;
            + Uri _uri;

            @override
            Uri get sseUri => _toSse(_uri);

            Uri get wsUri => _toWebSocket(_uri);
            - Uri _uri;
            +
            + Uri get devToolsUri => _toDevTools(_uri);

            final bool _ipv6;

            bool get isRunning => _uri != null;

            + final DevToolsConfiguration _devToolsConfiguration;
            +
            Future<void> get done => _done.future;
            Completer _done = Completer<void>();
            bool _shuttingDown = false;
            diff --git a/pkg/dds/lib/src/devtools/devtools_client.dart b/pkg/dds/lib/src/devtools/devtools_client.dart
            new file mode 100644
            index 0000000..5f8670e
            --- /dev/null
            +++ b/pkg/dds/lib/src/devtools/devtools_client.dart
            @@ -0,0 +1,96 @@

            +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
            +// for details. All rights reserved. Use of this source code is governed by a
            +// BSD-style license that can be found in the LICENSE file.
            +
            +// @dart=2.9
            +
            +import 'dart:async';
            +
            +import 'package:json_rpc_2/src/server.dart' as json_rpc;
            +import 'package:sse/src/server/sse_handler.dart';
            +import 'package:stream_channel/stream_channel.dart';
            +
            +import 'server_api.dart';
            +    bool loggingEnabled,
            + ) {
            + Stream<String> stream = sse.stream;
            + StreamSink sink = sse.sink;
            +
            + if (loggingEnabled) {
            + stream = stream.map<String>((String e) {
            + print('DevTools SSE request: $e');
            + return e;
            + });
            + sink = LoggingMiddlewareSink(sink);
            + }
            +
            + _server = json_rpc.Server(
            + StreamChannel(stream, sink),

            + strictProtocolChecks: false,
            + );
            + _registerJsonRpcMethods();
            + _server.listen();
            + }
            +
            + void _registerJsonRpcMethods() {
            + _server.registerMethod('connected', (parameters) {
            +      // Nothing to do here.

            + });
            +
            + _server.registerMethod('currentPage', (parameters) {
            +      // Nothing to do here.

            + });
            +
            + _server.registerMethod('disconnected', (parameters) {
            +      // Nothing to do here.

            + });
            +
            + _server.registerMethod('getPreferenceValue', (parameters) {
            + final key = parameters['key'].asString;
            + final value = ServerApi.devToolsPreferences.properties[key];
            + return value;
            + });
            +
            + _server.registerMethod('setPreferenceValue', (parameters) {
            + final key = parameters['key'].asString;
            + final value = parameters['value'].value;
            + ServerApi.devToolsPreferences.properties[key] = value;
            + });
            + }
            +
            +  json_rpc.Server _server;

            +}
            diff --git a/pkg/dds/lib/src/devtools/devtools_handler.dart b/pkg/dds/lib/src/devtools/devtools_handler.dart
            new file mode 100644
            index 0000000..a0a4bf1
            --- /dev/null
            +++ b/pkg/dds/lib/src/devtools/devtools_handler.dart
            @@ -0,0 +1,87 @@

            +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
            +// for details. All rights reserved. Use of this source code is governed by a
            +// BSD-style license that can be found in the LICENSE file.
            +
            +// @dart=2.9
            +
            +import 'dart:async';
            +
            +import 'package:dds/src/constants.dart';
            +import 'package:meta/meta.dart';
            +import 'package:shelf/shelf.dart';
            +import 'package:shelf_static/shelf_static.dart';
            +import 'package:sse/server/sse_handler.dart';
            +
            +import '../dds_impl.dart';
            +import 'devtools_client.dart';
            +import 'server_api.dart';
            +      dds.shouldLogRequests,
            diff --git a/pkg/dds/lib/src/devtools/file_system.dart b/pkg/dds/lib/src/devtools/file_system.dart
            new file mode 100644
            index 0000000..9a05de7
            --- /dev/null
            +++ b/pkg/dds/lib/src/devtools/file_system.dart
            @@ -0,0 +1,84 @@
            +// Copyright 2021 The Chromium Authors. All rights reserved.
            +// Use of this source code is governed by a BSD-style license that can be
            +// found in the LICENSE file.
            +
            +// @dart=2.9
            +
            +// TODO(bkonyi): remove once package:devtools_server_api is available
            +// See https://github.com/flutter/devtools/issues/2958.
            +
            +import 'dart:convert';
            +import 'dart:io';
            +
            +import 'package:path/path.dart' as path;
            +
            +import 'usage.dart';
            +
            +class LocalFileSystem {
            + static String _userHomeDir() {
            + final String envKey =
            + Platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME';
            + final String value = Platform.environment[envKey];
            + return value == null ? '.' : value;
            + }
            +
            + /// Returns the path to the DevTools storage directory.
            + static String devToolsDir() {
            + return path.join(_userHomeDir(), '.flutter-devtools');
            + }
            +
            + /// Moves the .devtools file to ~/.flutter-devtools/.devtools if the .devtools file
            + /// exists in the user's home directory.
            + static void maybeMoveLegacyDevToolsStore() {
            + final file = File(path.join(_userHomeDir(), DevToolsUsage.storeName));
            + if (file.existsSync()) {
            + ensureDevToolsDirectory();
            + file.copySync(path.join(devToolsDir(), DevToolsUsage.storeName));
            + file.deleteSync();
            + }
            + }
            +
            + /// Creates the ~/.flutter-devtools directory if it does not already exist.
            + static void ensureDevToolsDirectory() {
            + Directory('${LocalFileSystem.devToolsDir()}').createSync();
            + }
            +
            + /// Returns a DevTools file from the given path.
            + ///
            + /// Only files within ~/.flutter-devtools/ can be accessed.
            + static File devToolsFileFromPath(String pathFromDevToolsDir) {
            + if (pathFromDevToolsDir.contains('..')) {
            + // The passed in path should not be able to walk up the directory tree
            + // outside of the ~/.flutter-devtools/ directory.
            + return null;
            + }
            + ensureDevToolsDirectory();
            + final file = File(path.join(devToolsDir(), pathFromDevToolsDir));
            + if (!file.existsSync()) {
            + return null;
            + }
            + return file;
            + }
            +
            + /// Returns a DevTools file from the given path as encoded json.
            + ///
            + /// Only files within ~/.flutter-devtools/ can be accessed.
            + static String devToolsFileAsJson(String pathFromDevToolsDir) {
            + final file = devToolsFileFromPath(pathFromDevToolsDir);
            + if (file == null) return null;
            +
            + final fileName = path.basename(file.path);
            + if (!fileName.endsWith('.json')) return null;
            +
            + final content = file.readAsStringSync();
            + final json = jsonDecode(content);
            + json['lastModifiedTime'] = file.lastModifiedSync().toString();
            + return jsonEncode(json);
            + }
            +
            + /// Whether the flutter store file exists.
            + static bool flutterStoreExists() {
            + final flutterStore = File('${_userHomeDir()}/.flutter');
            + return flutterStore.existsSync();
            + }
            +}
            diff --git a/pkg/dds/lib/src/devtools/server_api.dart b/pkg/dds/lib/src/devtools/server_api.dart
            new file mode 100644
            index 0000000..b866f44
            --- /dev/null
            +++ b/pkg/dds/lib/src/devtools/server_api.dart
            @@ -0,0 +1,230 @@
            +// Copyright 2021 The Chromium Authors. All rights reserved.
            +// Use of this source code is governed by a BSD-style license that can be
            +// found in the LICENSE file.
            +
            +// @dart=2.9
            +
            +// TODO(bkonyi): remove once package:devtools_server_api is available
            +// See https://github.com/flutter/devtools/issues/2958.
            +

            +import 'dart:async';
            +import 'dart:convert';
            +import 'dart:io';
            +
            +import 'package:devtools_shared/devtools_shared.dart';
            +import 'package:shelf/shelf.dart' as shelf;
            +
            +import 'file_system.dart';
            +import 'usage.dart';
            +
            +/// The DevTools server API.
            +///
            +/// This defines endpoints that serve all requests that come in over api/.
            +class ServerApi {
            + static const errorNoActiveSurvey = 'ERROR: setActiveSurvey not called.';
            +
            + /// Determines whether or not [request] is an API call.
            + static bool canHandle(shelf.Request request) {
            + return request.url.path.startsWith(apiPrefix);
            + }
            +
            + /// Handles all requests.
            + ///
            + /// To override an API call, pass in a subclass of [ServerApi].
            + static FutureOr<shelf.Response> handle(
            + shelf.Request request, [
            + ServerApi api,
            + ]) {
            + api ??= ServerApi();
            + switch (request.url.path) {
            + // ----- Flutter Tool GA store. -----
            + case apiGetFlutterGAEnabled:
            + // Is Analytics collection enabled?
            + return api.getCompleted(
            + request,
            + json.encode(FlutterUsage.doesStoreExist ? _usage.enabled : null),
            + );
            + case apiGetFlutterGAClientId:
            + // Flutter Tool GA clientId - ONLY get Flutter's clientId if enabled is
            + // true.
            + return (FlutterUsage.doesStoreExist)
            + ? api.getCompleted(
            + request,
            + json.encode(_usage.enabled ? _usage.clientId : null),
            + )
            + : api.getCompleted(
            + request,
            + json.encode(null),
            + );
            +
            + // ----- DevTools GA store. -----
            +
            + case apiResetDevTools:
            + _devToolsUsage.reset();
            + return api.getCompleted(request, json.encode(true));
            + case apiGetDevToolsFirstRun:
            + // Has DevTools been run first time? To bring up welcome screen.
            + return api.getCompleted(
            + request,
            + json.encode(_devToolsUsage.isFirstRun),
            + );
            + case apiGetDevToolsEnabled:
            + // Is DevTools Analytics collection enabled?
            + return api.getCompleted(request, json.encode(_devToolsUsage.enabled));
            + case apiSetDevToolsEnabled:
            + // Enable or disable DevTools analytics collection.
            + final queryParams = request.requestedUri.queryParameters;
            + if (queryParams.containsKey(devToolsEnabledPropertyName)) {
            + _devToolsUsage.enabled =
            + json.decode(queryParams[devToolsEnabledPropertyName]);
            + }
            + return api.setCompleted(request, json.encode(_devToolsUsage.enabled));
            +
            + // ----- DevTools survey store. -----
            +
            + case apiSetActiveSurvey:
            + // Assume failure.
            + bool result = false;
            +
            + // Set the active survey used to store subsequent apiGetSurveyActionTaken,
            + // apiSetSurveyActionTaken, apiGetSurveyShownCount, and
            + // apiIncrementSurveyShownCount calls.
            + final queryParams = request.requestedUri.queryParameters;
            + if (queryParams.keys.length == 1 &&
            + queryParams.containsKey(activeSurveyName)) {
            + final String theSurveyName = queryParams[activeSurveyName];
            +
            + // Set the current activeSurvey.
            + _devToolsUsage.activeSurvey = theSurveyName;
            + result = true;
            + }
            +
            + return api.getCompleted(request, json.encode(result));
            + case apiGetSurveyActionTaken:
            + // Request setActiveSurvey has not been requested.
            + if (_devToolsUsage.activeSurvey == null) {
            + return api.badRequest('$errorNoActiveSurvey '
            + '- $apiGetSurveyActionTaken');
            + }
            + // SurveyActionTaken has the survey been acted upon (taken or dismissed)
            + return api.getCompleted(
            + request,
            + json.encode(_devToolsUsage.surveyActionTaken),
            + );
            + // TODO(terry): remove the query param logic for this request.
            + // setSurveyActionTaken should only be called with the value of true, so
            + // we can remove the extra complexity.
            + case apiSetSurveyActionTaken:
            + // Request setActiveSurvey has not been requested.
            + if (_devToolsUsage.activeSurvey == null) {
            + return api.badRequest('$errorNoActiveSurvey '
            + '- $apiSetSurveyActionTaken');
            + }
            + // Set the SurveyActionTaken.
            + // Has the survey been taken or dismissed..
            + final queryParams = request.requestedUri.queryParameters;
            + if (queryParams.containsKey(surveyActionTakenPropertyName)) {
            + _devToolsUsage.surveyActionTaken =
            + json.decode(queryParams[surveyActionTakenPropertyName]);
            + }
            + return api.setCompleted(
            + request,
            + json.encode(_devToolsUsage.surveyActionTaken),
            + );
            + case apiGetSurveyShownCount:
            + // Request setActiveSurvey has not been requested.
            + if (_devToolsUsage.activeSurvey == null) {
            + return api.badRequest('$errorNoActiveSurvey '
            + '- $apiGetSurveyShownCount');
            + }
            + // SurveyShownCount how many times have we asked to take survey.
            + return api.getCompleted(
            + request,
            + json.encode(_devToolsUsage.surveyShownCount),
            + );
            + case apiIncrementSurveyShownCount:
            + // Request setActiveSurvey has not been requested.
            + if (_devToolsUsage.activeSurvey == null) {
            + return api.badRequest('$errorNoActiveSurvey '
            + '- $apiIncrementSurveyShownCount');
            + }
            + // Increment the SurveyShownCount, we've asked about the survey.
            + _devToolsUsage.incrementSurveyShownCount();
            + return api.getCompleted(
            + request,
            + json.encode(_devToolsUsage.surveyShownCount),
            + );
            + case apiGetBaseAppSizeFile:
            + final queryParams = request.requestedUri.queryParameters;
            + if (queryParams.containsKey(baseAppSizeFilePropertyName)) {
            + final filePath = queryParams[baseAppSizeFilePropertyName];
            + final fileJson = LocalFileSystem.devToolsFileAsJson(filePath);
            + if (fileJson == null) {
            + return api.badRequest('No JSON file available at $filePath.');
            + }
            + return api.getCompleted(request, fileJson);
            + }
            + return api.badRequest('Request for base app size file does not '
            + 'contain a query parameter with the expected key: '
            + '$baseAppSizeFilePropertyName');
            + case apiGetTestAppSizeFile:
            + final queryParams = request.requestedUri.queryParameters;
            + if (queryParams.containsKey(testAppSizeFilePropertyName)) {
            + final filePath = queryParams[testAppSizeFilePropertyName];
            + final fileJson = LocalFileSystem.devToolsFileAsJson(filePath);
            + if (fileJson == null) {
            + return api.badRequest('No JSON file available at $filePath.');
            + }
            + return api.getCompleted(request, fileJson);
            + }
            + return api.badRequest('Request for test app size file does not '
            + 'contain a query parameter with the expected key: '
            + '$testAppSizeFilePropertyName');
            + default:
            + return api.notImplemented(request);
            + }
            + }
            +
            + // Accessing Flutter usage file e.g., ~/.flutter.
            + // NOTE: Only access the file if it exists otherwise Flutter Tool hasn't yet
            + // been run.
            + static final FlutterUsage _usage =
            + FlutterUsage.doesStoreExist ? FlutterUsage() : null;
            +
            + // Accessing DevTools usage file e.g., ~/.devtools
            + static final DevToolsUsage _devToolsUsage = DevToolsUsage();
            +
            + static DevToolsUsage get devToolsPreferences => _devToolsUsage;
            +
            + /// Logs a page view in the DevTools server.
            + ///
            + /// In the open-source version of DevTools, Google Analytics handles this
            + /// without any need to involve the server.
            + FutureOr<shelf.Response> logScreenView(shelf.Request request) =>
            + notImplemented(request);
            +
            + /// Return the value of the property.
            + FutureOr<shelf.Response> getCompleted(shelf.Request request, String value) =>
            + shelf.Response.ok('$value');
            +
            + /// Return the value of the property after the property value has been set.
            + FutureOr<shelf.Response> setCompleted(shelf.Request request, String value) =>
            + shelf.Response.ok('$value');
            +
            + /// A [shelf.Response] for API calls that encountered a request problem e.g.,
            + /// setActiveSurvey not called.
            + ///
            + /// This is a 400 Bad Request response.
            + FutureOr<shelf.Response> badRequest([String logError]) {
            + if (logError != null) print(logError);
            + return shelf.Response(HttpStatus.badRequest);
            + }
            +
            + /// A [shelf.Response] for API calls that have not been implemented in this
            + /// server.
            + ///
            + /// This is a no-op 204 No Content response because returning 404 Not Found
            + /// creates unnecessary noise in the console.
            + FutureOr<shelf.Response> notImplemented(shelf.Request request) =>
            + shelf.Response(HttpStatus.noContent);
            +}
            diff --git a/pkg/dds/lib/src/devtools/usage.dart b/pkg/dds/lib/src/devtools/usage.dart
            new file mode 100644
            index 0000000..afa35d7
            --- /dev/null
            +++ b/pkg/dds/lib/src/devtools/usage.dart
            @@ -0,0 +1,236 @@
            +// Copyright 2021 The Chromium Authors. All rights reserved.
            +// Use of this source code is governed by a BSD-style license that can be
            +// found in the LICENSE file.
            +
            +// @dart=2.9
            +
            +// TODO(bkonyi): remove once package:devtools_server_api is available
            +// See https://github.com/flutter/devtools/issues/2958.
            +
            +import 'dart:convert';
            +import 'dart:io';
            +
            +import 'package:path/path.dart' as path;
            +import 'package:usage/usage_io.dart';
            +
            +import 'file_system.dart';
            +
            +/// Access the file '~/.flutter'.
            +class FlutterUsage {
            + /// Create a new Usage instance; [versionOverride] and [configDirOverride] are
            + /// used for testing.
            + FlutterUsage({
            + String settingsName = 'flutter',
            + String versionOverride,
            + String configDirOverride,
            + }) {
            + _analytics = AnalyticsIO('', settingsName, '');
            + }
            +
            + Analytics _analytics;
            +
            + /// Does the .flutter store exist?
            + static bool get doesStoreExist {
            + return LocalFileSystem.flutterStoreExists();
            + }
            +
            + bool get isFirstRun => _analytics.firstRun;
            +
            + bool get enabled => _analytics.enabled;
            +
            + set enabled(bool value) => _analytics.enabled = value;
            +
            + String get clientId => _analytics.clientId;
            +}
            +
            +// Access the DevTools on disk store (~/.devtools/.devtools).
            +class DevToolsUsage {
            + /// Create a new Usage instance; [versionOverride] and [configDirOverride] are
            + /// used for testing.
            + DevToolsUsage({
            + String versionOverride,
            + String configDirOverride,
            + }) {
            + LocalFileSystem.maybeMoveLegacyDevToolsStore();
            + properties = IOPersistentProperties(
            + storeName,
            + documentDirPath: LocalFileSystem.devToolsDir(),
            + );
            + }
            +
            + static const storeName = '.devtools';
            +
            + /// The activeSurvey is the property name of a top-level property
            + /// existing or created in the file ~/.devtools
            + /// If the property doesn't exist it is created with default survey values:
            + ///
            + /// properties[activeSurvey]['surveyActionTaken'] = false;
            + /// properties[activeSurvey]['surveyShownCount'] = 0;
            + ///
            + /// It is a requirement that the API apiSetActiveSurvey must be called before
            + /// calling any survey method on DevToolsUsage (addSurvey, rewriteActiveSurvey,
            + /// surveyShownCount, incrementSurveyShownCount, or surveyActionTaken).
            + String _activeSurvey;
            +
            + IOPersistentProperties properties;
            +
            + static const _surveyActionTaken = 'surveyActionTaken';
            + static const _surveyShownCount = 'surveyShownCount';
            +
            + void reset() {
            + properties.remove('firstRun');
            + properties['enabled'] = false;
            + }
            +
            + bool get isFirstRun {
            + properties['firstRun'] = properties['firstRun'] == null;
            + return properties['firstRun'];
            + }
            +
            + bool get enabled {
            + if (properties['enabled'] == null) {
            + properties['enabled'] = false;
            + }
            +
            + return properties['enabled'];
            + }
            +
            + set enabled(bool value) {
            + properties['enabled'] = value;
            + return properties['enabled'];
            + }
            +
            + bool surveyNameExists(String surveyName) => properties[surveyName] != null;
            +
            + void _addSurvey(String surveyName) {
            + assert(activeSurvey != null);
            + assert(activeSurvey == surveyName);
            + rewriteActiveSurvey(false, 0);
            + }
            +
            + String get activeSurvey => _activeSurvey;
            +
            + set activeSurvey(String surveyName) {
            + assert(surveyName != null);
            + _activeSurvey = surveyName;
            +
            + if (!surveyNameExists(activeSurvey)) {
            + // Create the survey if property is non-existent in ~/.devtools
            + _addSurvey(activeSurvey);
            + }
            + }
            +
            + /// Need to rewrite the entire survey structure for property to be persisted.
            + void rewriteActiveSurvey(bool actionTaken, int shownCount) {
            + assert(activeSurvey != null);
            + properties[activeSurvey] = {
            + _surveyActionTaken: actionTaken,
            + _surveyShownCount: shownCount,
            + };
            + }
            +
            + int get surveyShownCount {
            + assert(activeSurvey != null);
            + final prop = properties[activeSurvey];
            + if (prop[_surveyShownCount] == null) {
            + rewriteActiveSurvey(prop[_surveyActionTaken], 0);
            + }
            + return properties[activeSurvey][_surveyShownCount];
            + }
            +
            + void incrementSurveyShownCount() {
            + assert(activeSurvey != null);
            + surveyShownCount; // Ensure surveyShownCount has been initialized.
            + final prop = properties[activeSurvey];
            + rewriteActiveSurvey(prop[_surveyActionTaken], prop[_surveyShownCount] + 1);
            + }
            +
            + bool get surveyActionTaken {
            + assert(activeSurvey != null);
            + return properties[activeSurvey][_surveyActionTaken] == true;
            + }
            +
            + set surveyActionTaken(bool value) {
            + assert(activeSurvey != null);
            + final prop = properties[activeSurvey];
            + rewriteActiveSurvey(value, prop[_surveyShownCount]);
            + }
            +}
            +
            +abstract class PersistentProperties {
            + PersistentProperties(this.name);
            +
            + final String name;
            +
            + dynamic operator [](String key);
            +
            + void operator []=(String key, dynamic value);
            +
            + /// Re-read settings from the backing store.
            + ///
            + /// May be a no-op on some platforms.
            + void syncSettings();
            +}
            +
            +const JsonEncoder _jsonEncoder = JsonEncoder.withIndent(' ');
            +
            +class IOPersistentProperties extends PersistentProperties {
            + IOPersistentProperties(
            + String name, {
            + String documentDirPath,
            + }) : super(name) {
            + final String fileName = name.replaceAll(' ', '_');
            + documentDirPath ??= LocalFileSystem.devToolsDir();
            + _file = File(path.join(documentDirPath, fileName));
            + if (!_file.existsSync()) {
            + _file.createSync(recursive: true);
            + }
            + syncSettings();
            + }
            +
            + IOPersistentProperties.fromFile(File file) : super(path.basename(file.path)) {
            + _file = file;
            + if (!_file.existsSync()) {
            + _file.createSync(recursive: true);
            + }
            + syncSettings();
            + }
            +
            + File _file;
            +
            + Map _map;
            +
            + @override
            + dynamic operator [](String key) => _map[key];
            +
            + @override
            + void operator []=(String key, dynamic value) {
            + if (value == null && !_map.containsKey(key)) return;
            + if (_map[key] == value) return;
            +
            + if (value == null) {
            + _map.remove(key);
            + } else {
            + _map[key] = value;
            + }
            +
            + try {
            + _file.writeAsStringSync(_jsonEncoder.convert(_map) + '\n');
            + } catch (_) {}
            + }
            +
            + @override
            + void syncSettings() {
            + try {
            + String contents = _file.readAsStringSync();
            + if (contents.isEmpty) contents = '{}';
            + _map = jsonDecode(contents);
            + } catch (_) {
            + _map = {};
            + }
            + }
            +
            + void remove(String propertyName) {
            + _map.remove(propertyName);

            + }
            +}
            diff --git a/pkg/dds/pubspec.yaml b/pkg/dds/pubspec.yaml
            index 221e3df..a69236c 100644

            --- a/pkg/dds/pubspec.yaml
            +++ b/pkg/dds/pubspec.yaml
            @@ -3,7 +3,7 @@
            A library used to spawn the Dart Developer Service, used to communicate with
            a Dart VM Service instance.

            -version: 1.7.6
            +version: 1.8.0-dev

            homepage: https://github.com/dart-lang/sdk/tree/master/pkg/dds

            @@ -12,18 +12,21 @@

            dependencies:
            async: ^2.4.1
            + devtools_shared: ^2.0.0
            json_rpc_2: ^2.2.0
            meta: ^1.1.8
            + path: ^1.8.0

            pedantic: ^1.7.0
            shelf: ^1.0.0
            shelf_proxy: ^1.0.0
            + shelf_static: ^1.0.0-dev
            shelf_web_socket: ^1.0.0
            sse: ^3.7.0
            stream_channel: ^2.0.0
            +  usage: ^4.0.0
            vm_service: ^6.0.1-nullsafety.0
            index d1f8a5d..833e5a2 100644

            --- a/sdk/lib/_internal/vm/bin/vmservice_io.dart
            +++ b/sdk/lib/_internal/vm/bin/vmservice_io.dart
            @@ -43,6 +43,7 @@
            // HTTP server.
            Server? server;
            Future<Server>? serverFuture;
            +_DebuggingSession? ddsInstance;

            Server _lazyServerBoot() {
            var localServer = server;
            @@ -58,6 +59,90 @@
            +      if (fullSdk) 'resources',
            + 'devtools',

            + ].join('/');
            +
            +    const enableLogging = false;

            + _process = await Process.start(
            + dartPath.toString(),
            + [
            + ddsSnapshot,
            + server!.serverAddress!.toString(),
            + host,
            + port,
            + disableServiceAuthCodes.toString(),
            + enableDevTools.toString(),
            + devToolsBinaries,
            +        enableLogging.toString(),
            @@ -221,10 +306,6 @@

            _server.acceptNewWebSocketConnections = enable;
            }

            -void _clearFuture(_) {
            - serverFuture = null;
            -}
            -
            _onSignal(ProcessSignal signal) {
            if (serverFuture != null) {
            // Still waiting.
            @@ -233,9 +314,21 @@
            index a69f6ee..077d758 100755
            --- a/third_party/devtools/update.sh
            +++ b/third_party/devtools/update.sh
            @@ -30,12 +30,11 @@
            # to serve from DDS.
            mkdir cipd_package
            cp -R packages/devtools/build/ cipd_package/web
            -cp -r packages/devtools_server cipd_package
            cp -r packages/devtools_shared cipd_package

            cipd create \

            -name dart/third_party/flutter/devtools \
            -in cipd_package \
            -install-mode copy \
            - -tag revision:$1
            + -tag git_revision:$1

            diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
            index be5f821..bfa020b 100644
            index 7f33d99..3ce3bc3 100644
            --- a/utils/dartdev/BUILD.gn
            +++ b/utils/dartdev/BUILD.gn
            @@ -2,12 +2,14 @@

            # for details. All rights reserved. Use of this source code is governed by a
            # BSD-style license that can be found in the LICENSE file.

            +import("../../build/dart/copy_tree.gni")
            import("../application_snapshot.gni")

             group("dartdev") {

            public_deps = [
            ":copy_dartdev_kernel",
            ":copy_dartdev_snapshot",
            + ":copy_prebuilt_devtools",
            ]
            }

            @@ -39,3 +41,15 @@
            deps = [ "../dds:dds" ]

            output = "$root_gen_dir/dartdev.dart.snapshot"
            }
            +
            +copy_trees("copy_prebuilt_devtools") {
            + sources = [
            + {
            + target = "copy_prebuilt_devtools"
            + visibility = [ ":dartdev" ]
            + source = "../../third_party/devtools/web"
            + dest = "$root_out_dir/devtools"
            + ignore_patterns = "{}"
            + },
            + ]
            +}

            20 is the latest approved patch-set. The change was submitted with unreviewed changes in the following files: The name of the file: .dart_tool/package_config.json Insertions: 7, Deletions: 1. ``` @@ -13:14, +13:14 @@ - "generated": "2021-04-29T17:46:07.346900", + "generated": "2021-05-03T09:47:39.938400", @@ +742:748 @@ + "name": "uuid", + "rootUri": "../third_party/pkg/uuid", + "packageUri": "lib/", + "languageVersion": "2.0" + }, + { ``` The name of the file: sdk/lib/_internal/vm/bin/vmservice_io.dart Insertions: 1, Deletions: 1. ``` @@ -89:90, +89:90 @@ - if (fullSdk) 'bin/resources', + if (fullSdk) 'resources', ``` The name of the file: third_party/devtools/update.sh Insertions: 0, Deletions: 1. ``` @@ -32:33 @@ - cp -r packages/devtools_server cipd_package ```

            To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

            Gerrit-Project: sdk
            Gerrit-Branch: master
            Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
            Gerrit-Change-Number: 188361
            Gerrit-PatchSet: 23
            Gerrit-Owner: Ben Konyi <bko...@google.com>
            Gerrit-Reviewer: Ben Konyi <bko...@google.com>
            Gerrit-Reviewer: Jacob Richman <jac...@google.com>
            Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
            Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
            Gerrit-Reviewer: Siva Annamalai <as...@google.com>
            Gerrit-CC: Devon Carew <devon...@google.com>
            Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
            Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
            Gerrit-MessageType: merged

            Dart CI (Gerrit)

            unread,
            May 3, 2021, 3:19:28 PM5/3/21
            to commi...@chromium.org, Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Ivan Inozemtsev, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, Keerti Parthasarathy

            go/dart-cbuild result: FAILURE (REGRESSIONS DETECTED)

            Details: https://goto.google.com/dart-cbuild/find/ef0e4ea10713b546363f24511bfdc2c6ce52d861
            Bugs: go/dart-cbuild-bug/ef0e4ea10713b546363f24511bfdc2c6ce52d861

            View Change

              To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: sdk
              Gerrit-Branch: master
              Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
              Gerrit-Change-Number: 188361
              Gerrit-PatchSet: 23
              Gerrit-Owner: Ben Konyi <bko...@google.com>
              Gerrit-Reviewer: Ben Konyi <bko...@google.com>
              Gerrit-Reviewer: Jacob Richman <jac...@google.com>
              Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
              Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
              Gerrit-Reviewer: Siva Annamalai <as...@google.com>
              Gerrit-CC: Devon Carew <devon...@google.com>
              Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
              Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
              Gerrit-Comment-Date: Mon, 03 May 2021 19:19:23 +0000

              Daco Harkes (Gerrit)

              unread,
              May 4, 2021, 7:33:01 AM5/4/21
              to commi...@chromium.org, Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Ivan Inozemtsev, Dart CI, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, Keerti Parthasarathy

              View Change

              1 comment:

              To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: sdk
              Gerrit-Branch: master
              Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
              Gerrit-Change-Number: 188361
              Gerrit-PatchSet: 23
              Gerrit-Owner: Ben Konyi <bko...@google.com>
              Gerrit-Reviewer: Ben Konyi <bko...@google.com>
              Gerrit-Reviewer: Jacob Richman <jac...@google.com>
              Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
              Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
              Gerrit-Reviewer: Siva Annamalai <as...@google.com>
              Gerrit-CC: Daco Harkes <dacoh...@google.com>
              Gerrit-CC: Devon Carew <devon...@google.com>
              Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
              Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
              Gerrit-Comment-Date: Tue, 04 May 2021 11:32:55 +0000
              Gerrit-HasComments: Yes
              Gerrit-Has-Labels: No
              Gerrit-MessageType: comment

              Alexander Markov (Gerrit)

              unread,
              May 5, 2021, 12:58:02 PM5/5/21
              to commi...@chromium.org, Ben Konyi, rev...@dartlang.org, vm-...@dartlang.org, Daco Harkes, Ivan Inozemtsev, Dart CI, Kenzie Schmoll, Jacob Richman, Siva Annamalai, Ryan Macnak, Devon Carew, Keerti Parthasarathy, Alexander Markov

              Alexander Markov has created a revert of this change.

              View Change

              To view, visit change 188361. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: sdk
              Gerrit-Branch: master
              Gerrit-Change-Id: Icd1afda87ad4a46f228125d53094d10adf8056ec
              Gerrit-Change-Number: 188361
              Gerrit-PatchSet: 23
              Gerrit-Owner: Ben Konyi <bko...@google.com>
              Gerrit-Reviewer: Ben Konyi <bko...@google.com>
              Gerrit-Reviewer: Jacob Richman <jac...@google.com>
              Gerrit-Reviewer: Kenzie Schmoll <kenzie...@google.com>
              Gerrit-Reviewer: Ryan Macnak <rma...@google.com>
              Gerrit-Reviewer: Siva Annamalai <as...@google.com>
              Gerrit-CC: Daco Harkes <dacoh...@google.com>
              Gerrit-CC: Devon Carew <devon...@google.com>
              Gerrit-CC: Ivan Inozemtsev <iinoz...@google.com>
              Gerrit-CC: Keerti Parthasarathy <kee...@google.com>
              Gerrit-MessageType: revert
              Reply all
              Reply to author
              Forward
              0 new messages