[scenarios] Use adb to take screenshot, block on screenshot operation. (flutter/engine#51879)

Use the screenshotUtil signal to have the runner take a screenshot with adb. Block the screenshotter until this has completed.
This commit is contained in:
Jonah Williams 2024-04-03 15:11:22 -07:00 committed by GitHub
parent 4059931118
commit b951d15850
2 changed files with 42 additions and 32 deletions

View File

@ -4,15 +4,14 @@
package dev.flutter.scenariosui;
import android.graphics.Bitmap;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import dev.flutter.scenarios.TestableFlutterActivity;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@ -30,24 +29,28 @@ public class ScreenshotUtil {
private static class Connection {
final Socket clientSocket;
final OutputStream out;
final InputStream in;
Connection(Socket socket) throws IOException {
clientSocket = socket;
out = socket.getOutputStream();
in = socket.getInputStream();
}
synchronized void writeFile(String name, byte[] fileContent, int pixelCount)
throws IOException {
final ByteBuffer buffer = ByteBuffer.allocate(name.length() + fileContent.length + 12);
synchronized void writeFile(String name) throws IOException {
final ByteBuffer buffer = ByteBuffer.allocate(name.length() + 12);
// See ScreenshotBlobTransformer#bind in screenshot_transformer.dart for consumer side.
buffer.putInt(name.length());
buffer.putInt(fileContent.length);
buffer.putInt(pixelCount);
buffer.putInt(0);
buffer.putInt(0);
buffer.put(name.getBytes());
buffer.put(fileContent);
final byte[] bytes = buffer.array();
out.write(bytes, 0, bytes.length);
out.flush();
// Wait on run_android_tests.dart to write a single byte into the socket
// as a signal that adb screencapture has completed.
in.read();
}
synchronized void close() throws IOException {
@ -95,14 +98,16 @@ public class ScreenshotUtil {
* @param fileContent The file content.
*/
public static synchronized void writeFile(
@NonNull String filename, @NonNull byte[] fileContent, int pixelCount) {
@NonNull String filename, @NonNull CountDownLatch latch) {
if (executor != null && conn != null) {
executor.execute(
() -> {
try {
conn.writeFile(filename, fileContent, pixelCount);
conn.writeFile(filename);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
latch.countDown();
}
});
}
@ -119,16 +124,9 @@ public class ScreenshotUtil {
*/
public static void capture(@NonNull TestableFlutterActivity activity, @NonNull String captureName)
throws Exception {
CountDownLatch latch = new CountDownLatch(1);
activity.waitUntilFlutterRendered();
final Bitmap bitmap =
InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
if (bitmap == null) {
throw new RuntimeException("failed to capture screenshot");
}
int pixelCount = bitmap.getWidth() * bitmap.getHeight();
final ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
ScreenshotUtil.writeFile(captureName, out.toByteArray(), pixelCount);
ScreenshotUtil.writeFile(captureName, latch);
latch.await();
}
}

View File

@ -5,7 +5,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:dir_contents_diff/dir_contents_diff.dart' show dirContentsDiff;
import 'package:engine_repo_tools/engine_repo_tools.dart';
@ -191,19 +190,32 @@ Future<void> _run({
stdout.writeln('client connected ${client.remoteAddress.address}:${client.remotePort}');
}
pendingConnections.add(client);
client.transform(const ScreenshotBlobTransformer()).listen((Screenshot screenshot) {
client.transform(const ScreenshotBlobTransformer()).listen((Screenshot screenshot) async {
final String fileName = screenshot.filename;
final Uint8List fileContent = screenshot.fileContent;
if (verbose) {
log('host received ${fileContent.lengthInBytes} bytes for screenshot `$fileName`');
final String filePath = join(screenshotPath, fileName);
{
const String remotePath = '/data/local/tmp/flutter_screenshot.png';
ProcessResult result = await pm.run(<String>['adb', 'shell', 'screencap', '-p', remotePath]);
if (result.exitCode != 0) {
panic(<String>['Failed to capture screenshot']);
}
result = await pm.run(
<String>['adb', 'pull', remotePath, filePath],
);
if (result.exitCode != 0) {
panic(<String>['Failed to pull screenshot']);
}
result = await pm.run(<String>['adb', 'shell', 'rm', remotePath]);
if (result.exitCode != 0) {
stderr.writeln('Warning: failed to delete old screenshot on device.');
}
}
// Write a single byte into the socket as a signal to ScreenshotUtil.java
// that the screenshot was taken.
client.write(0x8);
assert(skiaGoldClient != null, 'expected Skia Gold client');
late File goldenFile;
try {
goldenFile = File(join(screenshotPath, fileName))..writeAsBytesSync(fileContent, flush: true);
} on FileSystemException catch (err) {
panic(<String>['failed to create screenshot $fileName: $err']);
}
final File goldenFile = File(filePath);
if (verbose) {
log('wrote ${goldenFile.absolute.path}');
}