Files
rea/src/android/AndroidNativeInventory.ts
T
gensokyo-dev 570abe95f2 feat(android): link native declarations to static JNI candidates (#7472)
Link original DEX native declarations to per-ABI function exports and relocated static JNI table candidates through shared CLI/MCP workflows. Preserve global attribution ambiguity, exact provenance, partial coverage and retained Evidence; default MCP delivery to bounded summaries with filtered/batch pages.

Use one immutable ELF relocation decoder with streaming IL2CPP materialization, cooperative bounded export/version parsing and bounded JNI state. Reuse validated session inventories without loading target libraries or executing JNI code.

Validation: relevant type/lint/build and parser/domain/public CLI/MCP regressions; genuine four-ABI NDK fixtures and independent library/slot oracles; actual JDK/JADX Conscrypt workflows with retained-source removal. Full measurements and limitations are recorded in docs/verification/android-jni-bindings-2026-10-27.md.

Closes #6403.
2026-10-27 18:53:22 +08:00

43 lines
1.8 KiB
TypeScript

import type { JadxToolPort } from "./JadxAnalysis.js";
import type { AndroidNativeDeclarations } from "../domain/android/androidNativeDeclarations.js";
import { jadxNativeDeclarationsSchema } from "./JadxProtocol.js";
import { AnalysisOutputError } from "../domain/analysisErrorCore.js";
/** Validate the native-only batch at its producing boundary, preserving raw facts. */
export const readAndroidNativeInventory = async (
tools: JadxToolPort,
snapshot: string,
): Promise<AndroidNativeDeclarations> => {
const raw = await tools.json("rea_native_declarations", { path: snapshot });
const parsed = jadxNativeDeclarationsSchema.safeParse(raw);
if (!parsed.success)
throw new AnalysisOutputError(
"inspect_android_jni_bindings",
"JADX native declaration inventory was malformed",
{ cause: parsed.error },
);
const inventory = parsed.data;
const origins = new Map<number, string>();
const inconsistent =
inventory.coverage.examined_dex_entries > inventory.coverage.dex_entries ||
inventory.methods.length > inventory.coverage.examined_methods ||
(inventory.coverage.status === "complete" &&
(inventory.coverage.examined_dex_entries !==
inventory.coverage.dex_entries ||
inventory.unknowns.length !== 0)) ||
inventory.methods.some((method, index) => {
const previous = origins.get(method.dex_entry_index);
origins.set(method.dex_entry_index, method.dex_entry);
return (
method.source_index !== index ||
(previous !== undefined && previous !== method.dex_entry)
);
});
if (inconsistent)
throw new AnalysisOutputError(
"inspect_android_jni_bindings",
"JADX native declaration counts or source identities were inconsistent",
);
return inventory;
};