feat(android): trace callers of external DEX methods (#8154)

Resolve exact external method targets from directly encoded DEX invokes.
Preserve complete caller identity, bounded position evidence and follow-up
selectors. Report aggregate position coverage independently of the caller
inventory, and reuse bounded prototype facts within the exact session.

Absorbs #8096. Fixes #7811.

Co-authored-by: hhang <169027046+xu91102@users.noreply.github.com>
This commit is contained in:
gensokyo-devandhhang authored and GitHub committed 2026-10-31 01:07:18 +08:00
1 parent 675d4076de
commit 0ffed7a48c
20 files changed
+1472 -76

No files matched your search

+26 -1
View File
@@ -58,6 +58,9 @@ export const androidInputSchemas = {
}),
trace_android_references: z.strictObject({
...classTarget,
class_name: classTarget.class_name.describe(
"Exact APK-defined class, or an externally referenced DEX class when method_name is selected",
),
method_name: z
.string()
.min(1)
@@ -70,7 +73,7 @@ export const androidInputSchemas = {
.nonnegative()
.optional()
.describe(
"Index among same-name methods from inspect_android_class; requires method_name",
"Index among same-name APK methods or observed external DEX prototypes; requires method_name",
),
}),
} as const;
@@ -199,6 +202,12 @@ const method = z.strictObject({
is_constructor: z.boolean(),
dex_descriptor: dexDescriptorSchema,
});
/** Exact member selector shared with follow-up APK method inspection. */
export const androidMethodSelectorSchema = z.strictObject({
class_name: z.string().min(1),
method_name: z.string().min(1),
overload_index: z.int().nonnegative(),
});
const engine = z.strictObject({
name: z.string().min(1),
version: z.string().nullable(),
@@ -276,12 +285,26 @@ export const androidResultSchemas = {
}),
trace_android_references: z.strictObject({
...common,
/** Older retained Evidence omits this fact; omission does not mean external. */
target_definition: z.enum(["defined", "external"]).exactOptional(),
/** External results inventory directly encoded invokes, not reflection or dispatch. */
reference_scope: z.literal("direct_dex_invokes").exactOptional(),
class_name: z.string(),
method_name: z.string().nullable(),
overload_index: z.int().nonnegative().nullable(),
reported_signature: z.string().nullable(),
dex_descriptor: dexDescriptorSchema.nullable(),
total: z.int().nonnegative(),
/** Position coverage is separate from the complete using-node inventory.
* Historical Evidence may omit this aggregate; omission is unexamined. */
direct_invokes_coverage: z
.strictObject({
complete_using_nodes: z.int().nonnegative(),
partial_using_nodes: z.int().nonnegative(),
unknown_using_nodes: z.int().nonnegative(),
recorded_sites: z.int().nonnegative(),
})
.exactOptional(),
references: z.array(
z.strictObject({
kind: z.string(),
@@ -291,6 +314,8 @@ export const androidResultSchemas = {
top_class: z.string(),
source_line: z.null(),
dex_offset: z.null(),
/** An explicit follow-up selector accepted by inspect_android_method. */
source_selector: androidMethodSelectorSchema.exactOptional(),
/** false means transport-bounded instruction evidence; null is unknown. */
direct_invokes_exhaustive: z.boolean().nullable(),
/** Raw direct invoke instructions inside this using node, when available. */