![auto-submit[bot]](/assets/img/avatar_default.png)
Reverts: flutter/flutter#146593 Initiated by: zanderso Reason for reverting: Consistently failing `Windows_android native_assets_android` as in https://ci.chromium.org/ui/p/flutter/builders/prod/Windows_android%20native_assets_android/2533/overview Original PR Author: bkonyi Reviewed By: {christopherfujino, kenzieschmoll} This change reverts the following previous change: This change is a major step towards moving away from shipping DDS via Pub. The first component of this PR is the move away from importing package:dds to launch DDS. Instead, DDS is launched out of process using the `dart development-service` command shipped with the Dart SDK. This makes Flutter's handling of DDS consistent with the standalone Dart VM. The second component of this PR is the initial work to prepare for the removal of instances of DevTools being served manually by the flutter_tool, instead relying on DDS to serve DevTools. This will be consistent with how the standalone Dart VM serves DevTools, tying the DevTools lifecycle to a live DDS instance. This will allow for the removal of much of the logic needed to properly manage the lifecycle of the DevTools server in a future PR. Also, by serving DevTools from DDS, users will no longer need to forward a secondary port in remote workflows as DevTools will be available on the DDS port. There's two remaining circumstances that will prevent us from removing DevtoolsRunner completely: - The daemon's `devtools.serve` endpoint - `flutter drive`'s `--profile-memory` flag used for recording memory profiles This PR also includes some refactoring around `DebuggingOptions` to reduce the number of debugging related arguments being passed as parameters adjacent to a `DebuggingOptions` instance.
546 lines
14 KiB
Dart
546 lines
14 KiB
Dart
// Copyright 2014 The Flutter Authors. 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 'package:dds/dds.dart' as dds;
|
|
import 'package:flutter_tools/src/application_package.dart';
|
|
import 'package:flutter_tools/src/asset.dart';
|
|
import 'package:flutter_tools/src/base/dds.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/build_info.dart';
|
|
import 'package:flutter_tools/src/build_system/tools/scene_importer.dart';
|
|
import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart';
|
|
import 'package:flutter_tools/src/compile.dart';
|
|
import 'package:flutter_tools/src/devfs.dart';
|
|
import 'package:flutter_tools/src/device.dart';
|
|
import 'package:flutter_tools/src/device_port_forwarder.dart';
|
|
import 'package:flutter_tools/src/project.dart';
|
|
import 'package:flutter_tools/src/resident_runner.dart';
|
|
import 'package:flutter_tools/src/run_cold.dart';
|
|
import 'package:flutter_tools/src/run_hot.dart';
|
|
import 'package:flutter_tools/src/vmservice.dart';
|
|
import 'package:package_config/package_config.dart';
|
|
import 'package:test/fake.dart';
|
|
import 'package:vm_service/vm_service.dart' as vm_service;
|
|
|
|
import '../src/fake_vm_services.dart';
|
|
|
|
final vm_service.Event fakeUnpausedEvent = vm_service.Event(
|
|
kind: vm_service.EventKind.kResume,
|
|
timestamp: 0
|
|
);
|
|
|
|
final vm_service.Event fakePausedEvent = vm_service.Event(
|
|
kind: vm_service.EventKind.kPauseException,
|
|
timestamp: 0
|
|
);
|
|
|
|
final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate(
|
|
id: '1',
|
|
pauseEvent: fakeUnpausedEvent,
|
|
breakpoints: <vm_service.Breakpoint>[],
|
|
extensionRPCs: <String>[],
|
|
libraries: <vm_service.LibraryRef>[
|
|
vm_service.LibraryRef(
|
|
id: '1',
|
|
uri: 'file:///hello_world/main.dart',
|
|
name: '',
|
|
),
|
|
],
|
|
livePorts: 0,
|
|
name: 'test',
|
|
number: '1',
|
|
pauseOnExit: false,
|
|
runnable: true,
|
|
startTime: 0,
|
|
isSystemIsolate: false,
|
|
isolateFlags: <vm_service.IsolateFlag>[],
|
|
);
|
|
|
|
final vm_service.Isolate fakePausedIsolate = vm_service.Isolate(
|
|
id: '1',
|
|
pauseEvent: fakePausedEvent,
|
|
breakpoints: <vm_service.Breakpoint>[
|
|
vm_service.Breakpoint(
|
|
breakpointNumber: 123,
|
|
id: 'test-breakpoint',
|
|
location: vm_service.SourceLocation(
|
|
tokenPos: 0,
|
|
script: vm_service.ScriptRef(id: 'test-script', uri: 'foo.dart'),
|
|
),
|
|
enabled: true,
|
|
resolved: true,
|
|
),
|
|
],
|
|
libraries: <vm_service.LibraryRef>[],
|
|
livePorts: 0,
|
|
name: 'test',
|
|
number: '1',
|
|
pauseOnExit: false,
|
|
runnable: true,
|
|
startTime: 0,
|
|
isSystemIsolate: false,
|
|
isolateFlags: <vm_service.IsolateFlag>[],
|
|
);
|
|
|
|
final vm_service.VM fakeVM = vm_service.VM(
|
|
isolates: <vm_service.IsolateRef>[fakeUnpausedIsolate],
|
|
pid: 1,
|
|
hostCPU: '',
|
|
isolateGroups: <vm_service.IsolateGroupRef>[],
|
|
targetCPU: '',
|
|
startTime: 0,
|
|
name: 'dart',
|
|
architectureBits: 64,
|
|
operatingSystem: '',
|
|
version: '',
|
|
systemIsolateGroups: <vm_service.IsolateGroupRef>[],
|
|
systemIsolates: <vm_service.IsolateRef>[],
|
|
);
|
|
|
|
final FlutterView fakeFlutterView = FlutterView(
|
|
id: 'a',
|
|
uiIsolate: fakeUnpausedIsolate,
|
|
);
|
|
|
|
final FakeVmServiceRequest listViews = FakeVmServiceRequest(
|
|
method: kListViewsMethod,
|
|
jsonResponse: <String, Object>{
|
|
'views': <Object>[
|
|
fakeFlutterView.toJson(),
|
|
],
|
|
},
|
|
);
|
|
|
|
const FakeVmServiceRequest renderFrameRasterStats = FakeVmServiceRequest(
|
|
method: kRenderFrameWithRasterStatsMethod,
|
|
args: <String, Object>{
|
|
'viewId': 'a',
|
|
'isolateId': '1',
|
|
},
|
|
error: FakeRPCError(
|
|
code: RPCErrorCodes.kServerError,
|
|
error: 'Raster status not supported on Impeller backend',
|
|
),
|
|
);
|
|
|
|
const FakeVmServiceRequest setAssetBundlePath = FakeVmServiceRequest(
|
|
method: '_flutter.setAssetBundlePath',
|
|
args: <String, Object>{
|
|
'viewId': 'a',
|
|
'assetDirectory': 'build/flutter_assets',
|
|
'isolateId': '1',
|
|
}
|
|
);
|
|
|
|
const FakeVmServiceRequest evict = FakeVmServiceRequest(
|
|
method: 'ext.flutter.evict',
|
|
args: <String, Object>{
|
|
'value': 'asset',
|
|
'isolateId': '1',
|
|
}
|
|
);
|
|
|
|
const FakeVmServiceRequest evictShader = FakeVmServiceRequest(
|
|
method: 'ext.ui.window.reinitializeShader',
|
|
args: <String, Object>{
|
|
'assetKey': 'foo.frag',
|
|
'isolateId': '1',
|
|
}
|
|
);
|
|
|
|
final Uri testUri = Uri.parse('foo://bar');
|
|
|
|
// This implements [dds.DartDevelopmentService], not the [DartDevelopmentService]
|
|
// interface from package:flutter_tools.
|
|
class FakeDartDevelopmentService extends Fake implements dds.DartDevelopmentService {
|
|
@override
|
|
Future<void> get done => Future<void>.value();
|
|
|
|
@override
|
|
Uri? get uri => null;
|
|
}
|
|
|
|
class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceException {
|
|
FakeDartDevelopmentServiceException({this.message = defaultMessage});
|
|
|
|
@override
|
|
final int errorCode = dds.DartDevelopmentServiceException.existingDdsInstanceError;
|
|
|
|
@override
|
|
final String message;
|
|
static const String defaultMessage = 'A DDS instance is already connected at http://localhost:8181';
|
|
|
|
@override
|
|
Map<String, Object?> toJson() => <String, Object?>{
|
|
'error_code': errorCode,
|
|
'message': message,
|
|
};
|
|
}
|
|
|
|
class TestFlutterDevice extends FlutterDevice {
|
|
TestFlutterDevice(super.device, { Stream<Uri>? vmServiceUris })
|
|
: _vmServiceUris = vmServiceUris, super(buildInfo: BuildInfo.debug, developmentShaderCompiler: const FakeShaderCompiler());
|
|
|
|
final Stream<Uri>? _vmServiceUris;
|
|
|
|
@override
|
|
Stream<Uri> get vmServiceUris => _vmServiceUris!;
|
|
}
|
|
|
|
class ThrowingForwardingFileSystem extends ForwardingFileSystem {
|
|
ThrowingForwardingFileSystem(super.delegate);
|
|
|
|
@override
|
|
File file(dynamic path) {
|
|
if (path == 'foo') {
|
|
throw const FileSystemException();
|
|
}
|
|
return delegate.file(path);
|
|
}
|
|
}
|
|
|
|
class FakeFlutterDevice extends Fake implements FlutterDevice {
|
|
FakeVmServiceHost? Function()? vmServiceHost;
|
|
Uri? testUri;
|
|
UpdateFSReport report = UpdateFSReport(
|
|
success: true,
|
|
invalidatedSourcesCount: 1,
|
|
);
|
|
Exception? reportError;
|
|
Exception? runColdError;
|
|
int runHotCode = 0;
|
|
int runColdCode = 0;
|
|
|
|
@override
|
|
ResidentCompiler? generator;
|
|
|
|
@override
|
|
DevelopmentShaderCompiler get developmentShaderCompiler => const FakeShaderCompiler();
|
|
|
|
@override
|
|
TargetPlatform targetPlatform = TargetPlatform.android;
|
|
|
|
@override
|
|
Stream<Uri?> get vmServiceUris => Stream<Uri?>.value(testUri);
|
|
|
|
@override
|
|
FlutterVmService? get vmService => vmServiceHost?.call()?.vmService;
|
|
|
|
DevFS? fakeDevFS;
|
|
|
|
@override
|
|
DevFS? get devFS => fakeDevFS;
|
|
|
|
@override
|
|
set devFS(DevFS? value) { }
|
|
|
|
@override
|
|
Device? device;
|
|
|
|
@override
|
|
Future<void> stopEchoingDeviceLog() async { }
|
|
|
|
@override
|
|
Future<void> initLogReader() async { }
|
|
|
|
@override
|
|
Future<Uri> setupDevFS(String fsName, Directory rootDirectory) async {
|
|
return testUri!;
|
|
}
|
|
|
|
@override
|
|
Future<int> runHot({required HotRunner hotRunner, String? route}) async {
|
|
return runHotCode;
|
|
}
|
|
|
|
@override
|
|
Future<int> runCold({required ColdRunner coldRunner, String? route}) async {
|
|
if (runColdError != null) {
|
|
throw runColdError!;
|
|
}
|
|
return runColdCode;
|
|
}
|
|
|
|
@override
|
|
Future<void> connect({
|
|
ReloadSources? reloadSources,
|
|
Restart? restart,
|
|
CompileExpression? compileExpression,
|
|
GetSkSLMethod? getSkSLMethod,
|
|
FlutterProject? flutterProject,
|
|
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
|
int? hostVmServicePort,
|
|
int? ddsPort,
|
|
bool disableServiceAuthCodes = false,
|
|
bool enableDds = true,
|
|
bool cacheStartupProfile = false,
|
|
required bool allowExistingDdsInstance,
|
|
bool ipv6 = false,
|
|
}) async { }
|
|
|
|
@override
|
|
Future<UpdateFSReport> updateDevFS({
|
|
required Uri mainUri,
|
|
String? target,
|
|
AssetBundle? bundle,
|
|
bool bundleFirstUpload = false,
|
|
bool bundleDirty = false,
|
|
bool fullRestart = false,
|
|
String? projectRootPath,
|
|
required String pathToReload,
|
|
required String dillOutputPath,
|
|
required List<Uri> invalidatedFiles,
|
|
required PackageConfig packageConfig,
|
|
}) async {
|
|
if (reportError != null) {
|
|
throw reportError!;
|
|
}
|
|
return report;
|
|
}
|
|
|
|
@override
|
|
Future<void> updateReloadStatus(bool wasReloadSuccessful) async { }
|
|
}
|
|
|
|
class FakeDelegateFlutterDevice extends FlutterDevice {
|
|
FakeDelegateFlutterDevice(
|
|
super.device,
|
|
BuildInfo buildInfo,
|
|
ResidentCompiler residentCompiler,
|
|
this.fakeDevFS,
|
|
) : super(buildInfo: buildInfo, generator: residentCompiler, developmentShaderCompiler: const FakeShaderCompiler());
|
|
|
|
@override
|
|
Future<void> connect({
|
|
ReloadSources? reloadSources,
|
|
Restart? restart,
|
|
bool enableDds = true,
|
|
bool cacheStartupProfile = false,
|
|
bool disableServiceAuthCodes = false,
|
|
bool ipv6 = false,
|
|
CompileExpression? compileExpression,
|
|
GetSkSLMethod? getSkSLMethod,
|
|
FlutterProject? flutterProject,
|
|
int? hostVmServicePort,
|
|
int? ddsPort,
|
|
PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
|
|
bool allowExistingDdsInstance = false,
|
|
}) async { }
|
|
|
|
|
|
final DevFS fakeDevFS;
|
|
|
|
@override
|
|
DevFS? get devFS => fakeDevFS;
|
|
|
|
@override
|
|
set devFS(DevFS? value) {}
|
|
}
|
|
|
|
class FakeResidentCompiler extends Fake implements ResidentCompiler {
|
|
CompilerOutput? nextOutput;
|
|
bool didSuppressErrors = false;
|
|
Uri? receivedNativeAssetsYaml;
|
|
bool recompileCalled = false;
|
|
|
|
@override
|
|
Future<CompilerOutput?> recompile(
|
|
Uri mainUri,
|
|
List<Uri>? invalidatedFiles, {
|
|
required String outputPath,
|
|
required PackageConfig packageConfig,
|
|
String? projectRootPath,
|
|
required FileSystem fs,
|
|
bool suppressErrors = false,
|
|
bool checkDartPluginRegistry = false,
|
|
File? dartPluginRegistrant,
|
|
Uri? nativeAssetsYaml,
|
|
}) async {
|
|
recompileCalled = true;
|
|
receivedNativeAssetsYaml = nativeAssetsYaml;
|
|
didSuppressErrors = suppressErrors;
|
|
return nextOutput ?? const CompilerOutput('foo.dill', 0, <Uri>[]);
|
|
}
|
|
|
|
@override
|
|
void accept() { }
|
|
|
|
@override
|
|
void reset() { }
|
|
}
|
|
|
|
class FakeProjectFileInvalidator extends Fake implements ProjectFileInvalidator {
|
|
@override
|
|
Future<InvalidationResult> findInvalidated({
|
|
required DateTime? lastCompiled,
|
|
required List<Uri> urisToMonitor,
|
|
required String packagesPath,
|
|
required PackageConfig packageConfig,
|
|
bool asyncScanning = false,
|
|
}) async {
|
|
return InvalidationResult(
|
|
packageConfig: packageConfig,
|
|
uris: <Uri>[Uri.parse('file:///hello_world/main.dart'),
|
|
]);
|
|
}
|
|
}
|
|
|
|
class FakeDevice extends Fake implements Device {
|
|
FakeDevice({
|
|
String sdkNameAndVersion = 'Android',
|
|
TargetPlatform targetPlatform = TargetPlatform.android_arm,
|
|
bool isLocalEmulator = false,
|
|
this.supportsHotRestart = true,
|
|
this.supportsScreenshot = true,
|
|
this.supportsFlutterExit = true,
|
|
}) : _isLocalEmulator = isLocalEmulator,
|
|
_targetPlatform = targetPlatform,
|
|
_sdkNameAndVersion = sdkNameAndVersion;
|
|
|
|
final bool _isLocalEmulator;
|
|
final TargetPlatform _targetPlatform;
|
|
final String _sdkNameAndVersion;
|
|
|
|
bool disposed = false;
|
|
bool appStopped = false;
|
|
bool failScreenshot = false;
|
|
|
|
@override
|
|
bool supportsHotRestart;
|
|
|
|
@override
|
|
bool supportsScreenshot;
|
|
|
|
@override
|
|
bool supportsFlutterExit;
|
|
|
|
@override
|
|
PlatformType get platformType => _targetPlatform == TargetPlatform.web_javascript
|
|
? PlatformType.web
|
|
: PlatformType.android;
|
|
|
|
@override
|
|
Future<String> get sdkNameAndVersion async => _sdkNameAndVersion;
|
|
|
|
@override
|
|
Future<TargetPlatform> get targetPlatform async => _targetPlatform;
|
|
|
|
@override
|
|
Future<bool> get isLocalEmulator async => _isLocalEmulator;
|
|
|
|
@override
|
|
String get name => 'FakeDevice';
|
|
|
|
@override
|
|
late DartDevelopmentService dds;
|
|
|
|
@override
|
|
Future<void> dispose() async {
|
|
disposed = true;
|
|
}
|
|
|
|
@override
|
|
Future<bool> stopApp(ApplicationPackage? app, {String? userIdentifier}) async {
|
|
appStopped = true;
|
|
return true;
|
|
}
|
|
|
|
@override
|
|
Future<void> takeScreenshot(File outputFile) async {
|
|
if (failScreenshot) {
|
|
throw Exception();
|
|
}
|
|
outputFile.writeAsBytesSync(List<int>.generate(1024, (int i) => i));
|
|
}
|
|
|
|
@override
|
|
FutureOr<DeviceLogReader> getLogReader({
|
|
ApplicationPackage? app,
|
|
bool includePastLogs = false,
|
|
}) => NoOpDeviceLogReader(name);
|
|
|
|
@override
|
|
DevicePortForwarder portForwarder = const NoOpDevicePortForwarder();
|
|
}
|
|
|
|
class FakeDevFS extends Fake implements DevFS {
|
|
@override
|
|
DateTime? lastCompiled = DateTime(2000);
|
|
|
|
@override
|
|
PackageConfig? lastPackageConfig = PackageConfig.empty;
|
|
|
|
@override
|
|
List<Uri> sources = <Uri>[];
|
|
|
|
@override
|
|
Uri baseUri = Uri();
|
|
|
|
@override
|
|
Future<void> destroy() async { }
|
|
|
|
@override
|
|
Set<String> assetPathsToEvict = <String>{};
|
|
|
|
@override
|
|
Set<String> shaderPathsToEvict = <String>{};
|
|
|
|
@override
|
|
Set<String> scenePathsToEvict = <String>{};
|
|
|
|
@override
|
|
bool didUpdateFontManifest = false;
|
|
|
|
UpdateFSReport nextUpdateReport = UpdateFSReport(success: true);
|
|
|
|
@override
|
|
bool hasSetAssetDirectory = false;
|
|
|
|
@override
|
|
Future<Uri> create() async {
|
|
return Uri();
|
|
}
|
|
|
|
@override
|
|
void resetLastCompiled() {
|
|
lastCompiled = null;
|
|
}
|
|
|
|
@override
|
|
Future<UpdateFSReport> update({
|
|
required Uri mainUri,
|
|
required ResidentCompiler generator,
|
|
required bool trackWidgetCreation,
|
|
required String pathToReload,
|
|
required List<Uri> invalidatedFiles,
|
|
required PackageConfig packageConfig,
|
|
required String dillOutputPath,
|
|
required DevelopmentShaderCompiler shaderCompiler,
|
|
DevelopmentSceneImporter? sceneImporter,
|
|
DevFSWriter? devFSWriter,
|
|
String? target,
|
|
AssetBundle? bundle,
|
|
bool bundleFirstUpload = false,
|
|
bool fullRestart = false,
|
|
String? projectRootPath,
|
|
File? dartPluginRegistrant,
|
|
}) async {
|
|
return nextUpdateReport;
|
|
}
|
|
}
|
|
|
|
class FakeShaderCompiler implements DevelopmentShaderCompiler {
|
|
const FakeShaderCompiler();
|
|
|
|
@override
|
|
void configureCompiler(TargetPlatform? platform) { }
|
|
|
|
@override
|
|
Future<DevFSContent> recompileShader(DevFSContent inputShader) {
|
|
throw UnimplementedError();
|
|
}
|
|
}
|