Skip to content

Commit

Permalink
Run and record adb shell screenrecord during Android scenario app (f…
Browse files Browse the repository at this point in the history
…lutter#51832)

More grasping at straws to solve flutter/flutter#145988.

At some point this could be moved to `--verbose` if it isn't useful.

This will automatically be copied into `${FLUTTER_LOGS_DIR}`, yay!

Example:

https://github.com/flutter/engine/assets/168174/c8caca7a-88ec-4d09-88bd-ebfc531f6512
  • Loading branch information
matanlurey authored Apr 1, 2024
1 parent 6c8558f commit b03b80e
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
78 changes: 77 additions & 1 deletion testing/scenario_app/bin/run_android_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ void main(List<String> args) async {
ndkStack: options.ndkStack,
forceSurfaceProducerSurfaceTexture: options.forceSurfaceProducerSurfaceTexture,
prefixLogsPerRun: options.prefixLogsPerRun,
recordScreen: options.recordScreen,
);
onSigint.cancel();
exit(0);
Expand Down Expand Up @@ -135,6 +136,7 @@ Future<void> _run({
required String ndkStack,
required bool forceSurfaceProducerSurfaceTexture,
required bool prefixLogsPerRun,
required bool recordScreen,
}) async {
const ProcessManager pm = LocalProcessManager();
final String scenarioAppPath = join(outDir.path, 'scenario_app');
Expand Down Expand Up @@ -230,6 +232,7 @@ Future<void> _run({
late Process logcatProcess;
late Future<int> logcatProcessExitCode;
_ImpellerBackend? actualImpellerBackend;
Process? screenRecordProcess;

final IOSink logcat = File(logcatPath).openWrite();
try {
Expand Down Expand Up @@ -361,14 +364,44 @@ Future<void> _run({
}
});

if (recordScreen) {
await step('Recording screen...', () async {
// Create a /tmp directory on the device to store the screen recording.
final int exitCode = await pm.runAndForward(<String>[
adb.path,
'shell',
'mkdir',
'-p',
join(_emulatorStoragePath, 'tmp'),
]);
if (exitCode != 0) {
panic(<String>['could not create /tmp directory on device']);
}
final String screenRecordingPath = join(
_emulatorStoragePath,
'tmp',
'screen.mp4',
);
screenRecordProcess = await pm.start(<String>[
adb.path,
'shell',
'screenrecord',
'--time-limit=0',
'--bugreport',
screenRecordingPath,
]);
log('writing screen recording to $screenRecordingPath');
});
}

await step('Running instrumented tests...', () async {
final (int exitCode, StringBuffer out) = await pm.runAndCapture(<String>[
adb.path,
'shell',
'am',
'instrument',
'-w',
'--no-window-animation',
'--no-window-animation',
if (smokeTestFullPath != null)
'-e class $smokeTestFullPath',
if (enableImpeller)
Expand Down Expand Up @@ -447,6 +480,47 @@ Future<void> _run({
}
});

if (screenRecordProcess != null) {
await step('Killing screen recording process...', () async {
// Kill the screen recording process.
screenRecordProcess!.kill(ProcessSignal.sigkill);
await screenRecordProcess!.exitCode;

// Pull the screen recording from the device.
final String screenRecordingPath = join(
_emulatorStoragePath,
'tmp',
'screen.mp4',
);
final String screenRecordingLocalPath = join(
logsDir.path,
'screen.mp4',
);
final int exitCode = await pm.runAndForward(<String>[
adb.path,
'pull',
screenRecordingPath,
screenRecordingLocalPath,
]);
if (exitCode != 0) {
logError('could not pull screen recording from device');
}

log('wrote screen recording to $screenRecordingLocalPath');

// Remove the screen recording from the device.
final int removeExitCode = await pm.runAndForward(<String>[
adb.path,
'shell',
'rm',
screenRecordingPath,
]);
if (removeExitCode != 0) {
logError('could not remove screen recording from device');
}
});
}

await step('Killing logcat process...', () async {
final bool delivered = logcatProcess.kill(ProcessSignal.sigkill);
assert(delivered);
Expand Down Expand Up @@ -536,6 +610,8 @@ Future<void> _run({
}
}

const String _emulatorStoragePath = '/storage/emulated/0/Download';

void _withTemporaryCwd(String path, void Function() callback) {
final String originalCwd = Directory.current.path;
Directory.current = Directory(path).path;
Expand Down
8 changes: 8 additions & 0 deletions testing/scenario_app/bin/utils/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ extension type const Options._(ArgResults _args) {
defaultsTo: environment.isCi,
hide: hideUnusualOptions,
)
..addFlag(
'record-screen',
help: 'Whether to record the screen during the test run.',
defaultsTo: environment.isCi,
)
..addOption(
'impeller-backend',
help: 'The graphics backend to use when --enable-impeller is true. '
Expand Down Expand Up @@ -286,6 +291,9 @@ extension type const Options._(ArgResults _args) {
/// Whether to enable Impeller as the graphics backend.
bool get enableImpeller => _args['enable-impeller'] as bool;

/// Whether to record the screen during the test run.
bool get recordScreen => _args['record-screen'] as bool;

/// The graphics backend to use when --enable-impeller is true.
String get impellerBackend => _args['impeller-backend'] as String;

Expand Down

0 comments on commit b03b80e

Please sign in to comment.