-
Notifications
You must be signed in to change notification settings - Fork 761
Termux:API commands hang due to "Invalid action: com.termux.service_api" - Proposed Broadcast Fix #844
Description
Disclaimer:
This report has been prepared by Gemini 3.0. It has successfully solved the issue for me and, while I do not have a complete understanding of what it has done, I hope this might be useful anyway.
Gemini has been debugging a user's local Termux environment where termux-api commands were failing. I am reporting the specific findings, logs, and a confirmed working solution derived from this session to assist the mantainers. Happy to help further, if needed.
Environment
- Device: Android (Xiaomi/MIUI environment detected in logs)
- Termux App Version: 0.118.3 (F-Droid signature)
- Termux:API App Version: 0.53.0 (F-Droid signature)
- termux-api package: 0.59.1 (aarch64)
The Issue
Execution of any API command (e.g., termux-battery-status, termux-vibrate) hangs indefinitely. The commands never return output and eventually timeout if a timeout is enforced.
Logcat Analysis:
When running termux-battery-status, the system log shows TermuxService rejecting the intent:
ActivityManager: Logging startService for com.termux, ... intent=Intent { act=com.termux.service_api cmp=com.termux/.app.TermuxService ... }
Termux:TermuxService: Invalid action: "com.termux.service_api"
It appears the current termux-api binary (C helper) attempts to start com.termux.app.TermuxService with the action com.termux.service_api. The main Termux app's service implementation (in onStartCommand) falls through or explicitly logs this action as invalid/unhandled.
Investigation & Attempts
- Standard Execution: Confirmed
am startservice -a com.termux.service_api ...fails with the log error above. - Service Execute: Tried
am startservice -a com.termux.service_execute ...(which is handled byTermuxService), but this expects a plugin execution context/runner and did not successfully bridge to the API logic. - Targeting the Receiver directly:
We analyzed theTermux:APImanifest anddumpsys.com.termux.api.TermuxApiReceiveris a registered receiver. Although declared withandroid:exported="false", it shares the same signature and user ID as the main Termux app, allowing interaction via root or same-user contexts.
The Solution (Verified)
We created a Python shim to replace /data/data/com.termux/files/usr/libexec/termux-api.
Instead of calling am startservice targeting the main app, the shim calls am broadcast targeting the API receiver directly.
Old Command (failing):
am startservice --user 0 -n com.termux/com.termux.app.TermuxService -a com.termux.service_api --es api_method BatteryStatus ...New Command (Working):
am broadcast --user 0 -n com.termux.api/.TermuxApiReceiver --es api_method BatteryStatus ...Verification
We verified this fix locally by replacing the libexec/termux-api binary with a Python script implementing the broadcast logic.
- BatteryStatus: Returns JSON correctly.
- Vibrate: Vibrates the device (permissions granted).
- Clipboard: Works correctly (implemented stdin reading in the shim to pass to the input socket).
- JobScheduler: Successfully lists and schedules jobs.
Recommendation
The issue seems to be a disconnect between how the termux-api C binary invokes the service and how the TermuxService (in the main app) expects to be called (or has stopped supporting service_api).
Updating the termux-api.c client to use an Intent Broadcast targeting com.termux.api/.TermuxApiReceiver (rather than starting the main TermuxService) appears to resolve the issue entirely on this version combination.
Key technical note for the fix:
If implementing this in the C binary, ensure the input socket handling (stdin) is maintained, as the TermuxApiReceiver logic appears to handle the socket connections correctly once triggered via Broadcast.