[PR #3585] feat(android)!: expose method access flags and absent body reasons #5839

Open
opened 2026-10-31 01:09:49 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3585
Author: @daniyyell-dev
Created: 10/14/2026
Status: 🔄 Open

Base: main ← Head: feat/android-method-access-flags


📝 Commits (5)

  • fb96e9c feat(android): expose method access flags and absent body reasons
  • baf6129 fix(android)!: clarify unavailable method source evidence
  • 89d312b fix(android)!: reconcile method flags with current upstream body selection
  • da3dcee fix(android): reconcile verifier ownership with current upstream
  • 7ce3bef Merge origin/main into feat/android-method-access-flags

📊 Changes

12 files changed (+426 additions, -13 deletions)

View changed files

📝 bridge/android/ReaJadxBridge.java (+2 -1)
📝 docs/android-analysis.md (+15 -5)
📝 scripts/verify/android/method-bodies.mjs (+98 -1)
📝 src/android/JadxAnalysis.ts (+36 -2)
📝 src/android/JadxProtocol.ts (+34 -1)
📝 src/domain/android/androidAnalysis.ts (+34 -1)
📝 tests/boundary/android/JadxAnalysis.test.ts (+134 -0)
📝 tests/boundary/android/jadxProtocol.test.ts (+29 -0)
📝 tests/boundary/process/jadxIntegration.test.ts (+4 -2)
📝 tests/conformance/android/ReaJadxMetadataRegression.java (+24 -0)
📝 tests/fixtures/android/jadx-mcp.mjs (+3 -0)
➕ tests/fixtures/android/static-initializers/AccessFlags.smali (+13 -0)

📄 Description

Summary

This change exposes DEX method access flags in Android class and method inspection, helping callers identify native, abstract, static, synthetic, and bridge methods. This contribution fixes #3489.

Problem and expected behavior

Class summaries previously omitted method access flags. Callers had to inspect decompiled text to identify native, abstract, static, synthetic, or bridge methods. When a body was unavailable, the native/abstract placeholder did not distinguish between those two cases.

Method entries now include the raw unsigned access_flags value and decoded access_flag_names. Inspecting a native or abstract method returns empty source text and a specific body_unavailable_reason, without requesting a decompiled body. When both native and abstract flags are set, the reason is conflicting_access_flags, preserving both flags without assigning precedence. Other unavailable bodies use no_decompiled_body; available bodies have a null reason. Unavailable bodies have a null representation. Engine markers and placeholder text are preserved when a body RPC was made.

Change and scope

The bridge records access flags alongside method identities before generating source. The protocol validates the raw value, and the Android adapter decodes the method flags. The raw value preserves unknown bits. Shared result contracts expose these observations through both the CLI and MCP.

This change extends the existing static inspection workflow. PR #3527 addresses the related issue of incorrect source slices for native and abstract methods. This PR adds metadata and uses it to report why a body is unavailable.

Contract and boundary impact

  • Metadata ownership: the JADX bridge records raw flags; the Android adapter decodes them.
  • Scope: static metadata inspection within the existing provider. A separate scope decision for target execution or mutation is not applicable.
  • CLI and MCP contracts: method entries add access_flags and access_flag_names. Method results add the nullable body_unavailable_reason field and allow a null representation when the body is unavailable.
  • Provider compatibility: verified with the pinned jadx-headless-mcp 0.7.1 release on macOS arm64.
  • Evidence: preserves raw flags, reserved bits, overload identities, and artifact digests. Unavailable-body results distinguish observed flags from unexplained missing source.
  • Process and file effects: REA starts its existing managed JVM and compiles temporary bridge files. It does not execute or modify the target APK.
  • Generated metadata: docs:check regenerated and validated the ignored product catalog. Generated output is excluded from the commit.
  • Costs: method inventories add two fields per entry. Native and abstract requests skip the body RPC. Changes in token usage, execution time, CPU usage, and peak process-family memory were not measured.

Expected workflow effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.

The process and file effects above refer to the analysis JVM and temporary bridge files. Analysis does not contact network services. Test setup downloaded pinned public dependencies.

Evidence and regression coverage

  • Boundary tests cover raw values and unknown bits, decoded flags, specific native and abstract reasons, unexplained unavailable bodies, and malformed flag values. They also verify that native and abstract methods do not trigger a body RPC.
  • A new smali fixture contains abstract and native methods, plus a static method marked synthetic and bridge. A regression test using the real JADX engine checks exact flag values, decompiles the fixture, deliberately changes live method modifiers, and verifies that the frozen metadata retains the original values.
  • Against the original bridge at the branch base, the new regression test exits with code 1 and reports Raw method access flags were lost or changed for generated. It passes with the updated bridge.
  • Real CLI and MCP checks produce identical normalized results and confirm that the APK digest is unchanged.

Example native method result:

{
  "method": { "access_flags": 257, "access_flag_names": ["public", "native"] },
  "representation": null,
  "body_status": "not_available",
  "body_unavailable_reason": "native",
  "source": { "text": "" }
}

This is an excerpt of the fixture output, with other identity fields omitted.

Validation performed

Refreshed against upstream 32f0e51 on 18 October 2026, using Node 24.18.0, the installed macOS Command Line Tools and OpenJDK 21.

  • Typecheck and lint (npm run check:fast) passed.
  • All 95 tests in the four affected Android analysis, protocol, process and MCP files passed across the broad run and targeted rerun. The broad run passed 93 and timed out in two launch observations; those two passed after explicitly allowing 10 seconds for Java/ownership readiness before testing cancellation. Production deadlines are unchanged.
  • The complete npm run verify:android passed with the pinned JADX 0.7.1 JAR and ApiDemos APK. It exercised raw flags, original-method identity, native/abstract absence, CLI/MCP parity, direct-invoke offsets across two DEX files, class-search completeness, cancellation cleanup, prerequisite recovery and selector correction. The APK remained unchanged and was not executed.
  • npm run docs:check passed, including all five README consistency tests.
  • Whitespace checks passed.

Conflict resolution reuses upstream's shared prerequisite-verification helper and structured recovery assertions instead of retaining duplicated ownership setup. Human readiness declarations below are preserved from the existing PR. Fresh upstream CI and maintainer acceptance remain separate from these local checks.

Compatibility, safety, and release

Callers must handle representation: null when body_status is not_available; previously, unavailable bodies could be labelled java. Available bodies continue to report java or smali. Existing selectors and ordinary method-body behavior remain supported. The new fields increase class-summary size. Native and abstract methods now return empty source text with an explicit reason instead of a decompiler placeholder. Verification used the public ApiDemos APK and the new smali fixture on macOS arm64; it did not cover the reporter's BinaryEye APK, Linux, or Windows. This change adds no runtime dependencies or bundled provider binaries. Class-level access flags remain a separate follow-up to the method metadata requested in #3489.

Author readiness

Human owner: @daniyyell-dev

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

Before merge

  • The human owner completes the initial review and readiness declarations.
  • Maintainers confirm the output contract and resolve any remaining integration questions.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/3585 **Author:** [@daniyyell-dev](https://github.com/daniyyell-dev) **Created:** 10/14/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/android-method-access-flags` --- ### 📝 Commits (5) - [`fb96e9c`](https://github.com/morluto/rea/commit/fb96e9c19beb085fc5840ef3a1319a38bd5efc51) feat(android): expose method access flags and absent body reasons - [`baf6129`](https://github.com/morluto/rea/commit/baf6129749d240691fa6916f03359cab575afaf5) fix(android)!: clarify unavailable method source evidence - [`89d312b`](https://github.com/morluto/rea/commit/89d312b19729f245eae855bdabcf1cf7bedfd950) fix(android)!: reconcile method flags with current upstream body selection - [`da3dcee`](https://github.com/morluto/rea/commit/da3dceede9818038c5df189e9edbb0c3163ca660) fix(android): reconcile verifier ownership with current upstream - [`7ce3bef`](https://github.com/morluto/rea/commit/7ce3befffe03674bd61d0ee7858ccaccc0f6d27a) Merge origin/main into feat/android-method-access-flags ### 📊 Changes **12 files changed** (+426 additions, -13 deletions) <details> <summary>View changed files</summary> 📝 `bridge/android/ReaJadxBridge.java` (+2 -1) 📝 `docs/android-analysis.md` (+15 -5) 📝 `scripts/verify/android/method-bodies.mjs` (+98 -1) 📝 `src/android/JadxAnalysis.ts` (+36 -2) 📝 `src/android/JadxProtocol.ts` (+34 -1) 📝 `src/domain/android/androidAnalysis.ts` (+34 -1) 📝 `tests/boundary/android/JadxAnalysis.test.ts` (+134 -0) 📝 `tests/boundary/android/jadxProtocol.test.ts` (+29 -0) 📝 `tests/boundary/process/jadxIntegration.test.ts` (+4 -2) 📝 `tests/conformance/android/ReaJadxMetadataRegression.java` (+24 -0) 📝 `tests/fixtures/android/jadx-mcp.mjs` (+3 -0) ➕ `tests/fixtures/android/static-initializers/AccessFlags.smali` (+13 -0) </details> ### 📄 Description ## Summary This change exposes DEX method access flags in Android class and method inspection, helping callers identify native, abstract, static, synthetic, and bridge methods. This contribution fixes #3489. ## Problem and expected behavior Class summaries previously omitted method access flags. Callers had to inspect decompiled text to identify native, abstract, static, synthetic, or bridge methods. When a body was unavailable, the native/abstract placeholder did not distinguish between those two cases. Method entries now include the raw unsigned `access_flags` value and decoded `access_flag_names`. Inspecting a native or abstract method returns empty source text and a specific `body_unavailable_reason`, without requesting a decompiled body. When both native and abstract flags are set, the reason is `conflicting_access_flags`, preserving both flags without assigning precedence. Other unavailable bodies use `no_decompiled_body`; available bodies have a null reason. Unavailable bodies have a null `representation`. Engine markers and placeholder text are preserved when a body RPC was made. ## Change and scope The bridge records access flags alongside method identities before generating source. The protocol validates the raw value, and the Android adapter decodes the method flags. The raw value preserves unknown bits. Shared result contracts expose these observations through both the CLI and MCP. This change extends the existing static inspection workflow. PR #3527 addresses the related issue of incorrect source slices for native and abstract methods. This PR adds metadata and uses it to report why a body is unavailable. ## Contract and boundary impact - Metadata ownership: the JADX bridge records raw flags; the Android adapter decodes them. - Scope: static metadata inspection within the existing provider. A separate scope decision for target execution or mutation is not applicable. - CLI and MCP contracts: method entries add `access_flags` and `access_flag_names`. Method results add the nullable `body_unavailable_reason` field and allow a null `representation` when the body is unavailable. - Provider compatibility: verified with the pinned jadx-headless-mcp 0.7.1 release on macOS arm64. - Evidence: preserves raw flags, reserved bits, overload identities, and artifact digests. Unavailable-body results distinguish observed flags from unexplained missing source. - Process and file effects: REA starts its existing managed JVM and compiles temporary bridge files. It does not execute or modify the target APK. - Generated metadata: `docs:check` regenerated and validated the ignored product catalog. Generated output is excluded from the commit. - Costs: method inventories add two fields per entry. Native and abstract requests skip the body RPC. Changes in token usage, execution time, CPU usage, and peak process-family memory were not measured. Expected workflow effects: - [x] Read existing files or captured data. - [x] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [x] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. The process and file effects above refer to the analysis JVM and temporary bridge files. Analysis does not contact network services. Test setup downloaded pinned public dependencies. ## Evidence and regression coverage - Boundary tests cover raw values and unknown bits, decoded flags, specific native and abstract reasons, unexplained unavailable bodies, and malformed flag values. They also verify that native and abstract methods do not trigger a body RPC. - A new smali fixture contains abstract and native methods, plus a static method marked synthetic and bridge. A regression test using the real JADX engine checks exact flag values, decompiles the fixture, deliberately changes live method modifiers, and verifies that the frozen metadata retains the original values. - Against the original bridge at the branch base, the new regression test exits with code 1 and reports `Raw method access flags were lost or changed for generated`. It passes with the updated bridge. - Real CLI and MCP checks produce identical normalized results and confirm that the APK digest is unchanged. Example native method result: ```json { "method": { "access_flags": 257, "access_flag_names": ["public", "native"] }, "representation": null, "body_status": "not_available", "body_unavailable_reason": "native", "source": { "text": "" } } ``` This is an excerpt of the fixture output, with other identity fields omitted. ## Validation performed Refreshed against upstream `32f0e51` on 18 October 2026, using Node 24.18.0, the installed macOS Command Line Tools and OpenJDK 21. - Typecheck and lint (`npm run check:fast`) passed. - All 95 tests in the four affected Android analysis, protocol, process and MCP files passed across the broad run and targeted rerun. The broad run passed 93 and timed out in two launch observations; those two passed after explicitly allowing 10 seconds for Java/ownership readiness before testing cancellation. Production deadlines are unchanged. - The complete `npm run verify:android` passed with the pinned JADX 0.7.1 JAR and ApiDemos APK. It exercised raw flags, original-method identity, native/abstract absence, CLI/MCP parity, direct-invoke offsets across two DEX files, class-search completeness, cancellation cleanup, prerequisite recovery and selector correction. The APK remained unchanged and was not executed. - `npm run docs:check` passed, including all five README consistency tests. - Whitespace checks passed. Conflict resolution reuses upstream's shared prerequisite-verification helper and structured recovery assertions instead of retaining duplicated ownership setup. Human readiness declarations below are preserved from the existing PR. Fresh upstream CI and maintainer acceptance remain separate from these local checks. ## Compatibility, safety, and release Callers must handle `representation: null` when `body_status` is `not_available`; previously, unavailable bodies could be labelled `java`. Available bodies continue to report `java` or `smali`. Existing selectors and ordinary method-body behavior remain supported. The new fields increase class-summary size. Native and abstract methods now return empty source text with an explicit reason instead of a decompiler placeholder. Verification used the public ApiDemos APK and the new smali fixture on macOS arm64; it did not cover the reporter's BinaryEye APK, Linux, or Windows. This change adds no runtime dependencies or bundled provider binaries. Class-level access flags remain a separate follow-up to the method metadata requested in #3489. ## Author readiness Human owner: @daniyyell-dev - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge - [x] The human owner completes the initial review and readiness declarations. - [ ] Maintainers confirm the output contract and resolve any remaining integration questions. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5839
No description provided.