Skip to content

[flutter_tools] Add DeviceService app launch and flutter run support for tool extensions - #194589

Merged
auto-submit[bot] merged 15 commits into
flutter:masterfrom
bkonyi:ft-ext-step08-app-launch
Oct 27, 2026
Merged

auto-submit[bot] merged 15 commits into
flutter:masterfrom
bkonyi:ft-ext-step08-app-launch

Conversation

@bkonyi

@bkonyi bkonyi commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Adds DeviceService RPC methods (device.launchApp, device.getVmServiceUri, and device.stopApp) and ExtensionDebuggingOptions to support building, launching, and stopping applications on tool extension devices via flutter run. Also exposes @protected final Logger logger on Device for subclasses.

Part of #190753

…for tool extensions

Introduce `DeviceService.launchApp`, `getVmServiceUri`, and `stopApp` RPC methods, `TargetDevice.buildTarget`, `ExtensionBuildResult.executablePath`, and `ExtensionBackedDevice.startApp`/`stopApp` with VM Service discovery and `ResidentRunner` integration so `flutter run` works on custom extension devices.
@bkonyi bkonyi added CICD Run CI/CD tool Affects the "flutter" command-line tool. See also t: labels. labels Oct 16, 2026
@github-actions github-actions Bot added the team-linux Owned by the Linux platform team label Oct 16, 2026
…ager wiring

Delegates extension app builds in `ExtensionBackedDevice.startApp` to `ExtensionBuildManager`, supports `prebuiltApplication: true` via `PrebuiltApplicationPackage`, adds strongly-typed `ExtensionDebuggingOptions`, and hardens null-safe `vmService` handling in `ResidentRunner` and `HotRunner`.
Reverts unnecessary `source.dart` changes, removes arbitrary RPC and process launch timeouts, logs non-boolean RPC responses, tightens `ExtensionBackedDevice.startApp`, `FlutterDeviceManager`, and `ResidentHandlers.flutterDevices` nullability, documents early `pub.get()` in `FlutterCommand`, and parses `pubspec.yaml` via `package:yaml` in `LinuxBuildService`.
Use absolute file Uri for executableUri on ExtensionBuildResult and DeviceService.launchApp, require ExtensionDebuggingOptions on launchApp, fail ExtensionBackedDevice.startApp when VM Service discovery returns null with debugging enabled, revert core runner and early pub.get changes, consolidate LinuxDeviceService process state into _RunningApp, and support base64url padding in VM Service URI matching.
…I validation

Exports RpcException from package:flutter_tools_extension and updates prototype RPC error assertions to match RpcException directly. Exposes protected logger on Device to remove duplicate _logger in ExtensionBackedDevice, adds ExtensionFileUriValidation.isValidFileUri in package:flutter_tools_core, and simplifies ExtensionBuildResult._parseExecutableUri.
…aunch

# Conflicts:
#	packages/flutter_tools/lib/src/context/tool_dependencies.dart
#	packages/flutter_tools/lib/src/experimental/extension_device_manager.dart
#	packages/flutter_tools/lib/src/flutter_device_manager.dart
#	packages/flutter_tools/packages/flutter_tools_extension/lib/src/device.dart
#	packages/flutter_tools/packages/flutter_tools_extension_linux_prototype/lib/src/device.dart
#	packages/flutter_tools/packages/flutter_tools_extension_linux_prototype/test/linux_device_test.dart
#	packages/flutter_tools/test/commands.shard/hermetic/tool_extensions_device_test.dart
…unch

- Require debuggingEnabled in ExtensionDebuggingOptions constructor and deserialization.
- Reject prebuilt application bundles with a clean error on ExtensionBackedDevice until support is implemented.
- Enforce strict BINARY_NAME extraction from linux/CMakeLists.txt in LinuxBuildService without pubspec name fallbacks.
- Use allowMalformed: true when decoding process stdout/stderr in LinuxDeviceService and validate received VM service URIs.
- Revert modifications to Device base class to preserve Google3 compatibility.
@bkonyi
bkonyi marked this pull request as ready for review October 22, 2026 01:48
@bkonyi
bkonyi requested a review from a team as a code owner October 22, 2026 01:48

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements application launching, stopping, and VM Service URI discovery for tool extension devices. It updates the Device and DeviceService interfaces, provides a prototype implementation for Linux, and adds corresponding tests. The review feedback recommends making the VM Service URI matching regular expression more robust by supporting localhost and optional auth tokens, and correcting invalid leading-dot enum shorthand syntax (.debug to BuildMode.debug) in several test files.

chingjun
chingjun previously approved these changes Oct 22, 2026
@loic-sharma

Copy link
Copy Markdown
Member

I'll review this one tomorrow! :)

