[PR #1875] [CLOSED] fix(android): recover folded static initializer instructions #4872

Closed
opened 2026-10-31 00:56:15 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1875
Author: @chqcjq
Created: 10/11/2026
Status: ❌ Closed

Base: main ← Head: fix/android-static-initializer-evidence


📝 Commits (1)

  • a3c7571 fix(android): recover folded static initializer instructions

📊 Changes

5 files changed (+208 additions, -30 deletions)

View changed files

📝 bridge/android/ReaJadxBridge.java (+53 -3)
📝 docs/android-analysis.md (+8 -0)
📝 scripts/verify/android/analysis.mjs (+49 -24)
📝 scripts/verify/android/windows-lifecycle.mjs (+16 -3)
📝 tests/conformance/android/ReaJadxMetadataRegression.java (+82 -0)

📄 Description

Summary

Fixes #1846.

Recover executable <clinit>()V instructions when JADX folds initialization into fields and returns its native/abstract placeholder for the standalone Java body. The public method result now contains the exact original DEX method as Smali, with fell_back: true and java-body-not-emitted, instead of reporting executable initialization as unavailable.

Problem and expected behavior

Reproduced on the fixed Appium ApiDemos 6.0.18 fixture with the audited jadx-headless-mcp 0.7.1 JAR. io.appium.android.apis.ApiDemos.<clinit> has original code that creates and stores sDisplayNameComparator. On base bcd350c3, CLI method inspection returns representation: java, body_status: not_available, and // method exists but has no decompiled body (native/abstract).

After this change, the same request returns one complete <clinit>()V block containing new-instance, the exact constructor invocation, sput-object ...->sDisplayNameComparator:Ljava/util/Comparator;, and return-void. The APK is never executed or modified.

Change and scope

  • Keep the parsed method node for the initializer identity that code generation can remove. Ordinary methods retain the existing current-node lookup, including after provider cache eviction.
  • Only for the exact initializer and missing Java body, verify a unique original member with code, then select its exact method block from the original class disassembly. Using the original class avoids mixing inner-class initializers. The audited input API's per-method printer omits some opcodes/symbolic operands, so it cannot provide the complete evidence required here.
  • Preserve the existing text byte budget and report unavailable with explicit markers when the original method or unique source block cannot be recovered. Ordinary method fallback and the overloaded-Smali guard are unchanged.
  • Extend the existing real-JAR regression and CLI/MCP parity lane. Update that lane's stale configuration/hash imports to the current owning APIs so the verification can execute on this base.

Contract and boundary impact

  • Semantic owner and earliest changed stage: REA-owned Java bridge, before Android result normalization.
  • CLI and MCP/tool catalog: no input or output schema change; existing Smali/fallback/marker fields carry the recovered evidence.
  • Provider/bridge compatibility: unchanged audited 0.7.1 JAR; no upstream submodule changes. Tested on Windows x64 with Oracle JDK 17.0.18 and Node 24.18.0.
  • Evidence/provenance: original APK/JAR identity and bridge digest remain captured; source is derived static instruction evidence, not original Java or runtime observation.
  • Process/authorization/cleanup: no added target execution or changed ownership rules.
  • Generated metadata/package/installation: no version change, new dependency, or committed generated output.

Evidence and regression coverage

  • The new real-JAR initializer assertion failed against the original bridge with the native/abstract placeholder, then passed with this patch.
  • The regression verifies original non-native/non-abstract DEX code, one exact initializer block and its symbolic operands, repeated reads, ordinary-method-first ordering, reload, cold metadata, three existing overloads, and an actual abstract no-code control. The fixture did not supply a suitable uniquely named native no-code control; no real native-method coverage is claimed.
  • Cache reload checks preserve method identity and the complete declaration/body while allowing a synthetic @Override prefix change also observed with the original bridge.
  • The public real-engine lane compares all five Android operations between CLI and MCP, plus the initializer case, and validates Evidence identities, parameters, provider, limitations, and target digest.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity and source provenance remain preserved.
  • Unavailable or uncertain outcomes remain visible.

Validation performed

  • npm run verify:android — passed with the pinned ApiDemos/JADX artifacts and the released 6.4.0 Windows native bundle. Includes real Java compilation, CLI/MCP parity, selector recovery, invalid/missing Java and JAR recovery, Windows cancellation/disconnect/abrupt-owner-exit checks, and unchanged APK digest. JVM reported its default 16,344 MiB heap; this is not a constrained-memory claim.
  • npm run check — passed; existing lint warnings remain, no errors.
  • npm run docs:check — passed.
  • git diff --check — passed.
  • npm run test:focused -- tests/boundary/process/jadxIntegration.test.ts tests/boundary/process/androidAnalysisMcp.test.ts — on Windows, 3 failed and 37 skipped. Independently reproduced the identical failures on unmodified bcd350c3 in a separate worktree with the same dependencies/native bundle. Three test.each cases bypass the file's Windows skip and use a POSIX fake JDK that provides bin/java, while Windows admission requires bin/java.exe; they fail before the intended upstream partial observations. The test/fixture/configuration files are byte-identical between base and patch. These unrelated assertions were not changed or weakened.

Compatibility, safety, and release

  • Breaking changes/migrations: none.
  • Platform coverage: real Windows x64/JDK 17 lane passed. Linux/macOS and a native no-code method were not exercised locally. Windows native C++ was not rebuilt; the verified release artifact supplied host controls.
  • Existing Windows forced CLI termination proves child-job cleanup, but does not claim workspace removal after abrupt owner death; the verifier preserves that distinction.
  • No credentials, binaries, local logs, or generated artifacts are included.

Review checklist

  • One concrete outcome and Conventional Commit title.
  • Related issue linked.
  • Regressions exercise changed observable behavior through the real provider.
  • Owning documentation updated.
  • Representative CLI/MCP behavior described.
  • Final diff checked for unrelated changes and unsupported claims.

🔄 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/1875 **Author:** [@chqcjq](https://github.com/chqcjq) **Created:** 10/11/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/android-static-initializer-evidence` --- ### 📝 Commits (1) - [`a3c7571`](https://github.com/morluto/rea/commit/a3c7571120ee0431bb23b98f2125fa700bf78a8b) fix(android): recover folded static initializer instructions ### 📊 Changes **5 files changed** (+208 additions, -30 deletions) <details> <summary>View changed files</summary> 📝 `bridge/android/ReaJadxBridge.java` (+53 -3) 📝 `docs/android-analysis.md` (+8 -0) 📝 `scripts/verify/android/analysis.mjs` (+49 -24) 📝 `scripts/verify/android/windows-lifecycle.mjs` (+16 -3) 📝 `tests/conformance/android/ReaJadxMetadataRegression.java` (+82 -0) </details> ### 📄 Description ## Summary Fixes #1846. Recover executable `<clinit>()V` instructions when JADX folds initialization into fields and returns its native/abstract placeholder for the standalone Java body. The public method result now contains the exact original DEX method as Smali, with `fell_back: true` and `java-body-not-emitted`, instead of reporting executable initialization as unavailable. ## Problem and expected behavior Reproduced on the fixed Appium ApiDemos 6.0.18 fixture with the audited jadx-headless-mcp 0.7.1 JAR. `io.appium.android.apis.ApiDemos.<clinit>` has original code that creates and stores `sDisplayNameComparator`. On base `bcd350c3`, CLI method inspection returns `representation: java`, `body_status: not_available`, and `// method exists but has no decompiled body (native/abstract)`. After this change, the same request returns one complete `<clinit>()V` block containing `new-instance`, the exact constructor invocation, `sput-object ...->sDisplayNameComparator:Ljava/util/Comparator;`, and `return-void`. The APK is never executed or modified. ## Change and scope - Keep the parsed method node for the initializer identity that code generation can remove. Ordinary methods retain the existing current-node lookup, including after provider cache eviction. - Only for the exact initializer and missing Java body, verify a unique original member with code, then select its exact method block from the original class disassembly. Using the original class avoids mixing inner-class initializers. The audited input API's per-method printer omits some opcodes/symbolic operands, so it cannot provide the complete evidence required here. - Preserve the existing text byte budget and report unavailable with explicit markers when the original method or unique source block cannot be recovered. Ordinary method fallback and the overloaded-Smali guard are unchanged. - Extend the existing real-JAR regression and CLI/MCP parity lane. Update that lane's stale configuration/hash imports to the current owning APIs so the verification can execute on this base. ## Contract and boundary impact - Semantic owner and earliest changed stage: REA-owned Java bridge, before Android result normalization. - CLI and MCP/tool catalog: no input or output schema change; existing Smali/fallback/marker fields carry the recovered evidence. - Provider/bridge compatibility: unchanged audited 0.7.1 JAR; no upstream submodule changes. Tested on Windows x64 with Oracle JDK 17.0.18 and Node 24.18.0. - Evidence/provenance: original APK/JAR identity and bridge digest remain captured; source is derived static instruction evidence, not original Java or runtime observation. - Process/authorization/cleanup: no added target execution or changed ownership rules. - Generated metadata/package/installation: no version change, new dependency, or committed generated output. ## Evidence and regression coverage - The new real-JAR initializer assertion failed against the original bridge with the native/abstract placeholder, then passed with this patch. - The regression verifies original non-native/non-abstract DEX code, one exact initializer block and its symbolic operands, repeated reads, ordinary-method-first ordering, reload, cold metadata, three existing overloads, and an actual abstract no-code control. The fixture did not supply a suitable uniquely named native no-code control; no real native-method coverage is claimed. - Cache reload checks preserve method identity and the complete declaration/body while allowing a synthetic `@Override` prefix change also observed with the original bridge. - The public real-engine lane compares all five Android operations between CLI and MCP, plus the initializer case, and validates Evidence identities, parameters, provider, limitations, and target digest. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity and source provenance remain preserved. - [x] Unavailable or uncertain outcomes remain visible. ## Validation performed - `npm run verify:android` — passed with the pinned ApiDemos/JADX artifacts and the released 6.4.0 Windows native bundle. Includes real Java compilation, CLI/MCP parity, selector recovery, invalid/missing Java and JAR recovery, Windows cancellation/disconnect/abrupt-owner-exit checks, and unchanged APK digest. JVM reported its default 16,344 MiB heap; this is not a constrained-memory claim. - `npm run check` — passed; existing lint warnings remain, no errors. - `npm run docs:check` — passed. - `git diff --check` — passed. - `npm run test:focused -- tests/boundary/process/jadxIntegration.test.ts tests/boundary/process/androidAnalysisMcp.test.ts` — on Windows, **3 failed and 37 skipped**. Independently reproduced the identical failures on unmodified `bcd350c3` in a separate worktree with the same dependencies/native bundle. Three `test.each` cases bypass the file's Windows skip and use a POSIX fake JDK that provides `bin/java`, while Windows admission requires `bin/java.exe`; they fail before the intended upstream partial observations. The test/fixture/configuration files are byte-identical between base and patch. These unrelated assertions were not changed or weakened. ## Compatibility, safety, and release - Breaking changes/migrations: none. - Platform coverage: real Windows x64/JDK 17 lane passed. Linux/macOS and a native no-code method were not exercised locally. Windows native C++ was not rebuilt; the verified release artifact supplied host controls. - Existing Windows forced CLI termination proves child-job cleanup, but does not claim workspace removal after abrupt owner death; the verifier preserves that distinction. - No credentials, binaries, local logs, or generated artifacts are included. ## Review checklist - [x] One concrete outcome and Conventional Commit title. - [x] Related issue linked. - [x] Regressions exercise changed observable behavior through the real provider. - [x] Owning documentation updated. - [x] Representative CLI/MCP behavior described. - [x] Final diff checked for unrelated changes and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:56:15 +00:00
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#4872
No description provided.