Skip to content

Commit 187b86a

Browse files
committed
fix: validate adrenotools driver after extract to prevent cross-game cascade
The Adrenotools driver dir is shared across all containers using the same driver version (e.g. files/contents/adrenotools/Turnip_Gen8_V25/). When tar reports success but the extracted .so is silently truncated (storage hiccup, OOM, partial flush), every container that dlopens the binary inherits the bad state — manifesting as a black-screen cascade across games until the user reinstalls one of them, which forces a fresh re-extract. extractDriverFromResources now verifies the post-extract dir before returning success: - meta.json exists and parses - the libraryName from meta.json points at an existing .so - that .so is at least 1 MB (real Turnip/Adreno builds are 5-20 MB; anything smaller is partial) If any check fails the dir is deleted and false is returned, so the next launch starts from a clean slate instead of waiting for a manual reinstall. Costs a few stat() calls plus one small JSON parse — sub-millisecond. Catches truncated extracts (silent storage glitch). Doesn't catch fully-extracted-but-internally-corrupt .so files; that would require SHA-validating against an embedded checksum we don't have.
1 parent 73c235d commit 187b86a

1 file changed

Lines changed: 38 additions & 0 deletions

File tree

app/src/main/java/com/winlator/contents/AdrenotoolsManager.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,50 @@ private boolean extractDriverFromResources(String adrenotoolsDriverId) {
140140
Log.d("AdrenotoolsManager", "Extracting " + src + " to " + dst.getAbsolutePath());
141141
hasExtracted = TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, mContext, src, dst);
142142

143+
// Post-extract integrity check. tzst can report success while the .so is silently
144+
// truncated (storage hiccup, OOM, partial flush). A partial .so is the cross-game
145+
// corruption point: every container sharing this Adrenotools driver dlopens the
146+
// bad binary and renders nothing visible. Detecting it here forces clean re-extract
147+
// on next launch instead of waiting for a manual game reinstall.
148+
if (hasExtracted && !isDriverDirIntact(dst)) {
149+
Log.w("AdrenotoolsManager", "Driver dir failed integrity check after extract: " + dst.getAbsolutePath());
150+
hasExtracted = false;
151+
}
152+
143153
if (!hasExtracted)
144154
FileUtils.delete(dst);
145155

146156
return hasExtracted;
147157
}
148158

159+
/**
160+
* Validates that an extracted Adrenotools driver dir is structurally sound:
161+
* 1. meta.json exists and parses
162+
* 2. The libraryName referenced by meta.json points at an existing file
163+
* 3. That .so is at least 1 MB (real drivers are 5–20 MB; anything smaller is partial/empty)
164+
*
165+
* Returns true if all three hold. Cheap: a few stat calls + one small JSON parse.
166+
*/
167+
private boolean isDriverDirIntact(File driverDir) {
168+
try {
169+
File metaFile = new File(driverDir, "meta.json");
170+
if (!metaFile.isFile()) return false;
171+
String metaText = FileUtils.readString(metaFile);
172+
if (metaText == null || metaText.isEmpty()) return false;
173+
JSONObject meta = new JSONObject(metaText);
174+
String libraryName = meta.optString("libraryName", "");
175+
if (libraryName.isEmpty()) return false;
176+
File so = new File(driverDir, libraryName);
177+
if (!so.isFile()) return false;
178+
// Minimum sane size for a Vulkan driver .so. Real Turnip/Adreno builds are
179+
// 5–20 MB; truncated extracts typically leave files much smaller than that.
180+
return so.length() >= 1024L * 1024L;
181+
} catch (Exception e) {
182+
Log.w("AdrenotoolsManager", "isDriverDirIntact failed for " + driverDir.getAbsolutePath() + ": " + e);
183+
return false;
184+
}
185+
}
186+
149187
public String installDriver(Uri driverUri) {
150188
File tmpDir = new File(adrenotoolsContentDir, "tmp");
151189
if (tmpDir.exists()) tmpDir.delete();

0 commit comments

Comments
 (0)