Comment on lines +343 to +365
final String? buildTargetName = _targetDevice.buildTarget;
if (buildTargetName == null) {
logger.printError('Device $name does not specify a buildTarget for launching applications.');
return LaunchResult.failed();
}

final String targetMainPath = mainPath ?? 'lib/main.dart';
logger.printTrace('Building application using extension target "$buildTargetName"...');
final ExtensionBuildResult result = await _buildManager.build(
buildMode: buildMode,
mainPath: targetMainPath,
projectRoot: _fileSystem.currentDirectory.uri,
targetName: buildTargetName,
);
if (!result.success) {
final String? errorMessage = result.errorMessage;
logger.printError(
errorMessage != null && errorMessage.isNotEmpty
? 'Build failed: $errorMessage'
: 'Build failed.',
);
return LaunchResult.failed();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make the extension responsible for building the app as part of launchApp? This would help reduce communication between the tool and the extension. It also gives the extension greater control over what happens before/after the app is built.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the build step orchestrated by the host in ExtensionBackedDevice.startApp lets startApp support prebuiltApplication: true (--use-application-binary) without rebuilding, and lets the host resolve build output directories, artifact dependencies, and flutter assemble targets before passing the resulting binary URI to DeviceService.launchApp.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still feel uncertain but I'd be fine with this approach if we feel confident this will support all Android/iOS/web scenarios.

Today a device can have different build logic for its flutter build foo and flutter run -d foo commands. There might not be a flutter build subcommand that mirrors the build logic that runs on flutter run -d foo. But if this is a real scenario, I suspect we might be able to address it by supporting "hidden" build targets.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a device needs separate build logic for flutter run that shouldn't be exposed as a flutter build subcommand, we could also allow TargetDevice to reference an AssembleTarget (which is already internal to flutter assemble) rather than needing hidden BuildTargets.

/// [ExtensionDebuggingOptions.debuggingEnabled] is `true`. Implementations
/// may await VM Service discovery from the running process before returning,
/// or return `null` if the process exits or VM Service discovery fails.
Future<Uri?> getVmServiceUri({required String deviceId});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this current pattern, if we need to add an optional argument to getVmServiceUri, changing the method signature would be a breaking change. Instead, we'd need to introduce a new method with the new optional argument.

Perhaps all ToolExtensionService methods that an extension implements should accept an FooOptions object. For example, this would be:

final class GetVmServiceUriOptions { 
  GetVmServiceUriOptions({
    required this.deviceId,
  });

  final String deviceId;
}

abstract base class DeviceService extends ToolExtensionService {
  Future<Uri?> getVmServiceUri(GetVmServiceUriOptions options);
}

(Apologies if I've already commented on this and I'm repeating feedback!)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since extensions can constrain their package:flutter_tools_extension dependency in pubspec.yaml, signature changes only affect extensions when they explicitly bump their dependency constraint. The cross-version compatibility boundary between a newer flutter_tools SDK and an already-published extension is the JSON-RPC wire protocol, so keeping the wire protocol tolerant to new request fields and response object properties can give us compatibility without needing FooOptions wrappers on every method.

I think that encouraging extension authors to pin their package:flutter_tools_extension dependency or use caret version ranges would accomplish the same thing as wrapper objects if we respect semver properly. I'm not a huge fan of wrapper objects for parameters, but I do agree that they're probably the most robust way to handle adding additional parameters. I'm open to having a discussion on this :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since extensions can constrain their package:flutter_tools_extension dependency in pubspec.yaml, signature changes only affect extensions when they explicitly bump their dependency constraint.

Ah and if I remember correctly, two extension can have two different package:flutter_tools_extension versions? If that's the case, I'm OK with skipping wrapper objects.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct! Individual extensions can have completely different dependencies, including conflicting ones.

…-launch

# Conflicts:
#	packages/flutter_tools/packages/flutter_tools_core/lib/src/project.dart
#	packages/flutter_tools/packages/flutter_tools_extension_linux_prototype/lib/src/build.dart
#	packages/flutter_tools/packages/flutter_tools_extension_linux_prototype/test/linux_build_test.dart
#	packages/flutter_tools/test/commands.shard/hermetic/tool_extensions_build_test.dart
…ess.kill() in stopApp

Do not call stopApp when getVmServiceUri returns null during ExtensionBackedDevice.startApp, and return false from LinuxDeviceService.stopApp if process.kill() fails.

/// The [ExtensionBuildTarget.name] of the extension build target used to
/// build an application for this device during `flutter run`.
final String? buildTarget;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, it looks like ExtensionBuildTarget.name doesn't validate the extension's value. We should also add some docs to explain what's legal or not. Feel free to punt to another PR though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added ExtensionBuildTarget.isValidName validation and documented the valid target name format on ExtensionBuildTarget.name, BuildTarget.name, and TargetDevice.buildTarget.

loic-sharma
loic-sharma previously approved these changes Oct 26, 2026

@loic-sharma loic-sharma left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

…aunch

# Conflicts:
#	packages/flutter_tools/lib/src/experimental/extension_device_manager.dart
#	packages/flutter_tools/packages/flutter_tools_extension/lib/src/device.dart
#	packages/flutter_tools/test/commands.shard/hermetic/tool_extensions_device_test.dart
Validate ExtensionBuildTarget.name with isValidName, constructor assertion, and deserialization FormatException.

Remove empty build target name bypass in ExtensionBuildManager.

Define ExtensionUriValidation on non-nullable Uri.

Restore CMake BINARY_NAME check in LinuxBuildService.build.

Ensure LinuxDeviceService.stopApp verifies process termination before cleaning up tracking state.

Update tracking issue link for forwarding additional build and debug options.

Update unit tests for invalid build target names and URI validation.
Add const to collection arguments in build_test.dart and use inferred type for executableFile.

Add explicit String type annotation to _invalidNameMessage.

Remove redundant timeouts in ExtensionDeviceClient isSupportedForProject and stopApp.

Restore exact origin/master variable naming in ExtensionDevices.pollingGetDevices.

Update Phase 8 tracking issue URL in extension_device_manager.dart.

Fail early in ExtensionBackedDevice.startApp when no extension provides the requested build target.

Add unit test verifying startApp fails when the build target is missing.
@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 27, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into flutter:master with commit df89551 Oct 27, 2026
33 of 34 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 27, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Oct 28, 2026
flutter/flutter@d4c8577...0c2473c

2026-10-28 [email protected] Roll Packages from a8549ae to 13d38e0 (9 revisions) (flutter/flutter#195488)
2026-10-28 [email protected] Use int.oneBitCount in PersistentHashMap and scope 53-bit caps to JS (flutter/flutter#195005)
2026-10-28 [email protected] Roll pub packages (flutter/flutter#195483)
2026-10-28 [email protected] [iPhone Duo] Use the correct UIScreen to report the display size and update when fold/unfold (flutter/flutter#195199)
2026-10-28 [email protected] [fuchsia] Fix portable_ui_test.h includes for newer Fuchsia SDKs (flutter/flutter#195420)
2026-10-28 [email protected] Change default pipeline options to match production draw calls (flutter/flutter#194597)
2026-10-28 [email protected] Roll Fuchsia Test Scripts from 2T18KC7-LDQtmQiLP... to xl1LWBuppzu-BnOzV... (flutter/flutter#195450)
2026-10-27 [email protected] [flutter_tools] Inject dependencies into Darwin build targets, native assets, and Xcode build settings (flutter/flutter#194052)
2026-10-27 [email protected] Revert: Reland square corners fix (flutter/flutter#195436)
2026-10-27 [email protected] [flutter_tools] Add DeviceService app launch and flutter run support for tool extensions (flutter/flutter#194589)
2026-10-27 [email protected] [engine] Honor targetWidth/targetHeight for animated images (flutter/flutter#194615)
2026-10-27 [email protected] [Android][a11y] Set visibleToUser=false for hidden semantics nodes (flutter/flutter#194411)
2026-10-27 [email protected] Fix repo deletion test flake (flutter/flutter#195349)
2026-10-27 [email protected] Roll Packages from 23a05b6 to a8549ae (10 revisions) (flutter/flutter#195434)
2026-10-27 [email protected] [web] Capture pointers to the Flutter view so drags survive platform view iframes (flutter/flutter#195187)
2026-10-27 [email protected] [web] Add opt-in raw samples, measured sample count and warm-up phase hook to the web benchmark recorder (flutter/flutter#195118)
2026-10-27 [email protected] Link migration guide in deprecation messages (flutter/flutter#195361)
2026-10-27 [email protected] Pin basic_material_app_macos__compile to macOS 26 (flutter/flutter#195429)
2026-10-27 [email protected] Add benchmark for warmed pipeline usage (flutter/flutter#195001)
2026-10-27 [email protected] [flutter_tools] Add device log streaming support to DeviceService and ExtensionBackedDevice (flutter/flutter#194964)
2026-10-27 [email protected] Roll Dart SDK from 1d16c04dc346 to 65fc979759ca (4 revisions) (flutter/flutter#195383)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
suryaKommana2662 pushed a commit to suryaKommana2662/flutter that referenced this pull request Oct 29, 2026
…for tool extensions (flutter#194589)

Adds `DeviceService` RPC methods (`device.launchApp`,
`device.getVmServiceUri`, and `device.stopApp`) and
`ExtensionDebuggingOptions` to support building, launching, and stopping
applications on tool extension devices via `flutter run`. Also exposes
`@protected final Logger logger` on `Device` for subclasses.

Part of flutter#190753
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD team-linux Owned by the Linux platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants