Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ allowed_hosts = [
]

deps = {
'src': 'https://github.com/flutter/buildroot.git' + '@' + 'c26173f545880557c36e8fff8b7b6b5c4385c931',
'src': 'https://github.com/flutter/buildroot.git' + '@' + 'b6c4d42a35088b73125c5d589441b6357d5e91a8',

# Fuchsia compatibility
#
Expand Down
5 changes: 4 additions & 1 deletion lib/web_ui/dev/browser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ abstract class BrowserEnvironment {
/// browser in debug mode by pausing test execution after the code is loaded
/// but before calling the `main()` function of the test, giving the
/// developer a chance to set breakpoints.
Future<Browser> launchBrowserInstance(Uri url, {bool debug = false});
Future<Browser> launchBrowserInstance(
Uri url, {
bool debug = false,
});
}

/// An interface for running browser instances.
Expand Down
19 changes: 18 additions & 1 deletion lib/web_ui/dev/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:path/path.dart' as path;
import 'package:watcher/src/watch_event.dart';

import 'environment.dart';
import 'exceptions.dart';
import 'pipeline.dart';
import 'utils.dart';

Expand All @@ -17,7 +18,7 @@ const Map<String, String> targetAliases = <String, String>{
'web_sdk': 'flutter/web_sdk',
'canvaskit': 'flutter/third_party/canvaskit:canvaskit_group',
'canvaskit_chromium': 'flutter/third_party/canvaskit:canvaskit_chromium_group',
'skwasm': 'flutter/lib/web_ui/skwasm',
'skwasm': 'flutter/third_party/canvaskit:skwasm_group',
'archive': 'flutter/web_sdk:flutter_web_sdk_archive',
};

Expand Down Expand Up @@ -46,6 +47,11 @@ class BuildCommand extends Command<bool> with ArgUtils<bool> {
'output will be located at "out/wasm_debug".\nThis only applies to '
'the wasm build. The host build is always built in release mode.',
);
argParser.addFlag(
'dwarf',
help: 'Embed DWARF debugging info into the output wasm modules. This is '
'only valid in debug mode.',
);
}

@override
Expand All @@ -59,14 +65,19 @@ class BuildCommand extends Command<bool> with ArgUtils<bool> {
bool get host => boolArg('host');

List<String> get targets => argResults?.rest ?? <String>[];
bool get embedDwarf => boolArg('dwarf');

@override
FutureOr<bool> run() async {
if (embedDwarf && runtimeMode != RuntimeMode.debug) {
throw ToolExit('Embedding DWARF data requires debug runtime mode.');
}
final FilePath libPath = FilePath.fromWebUi('lib');
final List<PipelineStep> steps = <PipelineStep>[
GnPipelineStep(
host: host,
runtimeMode: runtimeMode,
embedDwarf: embedDwarf,
),
NinjaPipelineStep(
host: host,
Expand Down Expand Up @@ -99,10 +110,12 @@ class GnPipelineStep extends ProcessStep {
GnPipelineStep({
required this.host,
required this.runtimeMode,
required this.embedDwarf,
});

final bool host;
final RuntimeMode runtimeMode;
final bool embedDwarf;

@override
String get description => 'gn';
Expand All @@ -120,6 +133,10 @@ class GnPipelineStep extends ProcessStep {
return <String>[
'--web',
'--runtime-mode=${runtimeMode.name}',
if (runtimeMode == RuntimeMode.debug)
'--unoptimized',
if (embedDwarf)
'--wasm-use-dwarf',
];
}
}
Expand Down
95 changes: 89 additions & 6 deletions lib/web_ui/dev/chrome.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'dart:io';
import 'dart:math' as math;

import 'package:image/image.dart';
import 'package:path/path.dart' as path;
import 'package:test_api/src/backend/runtime.dart';
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
as wip;
Expand All @@ -21,15 +22,29 @@ import 'environment.dart';

/// Provides an environment for desktop Chrome.
class ChromeEnvironment implements BrowserEnvironment {
ChromeEnvironment(this._enableWasmGC);
ChromeEnvironment({
required bool enableWasmGC,
required bool useDwarf,
}) : _enableWasmGC = enableWasmGC,
_useDwarf = useDwarf;

late final BrowserInstallation _installation;

final bool _enableWasmGC;
final bool _useDwarf;

@override
Future<Browser> launchBrowserInstance(Uri url, {bool debug = false}) async {
return Chrome(url, _installation, debug: debug, enableWasmGC: _enableWasmGC);
Future<Browser> launchBrowserInstance(
Uri url, {
bool debug = false,
}) async {
return Chrome(
url,
_installation,
debug: debug,
enableWasmGC: _enableWasmGC,
useDwarf: _useDwarf
);
}

@override
Expand Down Expand Up @@ -64,7 +79,13 @@ class ChromeEnvironment implements BrowserEnvironment {
class Chrome extends Browser {
/// Starts a new instance of Chrome open to the given [url], which may be a
/// [Uri] or a [String].
factory Chrome(Uri url, BrowserInstallation installation, {required bool debug, required bool enableWasmGC}) {
factory Chrome(
Uri url,
BrowserInstallation installation, {
required bool debug,
required bool enableWasmGC,
required bool useDwarf,
}) {
final Completer<Uri> remoteDebuggerCompleter = Completer<Uri>.sync();
return Chrome._(BrowserProcess(() async {
// A good source of various Chrome CLI options:
Expand All @@ -79,7 +100,7 @@ class Chrome extends Browser {
// --disable-font-subpixel-positioning
final bool isChromeNoSandbox =
Platform.environment['CHROME_NO_SANDBOX'] == 'true';
final String dir = environment.webUiDartToolDir.createTempSync('test_chrome_user_data_').resolveSymbolicLinksSync();
final String dir = await generateUserDirectory(installation, useDwarf);
final String jsFlags = enableWasmGC ? <String>[
'--experimental-wasm-gc',
'--experimental-wasm-stack-switching',
Expand All @@ -101,9 +122,13 @@ class Chrome extends Browser {
'--start-maximized',
if (debug)
'--auto-open-devtools-for-tabs',
if (useDwarf)
'--devtools-flags=enabledExperiments=wasmDWARFDebugging',
// Always run unit tests at a 1x scale factor
'--force-device-scale-factor=1',
'--disable-extensions',
if (!useDwarf)
// DWARF debugging requires a Chrome extension.
'--disable-extensions',
'--disable-popup-blocking',
// Indicates that the browser is in "browse without sign-in" (Guest session) mode.
'--bwsi',
Expand Down Expand Up @@ -137,6 +162,64 @@ class Chrome extends Browser {

Chrome._(this._process, this.remoteDebuggerUrl);

static Future<String> generateUserDirectory(
BrowserInstallation installation,
bool useDwarf
) async {
final String userDirectoryPath = environment
.webUiDartToolDir
.createTempSync('test_chrome_user_data_')
.resolveSymbolicLinksSync();
if (!useDwarf) {
return userDirectoryPath;
}

// Using DWARF debugging info requires installation of a Chrome extension.
// We can prompt for this, but in order to avoid prompting on every single
// browser launch, we cache the user directory after it has been installed.
final Directory baselineUserDirectory = Directory(path.join(
environment.webUiDartToolDir.path,
'chrome_user_data_base',
));
final Directory dwarfExtensionInstallDirectory = Directory(path.join(
baselineUserDirectory.path,
'Default',
'Extensions',
// This is the ID of the dwarf debugging extension.
'pdcpmagijalfljmkmjngeonclgbbannb',
));
if (!baselineUserDirectory.existsSync()) {
baselineUserDirectory.createSync(recursive: true);
}
if (!dwarfExtensionInstallDirectory.existsSync()) {
print('DWARF debugging requested. Launching Chrome. Please install the '
'extension and then exit Chrome when the installation is complete...');
final Process addExtension = await Process.start(
installation.executable,
<String>[
'--user-data-dir=${baselineUserDirectory.path}',
'https://goo.gle/wasm-debugging-extension',
'--bwsi',
'--no-first-run',
'--no-default-browser-check',
'--disable-default-apps',
'--disable-translate',
]
);
await addExtension.exitCode;
}
for (final FileSystemEntity input in baselineUserDirectory.listSync(recursive: true)) {
final String relative = path.relative(input.path, from: baselineUserDirectory.path);
final String outputPath = path.join(userDirectoryPath, relative);
if (input is Directory) {
await Directory(outputPath).create(recursive: true);
} else if (input is File) {
await input.copy(outputPath);
}
}
return userDirectoryPath;
}

final BrowserProcess _process;

@override
Expand Down
8 changes: 6 additions & 2 deletions lib/web_ui/dev/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,14 @@ const List<String> kAllBrowserNames = <String>[
/// Creates an environment for a browser.
///
/// The [browserName] matches the browser name passed as the `--browser` option.
BrowserEnvironment getBrowserEnvironment(BrowserName browserName, { required bool enableWasmGC }) {
BrowserEnvironment getBrowserEnvironment(
BrowserName browserName, {
required bool enableWasmGC,
required bool useDwarf,
}) {
switch (browserName) {
case BrowserName.chrome:
return ChromeEnvironment(enableWasmGC);
return ChromeEnvironment(enableWasmGC: enableWasmGC, useDwarf: useDwarf);
case BrowserName.edge:
return EdgeEnvironment();
case BrowserName.firefox:
Expand Down
10 changes: 5 additions & 5 deletions lib/web_ui/dev/environment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class Environment {
io.Directory(pathlib.join(outDir.path, 'wasm_release'));
final io.Directory wasmProfileOutDir =
io.Directory(pathlib.join(outDir.path, 'wasm_profile'));
final io.Directory wasmDebugOutDir =
io.Directory(pathlib.join(outDir.path, 'wasm_debug'));
final io.Directory wasmDebugUnoptOutDir =
io.Directory(pathlib.join(outDir.path, 'wasm_debug_unopt'));
final io.Directory hostDebugUnoptDir =
io.Directory(pathlib.join(outDir.path, 'host_debug_unopt'));
final io.Directory dartSdkDir = dartExecutable.parent.parent;
Expand All @@ -59,7 +59,7 @@ class Environment {
outDir: outDir,
wasmReleaseOutDir: wasmReleaseOutDir,
wasmProfileOutDir: wasmProfileOutDir,
wasmDebugOutDir: wasmDebugOutDir,
wasmDebugUnoptOutDir: wasmDebugUnoptOutDir,
hostDebugUnoptDir: hostDebugUnoptDir,
dartSdkDir: dartSdkDir,
);
Expand All @@ -74,7 +74,7 @@ class Environment {
required this.outDir,
required this.wasmReleaseOutDir,
required this.wasmProfileOutDir,
required this.wasmDebugOutDir,
required this.wasmDebugUnoptOutDir,
required this.hostDebugUnoptDir,
required this.dartSdkDir,
});
Expand Down Expand Up @@ -108,7 +108,7 @@ class Environment {
final io.Directory wasmProfileOutDir;

/// The output directory for the wasm_debug build.
final io.Directory wasmDebugOutDir;
final io.Directory wasmDebugUnoptOutDir;

/// The output directory for the host_debug_unopt build.
final io.Directory hostDebugUnoptDir;
Expand Down
21 changes: 20 additions & 1 deletion lib/web_ui/dev/steps/copy_artifacts_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class CopyArtifactsStep implements PipelineStep {
for (final String filename in <String>[
'canvaskit.js',
'canvaskit.wasm',
'canvaskit.wasm.map',
]) {
final io.File sourceFile = io.File(pathlib.join(
sourceDirectoryPath,
Expand All @@ -160,7 +161,13 @@ class CopyArtifactsStep implements PipelineStep {
filename,
));
if (!sourceFile.existsSync()) {
throw ToolExit('Built CanvasKit artifact not found at path "$sourceFile".');
if (filename.endsWith('.map')) {
// Sourcemaps are only generated under certain build conditions, so
// they are optional.
continue;
} {
throw ToolExit('Built CanvasKit artifact not found at path "$sourceFile".');
}
}
await targetFile.create(recursive: true);
await sourceFile.copy(targetFile.path);
Expand All @@ -179,13 +186,25 @@ class CopyArtifactsStep implements PipelineStep {

for (final String fileName in <String>[
'skwasm.wasm',
'skwasm.wasm.map',
'skwasm.js',
'skwasm.worker.js',
]) {
final io.File sourceFile = io.File(pathlib.join(
outBuildPath,
'flutter_web_sdk',
'canvaskit',
fileName,
));
if (!sourceFile.existsSync()) {
if (fileName.endsWith('.map')) {
// Sourcemaps are only generated under certain build conditions, so
// they are optional.
continue;
} {
throw ToolExit('Built Skwasm artifact not found at path "$sourceFile".');
}
}
final io.File targetFile = io.File(pathlib.join(
targetDir.path,
fileName,
Expand Down
9 changes: 6 additions & 3 deletions lib/web_ui/dev/steps/run_suite_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ class RunSuiteStep implements PipelineStep {
required this.isVerbose,
required this.doUpdateScreenshotGoldens,
required this.requireSkiaGold,
this.testFiles,
required this.overridePathToCanvasKit,
required this.useDwarf,
this.testFiles,
});

final TestSuite suite;
Expand All @@ -43,6 +44,7 @@ class RunSuiteStep implements PipelineStep {
final bool isVerbose;
final bool doUpdateScreenshotGoldens;
final String? overridePathToCanvasKit;
final bool useDwarf;

/// Require Skia Gold to be available and reachable.
final bool requireSkiaGold;
Expand All @@ -63,7 +65,9 @@ class RunSuiteStep implements PipelineStep {
_prepareTestResultsDirectory();
final BrowserEnvironment browserEnvironment = getBrowserEnvironment(
suite.runConfig.browser,
enableWasmGC: isWasm);
enableWasmGC: isWasm,
useDwarf: useDwarf,
);
await browserEnvironment.prepare();

final SkiaGoldClient? skiaClient = await _createSkiaClient();
Expand Down Expand Up @@ -93,7 +97,6 @@ class RunSuiteStep implements PipelineStep {
doUpdateScreenshotGoldens: doUpdateScreenshotGoldens,
skiaClient: skiaClient,
overridePathToCanvasKit: overridePathToCanvasKit,
isWasm: isWasm,
isVerbose: isVerbose,
);
});
Expand Down
Loading