[flutter_tools] support all engine debugging options with FLUTTER_ENGINE_SWITCH environment variables (#67150)

Allow providing all debugging options to the desktop engine via the FLUTTER_ENGINE_SWITCH_ environment variables.

Fixes #66532
Fixes #46005
Fixes #58882

The underling engine changes have already landed for Windows, macOS, but linux is still in progress
This commit is contained in:
Jonah Williams 2020-10-05 09:56:48 -07:00 committed by GitHub
parent 4ce2a7aa6d
commit 21bb29cc68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 207 additions and 8 deletions

View file

@ -111,8 +111,8 @@ abstract class DesktopDevice extends Device {
ApplicationPackage package, {
String mainPath,
String route,
DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs,
@required DebuggingOptions debuggingOptions,
Map<String, dynamic> platformArgs = const <String, dynamic>{},
bool prebuiltApplication = false,
bool ipv6 = false,
String userIdentifier,
@ -120,13 +120,14 @@ abstract class DesktopDevice extends Device {
if (!prebuiltApplication) {
await buildForDevice(
package,
buildInfo: debuggingOptions?.buildInfo,
buildInfo: debuggingOptions.buildInfo,
mainPath: mainPath,
);
}
// Ensure that the executable is locatable.
final BuildMode buildMode = debuggingOptions?.buildInfo?.mode;
final bool traceStartup = platformArgs['trace-startup'] as bool ?? false;
final String executable = executablePathForDevice(package, buildMode);
if (executable == null) {
_logger.printError('Unable to find executable to run');
@ -137,6 +138,7 @@ abstract class DesktopDevice extends Device {
<String>[
executable,
],
environment: _computeEnvironment(debuggingOptions, traceStartup, route),
);
_runningProcesses.add(process);
unawaited(process.exitCode.then((_) => _runningProcesses.remove(process)));
@ -202,6 +204,92 @@ abstract class DesktopDevice extends Device {
/// Called after a process is attached, allowing any device-specific extra
/// steps to be run.
void onAttached(ApplicationPackage package, BuildMode buildMode, Process process) {}
/// Computes a set of environment variables used to pass debugging information
/// to the engine without interfering with application level command line
/// arguments.
///
/// The format of the environment variables is:
/// * FLUTTER_ENGINE_SWITCHES to the number of switches.
/// * FLUTTER_ENGINE_SWITCH_<N> (indexing from 1) to the individual switches.
Map<String, String> _computeEnvironment(DebuggingOptions debuggingOptions, bool traceStartup, String route) {
int flags = 0;
final Map<String, String> environment = <String, String>{};
void addFlag(String value) {
flags += 1;
environment['FLUTTER_ENGINE_SWITCH_$flags'] = value;
}
void finish() {
environment['FLUTTER_ENGINE_SWITCHES'] = flags.toString();
}
addFlag('enable-dart-profiling=true');
addFlag('enable-background-compilation=true');
if (traceStartup) {
addFlag('trace-startup=true');
}
if (route != null) {
addFlag('route=$route');
}
if (debuggingOptions.enableSoftwareRendering) {
addFlag('enable-software-rendering=true');
}
if (debuggingOptions.skiaDeterministicRendering) {
addFlag('skia-deterministic-rendering=true');
}
if (debuggingOptions.traceSkia) {
addFlag('trace-skia=true');
}
if (debuggingOptions.traceAllowlist != null) {
addFlag('trace-allowlist=${debuggingOptions.traceAllowlist}');
}
if (debuggingOptions.traceSystrace) {
addFlag('trace-systrace=true');
}
if (debuggingOptions.endlessTraceBuffer) {
addFlag('endless-trace-buffer=true');
}
if (debuggingOptions.dumpSkpOnShaderCompilation) {
addFlag('dump-skp-on-shader-compilation=true');
}
if (debuggingOptions.cacheSkSL) {
addFlag('cache-sksl=true');
}
if (debuggingOptions.purgePersistentCache) {
addFlag('purge-persistent-cache=true');
}
// Options only supported when there is a VM Service connection between the
// tool and the device, usually in debug or profile mode.
if (debuggingOptions.debuggingEnabled) {
if (debuggingOptions.deviceVmServicePort != null) {
addFlag('observatory-port=${debuggingOptions.deviceVmServicePort}');
}
if (debuggingOptions.buildInfo.isDebug) {
addFlag('enable-checked-mode=true');
addFlag('verify-entry-points=true');
}
if (debuggingOptions.startPaused) {
addFlag('start-paused=true');
}
if (debuggingOptions.disableServiceAuthCodes) {
addFlag('disable-service-auth-codes=true');
}
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
if (dartVmFlags.isNotEmpty) {
addFlag('dart-flags=$dartVmFlags');
}
if (debuggingOptions.useTestFonts) {
addFlag('use-test-fonts=true');
}
if (debuggingOptions.verboseSystemLogs) {
addFlag('verbose-logging=true');
}
}
finish();
return environment;
}
}
/// A log reader for desktop applications that delegates to a [Process] stdout

View file

@ -80,7 +80,7 @@ void main() {
final Completer<void> completer = Completer<void>();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(
command: const <String>['null'],
command: const <String>['debug'],
stdout: 'Observatory listening on http://127.0.0.1/0\n',
completer: completer,
),
@ -89,7 +89,11 @@ void main() {
final String executableName = device.executablePathForDevice(null, BuildMode.debug);
fileSystem.file(executableName).writeAsStringSync('\n');
final FakeAppplicationPackage package = FakeAppplicationPackage();
final LaunchResult result = await device.startApp(package, prebuiltApplication: true);
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
);
expect(result.started, true);
expect(result.observatoryUri, Uri.parse('http://127.0.0.1/0'));
@ -99,7 +103,11 @@ void main() {
final BufferLogger logger = BufferLogger.test();
final DesktopDevice device = setUpDesktopDevice(nullExecutablePathForDevice: true, logger: logger);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final LaunchResult result = await device.startApp(package, prebuiltApplication: true);
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
);
expect(result.started, false);
expect(logger.errorText, contains('Unable to find executable to run'));
@ -109,20 +117,123 @@ void main() {
final Completer<void> completer = Completer<void>();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(
command: const <String>['null'],
command: const <String>['debug'],
stdout: 'Observatory listening on http://127.0.0.1/0\n',
completer: completer,
),
]);
final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final LaunchResult result = await device.startApp(package, prebuiltApplication: true);
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
);
expect(result.started, true);
expect(await device.stopApp(package), true);
});
});
testWithoutContext('startApp supports DebuggingOptions through FLUTTER_ENGINE_SWITCH environment variables', () async {
final Completer<void> completer = Completer<void>();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(
command: const <String>['debug'],
stdout: 'Observatory listening on http://127.0.0.1/0\n',
completer: completer,
environment: const <String, String>{
'FLUTTER_ENGINE_SWITCH_1': 'enable-dart-profiling=true',
'FLUTTER_ENGINE_SWITCH_2': 'enable-background-compilation=true',
'FLUTTER_ENGINE_SWITCH_3': 'trace-startup=true',
'FLUTTER_ENGINE_SWITCH_4': 'enable-software-rendering=true',
'FLUTTER_ENGINE_SWITCH_5': 'skia-deterministic-rendering=true',
'FLUTTER_ENGINE_SWITCH_6': 'trace-skia=true',
'FLUTTER_ENGINE_SWITCH_7': 'trace-allowlist=foo,bar',
'FLUTTER_ENGINE_SWITCH_8': 'trace-systrace=true',
'FLUTTER_ENGINE_SWITCH_9': 'endless-trace-buffer=true',
'FLUTTER_ENGINE_SWITCH_10': 'dump-skp-on-shader-compilation=true',
'FLUTTER_ENGINE_SWITCH_11': 'cache-sksl=true',
'FLUTTER_ENGINE_SWITCH_12': 'purge-persistent-cache=true',
'FLUTTER_ENGINE_SWITCH_13': 'enable-checked-mode=true',
'FLUTTER_ENGINE_SWITCH_14': 'verify-entry-points=true',
'FLUTTER_ENGINE_SWITCH_15': 'start-paused=true',
'FLUTTER_ENGINE_SWITCH_16': 'disable-service-auth-codes=true',
'FLUTTER_ENGINE_SWITCH_17': 'dart-flags=--null_assertions',
'FLUTTER_ENGINE_SWITCH_18': 'use-test-fonts=true',
'FLUTTER_ENGINE_SWITCH_19': 'verbose-logging=true',
'FLUTTER_ENGINE_SWITCHES': '19'
}
),
]);
final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
platformArgs: <String, Object>{
'trace-startup': true,
},
debuggingOptions: DebuggingOptions.enabled(
BuildInfo.debug,
startPaused: true,
disableServiceAuthCodes: true,
dartFlags: '',
enableSoftwareRendering: true,
skiaDeterministicRendering: true,
traceSkia: true,
traceAllowlist: 'foo,bar',
traceSystrace: true,
endlessTraceBuffer: true,
dumpSkpOnShaderCompilation: true,
cacheSkSL: true,
purgePersistentCache: true,
useTestFonts: true,
verboseSystemLogs: true,
initializePlatform: true,
nullAssertions: true,
),
);
expect(result.started, true);
});
testWithoutContext('startApp supports DebuggingOptions through FLUTTER_ENGINE_SWITCH environment variables when debugging is disabled', () async {
final Completer<void> completer = Completer<void>();
final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(
command: const <String>['debug'],
stdout: 'Observatory listening on http://127.0.0.1/0\n',
completer: completer,
environment: const <String, String>{
'FLUTTER_ENGINE_SWITCH_1': 'enable-dart-profiling=true',
'FLUTTER_ENGINE_SWITCH_2': 'enable-background-compilation=true',
'FLUTTER_ENGINE_SWITCH_3': 'trace-startup=true',
'FLUTTER_ENGINE_SWITCH_4': 'trace-allowlist=foo,bar',
'FLUTTER_ENGINE_SWITCH_5': 'cache-sksl=true',
'FLUTTER_ENGINE_SWITCHES': '5'
}
),
]);
final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager);
final FakeAppplicationPackage package = FakeAppplicationPackage();
final LaunchResult result = await device.startApp(
package,
prebuiltApplication: true,
platformArgs: <String, Object>{
'trace-startup': true,
},
debuggingOptions: DebuggingOptions.disabled(
BuildInfo.debug,
traceAllowlist: 'foo,bar',
cacheSkSL: true,
initializePlatform: true,
),
);
expect(result.started, true);
});
testWithoutContext('Port forwarder is a no-op', () async {
final FakeDesktopDevice device = setUpDesktopDevice();
final DevicePortForwarder portForwarder = device.portForwarder;