[PR #738] [MERGED] feat(android): integrate static APK analysis with headless JADX #2205

Closed
opened 2026-10-16 21:15:40 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/738
Author: @N0zoM1z0
Created: 10/6/2026
Status: ✅ Merged
Merged: 10/6/2026
Merged by: @N0zoM1z0

Base: main ← Head: feat/apk-analysis-adapters


📝 Commits (2)

  • d14f8e6 feat(android): integrate static APK analysis with headless JADX
  • bf9858b test(android): include APK tools in explicit effects audit

📊 Changes

59 files changed (+3342 additions, -52 deletions)

View changed files

➕ .gitmodules (+3 -0)
📝 .jscpd.json (+1 -0)
📝 .oxfmtrc.json (+2 -1)
📝 .oxlintrc.json (+2 -1)
📝 README.md (+7 -0)
📝 README_ar.md (+1 -0)
📝 README_ja.md (+13 -12)
📝 README_ko.md (+13 -12)
📝 README_zh.md (+13 -12)
➕ docs/android-analysis.md (+126 -0)
📝 docs/architecture.mermaid (+5 -0)
📝 docs/product-catalog.json (+36 -7)
📝 docs/testing.md (+17 -0)
📝 docs/verification/managed-conformance-manifest.json (+2 -2)
📝 package.json (+2 -0)
➕ scripts/fetch-android-fixtures.mjs (+70 -0)
➕ scripts/fixtures/android-apidemos.json (+14 -0)
➕ scripts/lib/android-cli-cancellation.mjs (+120 -0)
📝 scripts/lib/catalog-builders.mjs (+9 -0)
📝 scripts/lib/catalog-core.mjs (+2 -0)

...and 39 more files

📄 Description

Summary

Refs #717. This is the first independently useful APK milestone; the umbrella roadmap remains open.

  • Add five static Android operations with equivalent CLI/MCP workflows: package/manifest inspection, complete decompiler class search, class member inspection, selected-method Java/smali inspection, and incoming static reference tracing.
  • Reuse 1013503897/jadx-headless-mcp v0.7.1 without source changes. Preserve original Apache-2.0 source as a Git submodule pinned to 5844800a486d2248fa949b74c9896285f5b54de2; record the audited release JAR SHA-256 separately. REA builds do not require Gradle or a populated submodule.
  • Keep producer protocols in src/android/, portable semantics in domain/contracts, and shared admission/Evidence composition in application workflows. Bind MCP handlers to their named contracts and regenerate catalogs, skill metadata, and documentation.
  • Require caller-supplied Java/JAR; no global installation or automatic download during analysis. Every request uses immutable APK/engine snapshots and an owned process group. Serialize engine launches, use one worker and a 512 MiB JVM heap, and clean up on completion, cancellation, failure, or timeout. Heap is not a total RSS cap.
  • Add an explicit, hash-verified public fixture downloader and real Android verification lane. APK/JAR/reference files are ignored and excluded from npm packages.

Evidence and limitations

Results retain the original request, APK digest, actual executed JAR digest, raw upstream responses, and normalized data inline. Engine source attribution is unknown for different JAR bytes even if the server reports the supported version.

Reject fuzzy class matches, incomplete inventories, upstream failure placeholders, and ambiguous overload selections. The audited upstream smali fallback joins same-name overloads, so that ambiguous result is rejected even when a Java overload index was supplied. Native/abstract methods with no body report body_status: "not_available".

Display signatures are not exact DEX descriptors. DEX instruction offsets/source lines remain unknown; references are static. This milestone does not verify APK signatures, handle splits/AAB, analyze native libraries, or capture Android runtime behavior. macOS real Android coverage is unverified; Windows is unsupported at the provider's owned stdio boundary.

Sanitized MCP request:

{
  "name": "inspect_android_method",
  "arguments": {
    "path": "/tmp/Example.apk",
    "class_name": "example.MainActivity",
    "method_name": "onCreate"
  }
}

The response returns result, evidence_id, and full evidence, including normalized_result; method results declare representation, body availability, source completeness, and unknown DEX identity.

Verification

  • Focused regression suite: 10 files / 80 tests passed, covering APK producer parsing, target identity, overloads, fallback/truncation, active/queued cancellation, cleanup failure, MCP disconnect, canonical metadata, SDK-converted schema validity, CLI signal handling, and the shared process boundary.
  • npm run check:ci: all 7 static tasks passed.
  • npm run docs:check: passed after rebasing onto the updated main and regenerating conflicting derived documents.
  • npm run fixtures:android -- <fresh-temporary-directory>: downloaded and verified both pinned public artifacts; reuse also verified.
  • npm pack --json --pack-destination <temporary-directory> and an isolated offline npm install --ignore-scripts --omit=dev: passed. Asserted required Android modules are included and APK/JAR/reference/upstream source/private planning bytes are excluded.
  • REA_ANDROID_ENTRYPOINT=<installed-package>/scripts/rea.mjs ... node scripts/verify-real-android.mjs: passed on Linux with the actually installed npm package, real headless JADX 0.7.1 and Appium ApiDemos 6.0.18. All five CLI operations and all five stdio MCP operations passed; normalized results, intent, provider identity, Evidence validity, and artifact identity agree. Verified actual method source/references, unchanged original APK, and real CLI SIGTERM/owned Java group cleanup. APK was not executed.

No real Hopper/Ghidra verification was performed: their provider behavior is unchanged. Full deterministic coverage is left to PR CI.

CI follow-up

The first CI run exposed an omitted Android family in the test's independently enumerated effects-audit inventory (contractSnapshot.test.ts). Added the family to that inventory without weakening its completeness assertion. npm run test:local -- src/contracts/contractSnapshot.test.ts: all 5 tests passed. This follow-up changes only that test; the packaged real-engine verification above remains applicable.

Main synchronization

Rebased onto d0f3480a after the subsequent main merge batch. Regenerated all conflicting derived documents/catalogs. Inspected the shared boundary changes: shutdown adds failure diagnostics, and createServer supplies retained-reference callbacks to application tools. Android provider, service, contracts, CLI handlers, named MCP handlers, and shared process acquisition are byte-for-byte unchanged from the packaged real-engine verification. Focused integration recheck after rebase: 6 files / 23 tests passed, including all Android MCP operations/disconnect cleanup, published schema validity, server/shutdown behavior, effects audit, and product catalog.

Final checks

Latest head bf9858bb: all 20 PR CI checks passed. Additional real-APK overload probe on this head: androidx.core.content.ContextCompat.startActivities reports two overloads; selecting index 0 returns exactly startActivities(Context, Intent[]): boolean and its two-argument Java wrapper calling the three-argument overload with null. Verified Evidence identity and unchanged APK digest. This probe used the same one-worker/512 MiB engine limits; its local report remains outside Git.


🔄 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/738 **Author:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Created:** 10/6/2026 **Status:** ✅ Merged **Merged:** 10/6/2026 **Merged by:** [@N0zoM1z0](https://github.com/N0zoM1z0) **Base:** `main` ← **Head:** `feat/apk-analysis-adapters` --- ### 📝 Commits (2) - [`d14f8e6`](https://github.com/morluto/rea/commit/d14f8e6365e95031d630486704ce02a534e66152) feat(android): integrate static APK analysis with headless JADX - [`bf9858b`](https://github.com/morluto/rea/commit/bf9858bbd55987b10ad6eb43f882eb8dc53416b8) test(android): include APK tools in explicit effects audit ### 📊 Changes **59 files changed** (+3342 additions, -52 deletions) <details> <summary>View changed files</summary> ➕ `.gitmodules` (+3 -0) 📝 `.jscpd.json` (+1 -0) 📝 `.oxfmtrc.json` (+2 -1) 📝 `.oxlintrc.json` (+2 -1) 📝 `README.md` (+7 -0) 📝 `README_ar.md` (+1 -0) 📝 `README_ja.md` (+13 -12) 📝 `README_ko.md` (+13 -12) 📝 `README_zh.md` (+13 -12) ➕ `docs/android-analysis.md` (+126 -0) 📝 `docs/architecture.mermaid` (+5 -0) 📝 `docs/product-catalog.json` (+36 -7) 📝 `docs/testing.md` (+17 -0) 📝 `docs/verification/managed-conformance-manifest.json` (+2 -2) 📝 `package.json` (+2 -0) ➕ `scripts/fetch-android-fixtures.mjs` (+70 -0) ➕ `scripts/fixtures/android-apidemos.json` (+14 -0) ➕ `scripts/lib/android-cli-cancellation.mjs` (+120 -0) 📝 `scripts/lib/catalog-builders.mjs` (+9 -0) 📝 `scripts/lib/catalog-core.mjs` (+2 -0) _...and 39 more files_ </details> ### 📄 Description ## Summary Refs #717. This is the first independently useful APK milestone; the umbrella roadmap remains open. - Add five static Android operations with equivalent CLI/MCP workflows: package/manifest inspection, complete decompiler class search, class member inspection, selected-method Java/smali inspection, and incoming static reference tracing. - Reuse `1013503897/jadx-headless-mcp` v0.7.1 without source changes. Preserve original Apache-2.0 source as a Git submodule pinned to `5844800a486d2248fa949b74c9896285f5b54de2`; record the audited release JAR SHA-256 separately. REA builds do not require Gradle or a populated submodule. - Keep producer protocols in `src/android/`, portable semantics in domain/contracts, and shared admission/Evidence composition in application workflows. Bind MCP handlers to their named contracts and regenerate catalogs, skill metadata, and documentation. - Require caller-supplied Java/JAR; no global installation or automatic download during analysis. Every request uses immutable APK/engine snapshots and an owned process group. Serialize engine launches, use one worker and a 512 MiB JVM heap, and clean up on completion, cancellation, failure, or timeout. Heap is not a total RSS cap. - Add an explicit, hash-verified public fixture downloader and real Android verification lane. APK/JAR/reference files are ignored and excluded from npm packages. ## Evidence and limitations Results retain the original request, APK digest, actual executed JAR digest, raw upstream responses, and normalized data inline. Engine source attribution is unknown for different JAR bytes even if the server reports the supported version. Reject fuzzy class matches, incomplete inventories, upstream failure placeholders, and ambiguous overload selections. The audited upstream smali fallback joins same-name overloads, so that ambiguous result is rejected even when a Java overload index was supplied. Native/abstract methods with no body report `body_status: "not_available"`. Display signatures are not exact DEX descriptors. DEX instruction offsets/source lines remain unknown; references are static. This milestone does not verify APK signatures, handle splits/AAB, analyze native libraries, or capture Android runtime behavior. macOS real Android coverage is unverified; Windows is unsupported at the provider's owned stdio boundary. Sanitized MCP request: ```json { "name": "inspect_android_method", "arguments": { "path": "/tmp/Example.apk", "class_name": "example.MainActivity", "method_name": "onCreate" } } ``` The response returns `result`, `evidence_id`, and full `evidence`, including `normalized_result`; method results declare representation, body availability, source completeness, and unknown DEX identity. ## Verification - Focused regression suite: **10 files / 80 tests passed**, covering APK producer parsing, target identity, overloads, fallback/truncation, active/queued cancellation, cleanup failure, MCP disconnect, canonical metadata, SDK-converted schema validity, CLI signal handling, and the shared process boundary. - `npm run check:ci`: **all 7 static tasks passed**. - `npm run docs:check`: **passed** after rebasing onto the updated main and regenerating conflicting derived documents. - `npm run fixtures:android -- <fresh-temporary-directory>`: downloaded and verified both pinned public artifacts; reuse also verified. - `npm pack --json --pack-destination <temporary-directory>` and an isolated offline `npm install --ignore-scripts --omit=dev`: **passed**. Asserted required Android modules are included and APK/JAR/reference/upstream source/private planning bytes are excluded. - `REA_ANDROID_ENTRYPOINT=<installed-package>/scripts/rea.mjs ... node scripts/verify-real-android.mjs`: **passed on Linux with the actually installed npm package**, real headless JADX 0.7.1 and Appium ApiDemos 6.0.18. All five CLI operations and all five stdio MCP operations passed; normalized results, intent, provider identity, Evidence validity, and artifact identity agree. Verified actual method source/references, unchanged original APK, and real CLI SIGTERM/owned Java group cleanup. APK was not executed. No real Hopper/Ghidra verification was performed: their provider behavior is unchanged. Full deterministic coverage is left to PR CI. ### CI follow-up The first CI run exposed an omitted Android family in the test's independently enumerated effects-audit inventory (`contractSnapshot.test.ts`). Added the family to that inventory without weakening its completeness assertion. `npm run test:local -- src/contracts/contractSnapshot.test.ts`: **all 5 tests passed**. This follow-up changes only that test; the packaged real-engine verification above remains applicable. ### Main synchronization Rebased onto `d0f3480a` after the subsequent main merge batch. Regenerated all conflicting derived documents/catalogs. Inspected the shared boundary changes: shutdown adds failure diagnostics, and createServer supplies retained-reference callbacks to application tools. Android provider, service, contracts, CLI handlers, named MCP handlers, and shared process acquisition are byte-for-byte unchanged from the packaged real-engine verification. Focused integration recheck after rebase: **6 files / 23 tests passed**, including all Android MCP operations/disconnect cleanup, published schema validity, server/shutdown behavior, effects audit, and product catalog. ### Final checks Latest head `bf9858bb`: **all 20 PR CI checks passed**. Additional real-APK overload probe on this head: `androidx.core.content.ContextCompat.startActivities` reports two overloads; selecting index 0 returns exactly `startActivities(Context, Intent[]): boolean` and its two-argument Java wrapper calling the three-argument overload with `null`. Verified Evidence identity and unchanged APK digest. This probe used the same one-worker/512 MiB engine limits; its local report remains outside Git. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-16 21:15:40 +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#2205
No description provided.