Skip to content

Termux:API bridge: restore the socket read, fix the review findings, clean build - #35

Merged
GlobalTechInfo merged 8 commits into
mainfrom
feature/termux-api
Nov 5, 2026
Merged

GlobalTechInfo merged 8 commits into
mainfrom
feature/termux-api

Conversation

@GlobalTechInfo

@GlobalTechInfo GlobalTechInfo commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Adds the in-app termux:API bridge (guest helper over an abstract Unix socket, per-feature API actions), and closes the outstanding review findings.

This branch specifically:

  • Restores the request read to the inline form proven on device (the pooled read was closing connections with no answer).
  • Keeps the safe peer-credential guard and per-outcome logging so a silent close is diagnosable.
  • Rebuilds the guest helper for all four ABIs (rootfs-host extra, spacing fix).
  • Pins the parser against the exact wire lines the helper emits.
  • Compiles with 0 errors / 0 warnings, 558 unit tests pass, lint has 0 errors.

Summary by CodeRabbit

  • New Features
    • Updated the app to version 2.4.0.
    • Added a Termux:API-compatible bridge with commands for device information, networking, media, storage, notifications, and more.
    • Added Settings controls for viewing and requesting API permissions.
    • Added an optional startup hook for interactive distro sessions.
  • Documentation
    • Added the v2.4.0 changelog and updated F-Droid release details.

…ile, and the user startup hook

The Termux:API command surface runs entirely in-app: a per-ABI C helper
spoke the abstract-UDS wire protocol with a listener in the app process,
and the guest scripts reach Android features without a second SSH, camera or
SMS stack. The manifest is trimmed to a defensible core so the app stops
reading as a trojan profile to Play Protect, and the dispatch gate
distinguishes a missing grant from an undeclared permission so affected
commands answer honestly instead of dying in a pipe.

/root/.startup.local is the user-managed, once-per-interactive-session
startup hook (issue 32); it is in the shared tail of the generated startup
for all twenty distros, and redterm-startup-local prints a safe starter
body that is a no-op wherever run-parts or /etc/update-motd.d is absent.

versionCode 8 / versionName 2.4.0.
…erence

The gate is reading the w: lines of compileDebugKotlin, not the exit
code, and 13 compiler warnings had slipped through being reported as a
clean build. None is fixed by a suppression:

- The five unchecked as? List<T> casts on reflective results
  (CellInfoApi, NetworkApis, SsidApi) become a star-projection cast plus
  per-element concrete casts, which the compiler can check.
- The eight deprecated references stop being references:
  ScanResult.SSID is read by name (withdrawn on 33); setVisibleInDownloadsUi
  is invoked reflectively on the levels where it still has effect (<29, a
  documented no-op since); the no-arg MediaRecorder is reached by name with
  the Context constructor on 34+; the withdrawn CDMA/EHRPD/1xRTT constants
  stand as their stable documented values; the three-argument Locale
  constructor becomes Locale.forLanguageTag (non-deprecated on every level
  the app runs); and setWifiEnabled is reached by name on the declared
  type.
…unded reads, and close the review's gaps

Guest paths are named on the distro side, but the bridge opens them in the
app process. The launcher now exports REDTERM_ROOTFS_HOST, the guest helper
attaches it to every request, and ApiPaths is the one place that projects a
guest path to the host path it actually lives at (or refuses it). Share,
storage-get, media-play and media-scan all go through it.

Also, per the review:
- ApiSocket reads run on a bounded pool with a deadline; LocalSocket has no
  read-timeout API, so a stuck peer is bounded by the pool cap and closed,
  not pinned. Response bodies over the uint16 field are refused, not sent.
- A read/write size cap on saf readDocument; a counter-range guard; a
  bounded callback read; a non-cyclic media scan; a bound on concurrent
  requests.
- A single JSON string encoder (ApiJson) so an SSID with control bytes is
  valid JSON; TtsApi keeps the exact language/region/variant; the wifi
  toggle checks its grant and a present boolean flag; NFC rejects a disabled
  radio, re-enables reader mode on resume, and posts a cancel on destroy.
- installOne only replaces scripts it owns (the marker); ensureInstalled
  clears just the binary and stamp, keeping feature output.
- the startup-hook sourcing test now runs the block the generator emits,
  not a hand copy.

Helper binaries rebuilt for all four ABIs; GUEST_SCRIPT_VERSION is 7.
…host wire line

con.peerCredentials can throw IOException; unguarded it skipped every
writeResponse and the guest saw 'no response from the app'. The uid
guard now catches the read and says which way it closed, instead of
vanishing.

Also pin the parser against the exact rootfs-host line the rebuilt
helper puts on the wire, and finish the F-Droid metadata for v2.4.0.
A 'no response from the app' from the guest means the connection was
accepted and then closed without an answer. Several paths did that
silently: the uid guard (peerCredentials can throw), a peer that
closed before sending, and nothing marked the listener coming up.
Every outcome now logs, so the next on-device run says exactly which
branch closed the connection instead of vanishing.

