mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
d137a4cdde
Read Apktool 3's producer string dialect before YAML can discard hashes or reinterpret values. Preserve older YAML behavior and decode producer escapes once. Select the exact root AndroidManifest.xml resource in REA's JADX bridge and derive summaries once with namespace-aware XML parsing. Preserve decoded text, summarize before its display cap, invalidate cached facts with the loaded session, and remove superseded upstream manifest handlers. Keep the engine pinned to 0.7.1. Validated Apktool parser/provider and public adapter controls; compiled the bridge against the verified pinned JAR and ran its real Java regressions plus public CLI and stdio MCP manifest parity checks. Real Apktool execution remains unverified; the new manifest fixtures use plain XML. No Android application was executed. Fixes #6804 Fixes #6866 Fixes #6863 Fixes #6819
145 lines
4.1 KiB
JavaScript
145 lines
4.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { delimiter, join, resolve } from "node:path";
|
|
import { verifyAndroidMethodBodies } from "./method-bodies.mjs";
|
|
import { verifyAndroidDirectInvokes } from "./direct-invokes.mjs";
|
|
|
|
/** Prove cold metadata stays unmaterialized and overload identities survive code generation. */
|
|
export const verifyAndroidMetadata = async ({
|
|
java,
|
|
jar,
|
|
apk,
|
|
bridge,
|
|
repository,
|
|
execute,
|
|
entrypoint,
|
|
environment,
|
|
jvmArguments = [],
|
|
}) => {
|
|
const javac =
|
|
process.env.JAVA_HOME === undefined
|
|
? "javac"
|
|
: resolve(
|
|
process.env.JAVA_HOME,
|
|
"bin",
|
|
process.platform === "win32" ? "javac.exe" : "javac",
|
|
);
|
|
try {
|
|
await execute(javac, ["-version"], { timeout: 10_000 });
|
|
} catch (cause) {
|
|
throw new Error(
|
|
"verify:android metadata requires the full selected JDK, including javac",
|
|
{ cause },
|
|
);
|
|
}
|
|
const classes = await mkdtemp(join(tmpdir(), "rea-android-metadata-"));
|
|
try {
|
|
await execute(
|
|
javac,
|
|
[
|
|
...jvmArguments.map((argument) => `-J${argument}`),
|
|
"-classpath",
|
|
jar,
|
|
"-d",
|
|
classes,
|
|
bridge,
|
|
resolve(
|
|
repository,
|
|
"tests/conformance/android/ReaJadxMetadataRegression.java",
|
|
),
|
|
],
|
|
{ timeout: 30_000 },
|
|
);
|
|
const result = await execute(
|
|
java,
|
|
[
|
|
...jvmArguments,
|
|
"-classpath",
|
|
`${classes}${delimiter}${jar}`,
|
|
"ReaJadxMetadataRegression",
|
|
apk,
|
|
resolve(repository, "tests/fixtures/android/static-initializers"),
|
|
classes,
|
|
resolve(repository, "tests/fixtures/android/direct-invokes"),
|
|
],
|
|
{ timeout: 120_000, maxBuffer: 8 * 1024 * 1024 },
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/LOAD_FAILURE_REGRESSION_PASS typed=true decoy=true suspension=true cancellation=true/u,
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/METADATA_REGRESSION_PASS classes=\d+ overloads=3/u,
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/CLASS_SEARCH_REGRESSION_PASS pages=\d+ nonzero=true/u,
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/INITIALIZER_REGRESSION_PASS folded=2 bounded=true/u,
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/NO_BODY_REGRESSION_PASS native=true abstract=true frozen=true/u,
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/MERGED_METHOD_REGRESSION_PASS exact=true overloaded=true handlers=true/u,
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/DIRECT_INVOKE_REGRESSION_PASS nodes=1 offsets=0,3 cross_dex=true/u,
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/MANIFEST_REGRESSION_PASS root=true namespaces=true entities=true reload=true missing=true bounded=true/u,
|
|
);
|
|
console.log(
|
|
"PASS real cold metadata, full generic types and stable overloaded method selection",
|
|
);
|
|
console.log(
|
|
"PASS real Java filtered pages, nonzero inventory cursors and complete combined results",
|
|
);
|
|
console.log(
|
|
"PASS real folded and mixed static initializers, absent bodies and bounded smali",
|
|
);
|
|
console.log(
|
|
"PASS real native/abstract absence before and after neighbouring code generation",
|
|
);
|
|
console.log(
|
|
"PASS real raw DEX direct-invoke offsets and cross-DEX source identity",
|
|
);
|
|
console.log(
|
|
"PASS root manifest selection, namespace/entity values and session cache identity",
|
|
);
|
|
await verifyAndroidMethodBodies({
|
|
apk: resolve(classes, "initializers.apk"),
|
|
repository,
|
|
entrypoint,
|
|
environment,
|
|
execute,
|
|
});
|
|
await verifyAndroidDirectInvokes({
|
|
apk: resolve(classes, "direct-invokes.apk"),
|
|
dexEntry: "classes.dex",
|
|
repository,
|
|
entrypoint,
|
|
environment,
|
|
execute,
|
|
});
|
|
await verifyAndroidDirectInvokes({
|
|
apk: resolve(classes, "direct-invokes-multidex.apk"),
|
|
dexEntry: "classes2.dex",
|
|
repository,
|
|
entrypoint,
|
|
environment,
|
|
execute,
|
|
});
|
|
} finally {
|
|
await rm(classes, { recursive: true, force: true });
|
|
}
|
|
};
|