[Fix] (ci): harden Android trace replay CI

This commit is contained in:
2026-06-21 00:07:13 +08:00
parent b4f9401395
commit f270988e03
2 changed files with 75 additions and 16 deletions
@@ -4,7 +4,9 @@
#include <android/native_window_jni.h>
#include <jni.h>
#include <exception>
#include <string>
#include <sys/stat.h>
extern "C" void mobilegl_trace_set_native_window(ANativeWindow *window);
extern "C" void mobilegl_trace_set_requested_size(int width, int height);
@@ -46,6 +48,35 @@ jobject MakeResult(JNIEnv* env, const mobilegl_trace::Result& result) {
return object;
}
void EnsureDirectory(const std::string& path) {
if (!path.empty()) {
mkdir(path.c_str(), 0775);
}
}
mobilegl_trace::Result MakeFailureResult(const mobilegl_trace::Request& request,
int statusCode,
const std::string& message) {
mobilegl_trace::Result result;
result.statusCode = statusCode;
result.message = message;
if (!request.outputDir.empty()) {
EnsureDirectory(request.outputDir);
result.resultPath = request.outputDir + "/result.json";
result.actualPath = request.outputDir + "/actual.png";
}
result.diffPath = request.diffPath;
return result;
}
class ScopedTraceReplayState {
public:
~ScopedTraceReplayState() {
mobilegl_trace_set_native_window(nullptr);
mobilegl_trace_set_requested_size(0, 0);
}
};
} // namespace
extern "C" JNIEXPORT jobject JNICALL
@@ -89,6 +120,7 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv*
request.cropHeight = cropHeight;
request.fuzzPercent = fuzzPercent;
ScopedTraceReplayState replayState;
mobilegl_trace_set_requested_size(request.width, request.height);
const bool needsNativeWindow = request.backend == "DirectVulkan";
ANativeWindow *window = needsNativeWindow && surface != nullptr ? ANativeWindow_fromSurface(env, surface) : nullptr;
@@ -97,9 +129,19 @@ Java_top_mobilegl_plugin_trace_TraceReplayActivity_nativeRunTraceReplay(JNIEnv*
ANativeWindow_release(window);
}
mobilegl_trace::Result result = mobilegl_trace::RunTraceReplay(request);
mobilegl_trace_set_native_window(nullptr);
mobilegl_trace_set_requested_size(0, 0);
mobilegl_trace::Result result;
try {
result = mobilegl_trace::RunTraceReplay(request);
} catch (const std::exception& exception) {
result = MakeFailureResult(request,
mobilegl_trace::STATUS_RETRACE_FAILED,
"trace replay failed with unhandled native exception: " +
std::string(exception.what()));
} catch (...) {
result = MakeFailureResult(request,
mobilegl_trace::STATUS_RETRACE_FAILED,
"trace replay failed with unknown native exception");
}
if (!result.resultPath.empty()) {
mobilegl_trace::WriteResultJson(request, result);
}
+30 -13
View File
@@ -136,6 +136,17 @@ if [ -n "${alternate_golden_path}" ]; then
fi
safe_case="$(printf '%s' "${case_name}" | sed 's/[^A-Za-z0-9._-]/_/g')"
app_dir="/data/user/0/${package_name}/files/trace-replay"
collect_run_diagnostics() {
diagnostics_dir="$1"
mkdir -p "${diagnostics_dir}"
"${ADB}" logcat -d -t 2000 > "${diagnostics_dir}/logcat.txt" || true
"${ADB}" shell pidof "${package_name}" > "${diagnostics_dir}/pidof.txt" 2>&1 || true
"${ADB}" shell dumpsys activity activities > "${diagnostics_dir}/activity.txt" 2>&1 || true
"${ADB}" shell run-as "${package_name}" ls -laR "${app_dir}" > "${diagnostics_dir}/app-files.txt" 2>&1 || true
"${ADB}" exec-out run-as "${package_name}" cat "${app_dir}/output/retrace.log" > "${diagnostics_dir}/retrace.log" || true
}
prepare_fixture() {
fixture_dir="${fixture_root}/${safe_case}"
@@ -162,17 +173,16 @@ copy_fixture_to_app() {
golden_tmp="/data/local/tmp/mobilegl-${safe_case}.golden.png"
alternate_golden_tmp="/data/local/tmp/mobilegl-${safe_case}.alternate-golden.png"
"${ADB}" shell run-as "${package_name}" rm -rf files/trace-replay
"${ADB}" shell run-as "${package_name}" mkdir -p files/trace-replay/input files/trace-replay/output
"${ADB}" shell run-as "${package_name}" cp "${trace_tmp}" files/trace-replay/input/trace.trace
"${ADB}" shell run-as "${package_name}" cp "${golden_tmp}" files/trace-replay/input/golden.png
"${ADB}" shell run-as "${package_name}" rm -rf "${app_dir}"
"${ADB}" shell run-as "${package_name}" mkdir -p "${app_dir}/input" "${app_dir}/output"
"${ADB}" shell run-as "${package_name}" cp "${trace_tmp}" "${app_dir}/input/trace.trace"
"${ADB}" shell run-as "${package_name}" cp "${golden_tmp}" "${app_dir}/input/golden.png"
if [ -n "${alternate_golden_path}" ]; then
"${ADB}" shell run-as "${package_name}" cp "${alternate_golden_tmp}" files/trace-replay/input/alternate-golden.png
"${ADB}" shell run-as "${package_name}" cp "${alternate_golden_tmp}" "${app_dir}/input/alternate-golden.png"
fi
}
run_retrace() {
app_dir="/data/user/0/${package_name}/files/trace-replay"
result_dir="${result_root}/${safe_case}-${backend}"
alternate_golden_app_path=""
if [ -n "${alternate_golden_path}" ]; then
@@ -207,19 +217,26 @@ run_retrace() {
"${ADB}" shell "$@"
for _ in $(seq 1 "${timeout_seconds}"); do
if "${ADB}" shell run-as "${package_name}" ls files/trace-replay/output/result.json >/dev/null 2>&1; then
if "${ADB}" shell run-as "${package_name}" ls "${app_dir}/output/result.json" >/dev/null 2>&1; then
break
fi
sleep 1
done
"${ADB}" logcat -d -t 1000 > "${result_dir}/logcat.txt" || true
"${ADB}" shell run-as "${package_name}" ls files/trace-replay/output/result.json
"${ADB}" exec-out run-as "${package_name}" cat files/trace-replay/output/result.json > "${result_dir}/result.json"
collect_run_diagnostics "${result_dir}"
if ! "${ADB}" shell run-as "${package_name}" ls "${app_dir}/output/result.json" >/dev/null 2>&1; then
echo "trace-replay-ci.sh: result.json was not created after ${timeout_seconds}s" >&2
echo "trace-replay-ci.sh: recent relevant logcat lines:" >&2
grep -E 'MobileGLTraceRunner|AndroidRuntime|FATAL EXCEPTION|trace_replay|MobileGL|libc' "${result_dir}/logcat.txt" | tail -200 >&2 || true
echo "trace-replay-ci.sh: app trace-replay files:" >&2
cat "${result_dir}/app-files.txt" >&2 || true
exit 1
fi
"${ADB}" exec-out run-as "${package_name}" cat "${app_dir}/output/result.json" > "${result_dir}/result.json"
cat "${result_dir}/result.json"
"${ADB}" exec-out run-as "${package_name}" cat files/trace-replay/output/actual.png > "${result_dir}/${safe_case}-${backend}-actual.png"
"${ADB}" exec-out run-as "${package_name}" cat "files/trace-replay/output/${safe_case}-diff.png" > "${result_dir}/${safe_case}-${backend}-diff.png"
"${ADB}" exec-out run-as "${package_name}" cat files/trace-replay/output/retrace.log > "${result_dir}/retrace.log" || true
"${ADB}" exec-out run-as "${package_name}" cat "${app_dir}/output/actual.png" > "${result_dir}/${safe_case}-${backend}-actual.png"
"${ADB}" exec-out run-as "${package_name}" cat "${app_dir}/output/${safe_case}-diff.png" > "${result_dir}/${safe_case}-${backend}-diff.png"
"${ADB}" exec-out run-as "${package_name}" cat "${app_dir}/output/retrace.log" > "${result_dir}/retrace.log" || true
"${PYTHON}" -c 'import json, sys; result = json.load(open(sys.argv[1], encoding="utf-8")); sys.exit(0 if result.get("passed") else f"trace replay failed: {result}")' "${result_dir}/result.json"
}