Also pin the parser against the battery-status wire line with the
rootfs-host extra the rebuilt helper emits.
… pool

On device the pooled read stopped after 'connection accepted; reading
request' and never reached any outcome, so the guest saw 'no response
from the app'. The last release read inline on the request thread and
worked. Revert that one change: a stuck peer blocks only its own
request thread (capped by the semaphore), which LocalSocket cannot
bound any other way, and is the approach that is proven on device.
The safe uid guard and the per-outcome logging are kept.
@coderabbitai

coderabbitai Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Explain Change →

Caution

Review failed

The pull request is closed.

Walkthrough

RedTerm 2.4.0 adds a Termux:API-compatible bridge between guest shell commands and Android features. The app includes a native helper, request parsing and dispatch, API-specific implementations, permission and interactive UI flows, and an interactive-session startup hook.

Changes: Termux:API bridge

Layer / File(s) Summary
Request protocol and dispatch
native/redterm-api/*, native/build-redterm-api.sh, app/src/main/java/com/redtermapp/util/api/Api*.kt
The native guest helper sends requests over an abstract Unix socket. The app parses and dispatches requests to registered API features and returns framed responses.
Helper installation and proot integration
app/src/main/java/com/redtermapp/util/api/ApiHelper.kt, app/src/main/java/com/redtermapp/distro/*, app/src/main/java/com/redtermapp/ui/TerminalActivity.kt
The app extracts the helper, installs guest command aliases, and optionally binds the helper into proot. Interactive launches set session and rootfs environment values. The startup script runs /root/.startup.local only for interactive sessions.
Permission controls and blocking UI flows
app/src/main/AndroidManifest.xml, app/src/main/java/com/redtermapp/ui/SettingsActivity.kt, app/src/main/java/com/redtermapp/util/api/ui/*, app/src/main/java/com/redtermapp/util/api/{ApiPermissions,DialogApi,CameraPhotoApi,FingerprintApi,NfcApi,SafApi,SpeechToTextApi}.kt, app/src/main/res/layout/*, app/src/main/res/values/*
The manifest declares API permissions and non-exported UI activities. Settings displays runtime permission status. The UI bridge supports dialog, NFC, SAF grant, and speech request results.
Device and network query APIs
app/src/main/java/com/redtermapp/util/api/{BatteryApi,CallLogApi,CameraInfoApi,CellInfoApi,DangerousApis,NetworkApis,SsidApi,TelephonyInfoApi,UsbApi,SensorApi}.kt, app/src/test/java/com/redtermapp/util/api/*Test.kt
The bridge adds APIs that return device, call-history, camera, cellular, network, contact, sensor, and USB information.
Device controls, media, and scheduled work
app/src/main/java/com/redtermapp/util/api/{DangerousApis,DisplayApis,InfraredApi,JobRunWorker,JobScheduleApi,MediaApis,MediaPlaybackApi,MicRecordApi,NotificationApi,NotificationChannelApi,TtsApi,WifiEnableApi}.kt, app/build.gradle.kts
The bridge adds device controls, media operations, notifications, and WorkManager-backed job scheduling.
File, sharing, and external-service APIs
app/src/main/java/com/redtermapp/util/api/{CallbackApi,DownloadApi,MediaScannerApi,ShareApi,StorageGetApi,WallpaperApi,KeystoreApi}.kt
The bridge adds callback requests, file downloads and queries, media scanning, sharing, wallpaper operations, and AndroidKeyStore commands.
Release metadata and changelog
.fdroid/com.redtermapp.yml, CHANGELOG.md, app/build.gradle.kts, app/src/main/res/values/themes.xml
The app version changes to 2.4.0. F-Droid metadata points to the v2.4.0 changelog and screenshots, and the changelog documents the release.

Estimated code review effort: 5 (Critical) | ~90 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Guest as Guest command
  participant Client as redterm-api
  participant Socket as ApiSocket
  participant Parser as ApiRequestParser
  participant Dispatcher as ApiActions
  participant Feature as API feature
  Guest->>Client: Pass action and extras
  Client->>Socket: Send framed request
  Socket->>Parser: Parse request
  Parser-->>Socket: Return request or parse error
  Socket->>Dispatcher: Dispatch parsed request
  Dispatcher->>Feature: Run selected feature
  Feature-->>Socket: Return feature response
  Socket-->>Client: Send framed response
  Client-->>Guest: Print response
Loading
Merge Risk: High · up to 48389

This release adds a large Termux:API-compatible bridge, but several advertised commands do not work: keystore, NFC, job scripts, and fingerprint check. On Android 7–9 the release also stops backups and breaks distro exports by removing a storage permission. A guest can use the share command to expose app-private files, and stalled connections can make the bridge answer "busy" indefinitely. Fix the storage permission, the path containment, and the broken commands before merging.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@GlobalTechInfo
GlobalTechInfo merged commit e1d26ed into main Nov 5, 2026
1 of 2 checks passed
@GlobalTechInfo
GlobalTechInfo deleted the feature/termux-api branch November 5, 2026 07:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant