Files
rea/experiments/analysis-efficiency/android-components.md
T
gensokyo-dev 7e8f7f6101 feat(android): expose selected manifest component declarations (#7379)
Extend static manifest declarations and retain precise source locations and historical unknowns. Share bounded selected component views across CLI and MCP with complete parent Evidence.

Verified real ApiDemos, an AAPT2-built fixture, legacy Evidence, default-package metadata and relevant CLI/MCP contracts. Recorded whole-task token estimates, timing/resource limits and independent main-failure controls in the PR.

Co-authored-by: Harsh <johiyaharsh@gmail.com>
2026-10-27 12:37:10 +08:00

15 KiB

Android component declarations and selected retained facts

Addresses #4448, extending the inventory already on main. Builds on Harsh's partial #7264 revision 987b5aceb66c7526e47cf6d064c22029c2f48c04, including its process budget. The historical-field correction preserves omission and marks unknown coverage; new fields are never invented as absent in old Evidence.

Owner and compatibility

The Android manifest parser owns declaration interpretation. A shared domain contract replaces duplicated provider/domain declarations; a single namespace reader and one nested-declaration pass produce structured filters and existing flattened action/category fields. Source positions address the exact retained decoded text. Unsupported data constraints and filter constructs mark partial coverage, including scheme-specific-part attributes outside the projected fields. The producer emits all current fields; historical readers accept omitted fields.

Existing complete requests and the existing default summary remain available. An explicit components view selects exact names/kinds/actions/exported declarations, fields and pages. Component summaries count explicit/default exports separately. CLI and MCP share the retained projection and retain complete parent Evidence. Repeated views reuse validated sealed records under the existing session lifetime; no new persistent provider cache or live-state freshness claim is introduced. Rows always retain the parent array ordinal and declaration coverage. The APK subject, engine identity, source status, limitations and parent linkage remain available. Nothing here establishes runtime enabling, resource resolution, Android URI matching, signature authenticity or execution of an app.

Reproduction inputs

The old runtime is main 15a8f6847ccac581c7ff717b42062a54b1ba8084. The timing/token qualification below was captured on that pinned base before the feature was rebased onto main 6207843814e5267e3a1d9796d5800346f69dc7da. The Android producer, bridge and view sources had no upstream changes in that range; latest-main integration is checked separately rather than relabeling the older runtime receipts. Actual verification uses Linux x86-64, Node 24.22.1, Temurin 21.0.12.1, JADX headless MCP 0.7.1 and the existing REA Java bridge protocol 7. JAR SHA-256: 6e5eacf500b64292bfb73c49797c1958f6ee44646e43e868039ae7feb573ff75. The public Appium ApiDemos 6.0.18 APK is 6,521,217 bytes, SHA-256 a9eecf37b26cd084855c530db81c2bb1b91f4c1b095a04f47aa7c20e2791f686. It has 355 declared components and 152,541 decoded manifest UTF-16 units. The recorded sorted relative-path/SHA-256 tables cover compiled dist/*.js and JSON recursively, the dispatcher/environment helper and Android bridge. Table SHA-256: old runtime 9581afe8ba48c15d803dd7ed3ffc4d10e4e4b99857a0b90206c8012e266daffe (2,435 files), final candidate a78698c12ae1dc514ffd3f09ca1b881747c9dde7d1a8677ceed7de3233334c40 (2,439 files). Raw tables remain with the private receipts.

android-components.mjs exercises actual public stdio MCP tools and validates results against the selected named SDK tool definition. Supply --repository, --target, a fresh --output directory, --mode before|after, --java-home and --jar. It captures the selected catalog, every RPC, complete exported parents, first-capture and warm-session results, and checks APK identity and an independent stdlib ElementTree oracle. No production manifest parser is reused by that oracle. Keep raw results, APKs and resource receipts outside Git. The selected tool families are android/application/session, with compact input schemas, two allowed CPUs, one analysis worker, 1 GiB JVM heap and a 3 GiB Node heap. A separate supervisor samples process-family memory every 100 ms, with an 8 GiB early stop and a 4 GiB host-available-memory floor. No guard stop or OOM occurred in these measurements.

Equivalent completed question

Find the receiver declaring android.provider.Telephony.SMS_RECEIVED and report its identity, permission, enabled/process declarations, per-filter priority and source position. The old runtime needs complete manifest delivery for the new facets. The selected candidate returns the matching row directly. Both treatments make one inspection plus one complete Evidence export per capture; the oracle verifies one positive match and the total count of 355 source declarations. An additional capture uses the same server/engine session. First capture is a fresh process/session, not a flushed OS page cache. Export costs and the extra call are included.

Initial candidate qualification passed the independent oracle. It measured first/warm inspection RPCs of 11.395/0.329 seconds versus the old runtime's 10.534/0.314 seconds. The complete two-capture process family took 19.065 seconds, 27.687 CPU seconds and 1,193,615,360 peak sampled RSS bytes versus 16.534 seconds, 24.675 CPU seconds and 1,107,955,712 bytes. This run predates the additional unsupported-data-attribute coverage correction. It establishes no latency, CPU or memory improvement; retained data has more declaration facts.

The final coverage-corrected candidate and a repeated immutable-main control also passed the identical oracle. Preserve all four receipts rather than choosing a favorable timing:

Runtime, execution order First/warm inspection RPC seconds Whole two-capture seconds CPU seconds Peak sampled family RSS bytes
Main control 1 10.534 / 0.314 16.534 24.675 1,107,955,712
Initial candidate 11.395 / 0.329 19.065 27.687 1,193,615,360
Final candidate 14.558 / 0.571 23.369 36.031 1,145,073,664
Main control 2 26.348 / 0.511 36.537 36.381 1,168,494,592

The repeated main control shows substantial host/run variation. These samples establish neither a deterministic slowdown nor a speedup; warm candidate RPCs are slightly slower in both observations. RSS is the sum of family RSS sampled every 100 ms, so shared pages may count more than once and short peaks may be missed; it is not a kernel/cgroup peak. Tokenizer processing is outside the timed SDK runs. Local oracle work, hashing, discovery, serialization, proof export and cleanup are inside. Cold/warm CPU and memory are not separately measured.

For the first main control and final candidate, o200k_base estimates give:

Cost per first capture Old complete Selected components
Inspection reply bytes 978,381 11,307
Inspection reply estimated tokens 225,926 2,715
Selected family name/description/input-schema catalog tokens 14,855 15,346
Question + input catalog + both call arguments/text replies 118,430 16,893
Full SDK catalog, including output schemas, + both calls 516,533 299,566

The primary text projection counts a fixed question, the input catalog once, all call arguments and every text reply, including export receipts. The SDK transport row additionally counts output schemas and structuredContent; it is not equated with model context. Reproduce with android-component-costs.py --output costs.json BEFORE_DIRECTORY AFTER_DIRECTORY (requires tiktoken). The manifest file exported locally is retained proof, not inline model context. These are tokenizer estimates of scripted SDK workflows, not billed model usage or a measured autonomous-agent task. They do not establish fewer model rounds or a generic analysis speedup. Actual provider work still reads the complete manifest, and schema discovery grows.

Global catalog compatibility

The actual CI merge 10746a4e8f8c622357cf8dd529f98adc8bf06d2b combines the feature with main parent 86d4a21215cb0fbafaf555b5c7d9fcda3f255d82. Real SDK discovery, using the same complete contract registrations as the existing profile test, gives:

Explicit wire profiles Pure main bytes CI merge bytes
Full input / full output 4,398,561 4,425,163
Compact input / compact output 556,450 558,653
Compact input / output off 302,913 305,116
Full input / output off 1,047,039 1,052,239

Input presentation defaults to compact; output presentation defaults to full. For frame-capped hosts, compact/off outputs are explicit compatibility choices. The bounded compatibility combinations retain the existing one-megabyte test limit and per-schema budgets. New selectors add 5,200 bytes with full inputs: 2,699 input bytes and 379 description bytes on inspect_android_package, plus 2,122 input bytes on the retained-view operation. Compact-input discovery grows 2,203 bytes. These global discovery costs are distinct from the selected-family task token estimates above.

This change crosses the old test assertion for full input with output off. That assertion was broader than its default-compact test name and the existing profile documentation: full inputs deliberately preserve complete guidance and can dominate the frame even without output schemas. The corrected test retains both compact-input frame limits, compares every full input schema with its named canonical advertisement under full/off outputs, preserves the entire tool set, and verifies that off removes only output advertisements. No production limit is raised and no full input validation/guidance is discarded. The owning guide now states this full-profile boundary explicitly.

Verification boundaries and failed attempts

The real Java regression exercises the existing raw/default-package class selector, native absence, references and frozen metadata around neighbouring source generation. An initial assertion compared the entire usage object: JADX legitimately populated def_pos from 0 to 103 after generating source. The revised assertion excludes only that presentation position and keeps class/method identity, raw DEX invoke IDs, descriptor/overload facts and invoke offsets. Production bridge behavior and version are unchanged.

One combined focused run passed 121 checks but hit the existing 30-second MCP test timeout while advertising every unrelated tool family to the SDK. Its failed receipt is retained. The Android-specific test now selects the same relevant families as the real SDK workflow; its named schemas, retained manifest/source-removal behavior, full/summary compatibility and complete Evidence export assertions remain enabled. A subsequent run exposed a test assertion that incorrectly expected repeated acquisitions to reuse the first Evidence ID. Each selected capture now proves its own retained parent exists and has the same artifact and normalized facts; engine reuse does not collapse distinct acquisition identities.

ApiDemos contains no URI data declarations. The checked-in manifest/resources and Smali container permit a second source-built APK with real AAPT2 binary XML and JADX decoding, including two filters, URI data, metadata, a resource boolean, explicit process and provider URI grants. Compiled APK/DEX outputs are private. Static declaration verification does not execute these component classes. The source-built APK SHA-256 was aea6ac64630ad70e93f4d85de0237cc51a7012b077ca0d0e7b24cf22c5737532. Its real CLI selected view and retained bundle passed verify-fixture.py, including AAPT2 dump comparison, all source positions, grouping, raw resource references, metadata names and provider URI grants. The real SDK VIEW query passed the independent ElementTree oracle on first and warm capture. An initial fixture build used Smali's CLI and failed because the engine JAR does not bundle optional JCommander; BuildDex.java now calls the already bundled Smali API directly.

The real metadata helper passed all Java markers and downstream CLI/MCP method body and direct-invoke parity checks for both classes.dex and classes2.dex: 149.436 seconds, 204.026 CPU seconds and 1,070,514,176 sampled peak family RSS bytes. No production bridge change was needed for default-package selectors.

A genuine complete parent from the old runtime also passed a new CLI retained component query with an explicitly nonexistent engine JAR. Its newly introduced fields remained omitted and row coverage remained unknown; no APK/provider reopening was required. The current source checks cover 111 parser cases, six projection cases, four CLI early-validation cases and four MCP cases, including named SDK-converted schemas and retained source-removal behavior.

After the rebase onto 6207843814e5267e3a1d9796d5800346f69dc7da, type/lint, all 125 focused cases and the nine documentation conformance cases passed again. A fresh real ApiDemos SDK qualification also passed the independent oracle: first/warm RPCs 11.291/0.290 seconds, whole two-capture elapsed 17.008 seconds, CPU 26.425 seconds and peak sampled family RSS 1,166,245,888 bytes. This is latest-main integration evidence; it is not paired with a new baseline performance cohort.

Review follow-up: Greptile correctly identified that the original oracle filtered before comparison, so the timing cohorts above verified selected-receiver facts and the inventory count, not every unselected component's facts. The oracle now returns an unfiltered inventory and derives the selected list from it. The driver checks every retained parent's identity, enabled/raw-enabled/process/permission, filter grouping/data/priority, metadata names, declaration coverage and component source location before checking the selected page. The receipt records both the verified count and scope; historical mode checks the available identity/permission facets without inventing the new observations. A fresh real ApiDemos first/warm run passed all 355 rows in both captures (16.538 seconds, 24.977 CPU seconds, 1,176,817,664 sampled peak family RSS bytes). The older receipts remain unchanged. The unfiltered historical-mode run also passed all 355 available identity/permission rows in both captures; the compiled manifest fixture passed all three current rows plus its selected VIEW page.

Platform coverage is Linux/JDK21/JADX0.7.1 only. Android devices, emulators, actual runtime enabling/registration, other JDKs and Windows/macOS are unverified here.