termux / termux-api

Termux add-on app which exposes device functionality as API to command line programs.
https://f-droid.org/en/packages/com.termux.api/
2.31k stars 457 forks source link

[question] is there any way to judge a temux-api can work normally not hang? #402

Closed Freed-Wu closed 2 years ago

Freed-Wu commented 3 years ago

https://github.com/romkatv/powerlevel10k/pull/1289#issuecomment-792236680

termux-battery-status hangs by default unless Termux:API is installed and given extra permissions. Thus, it's unsafe to invoke it without first ensuring that it won't hang. This is a deal breaker.

is there any way to judge a temux-api can work normally not hang?

Thanks!

Efreak commented 3 years ago

Check for existence of termux-api binary: [ -x $PREFIX/libexec/termux-api ] && do_something

Freed-Wu commented 3 years ago

Sorry for late. :(

it cannot work for me.

❯ tsu
❯ [ -x $PREFIX/libexec/termux-api ] && echo 1
1
# it will hang
❯ termux-wifi-connectioninfo
^C
Grimler91 commented 3 years ago

Why are you running it as root? There is no reason to do so, I guess that is the cause of the issue

ghost commented 3 years ago

[ -x $PREFIX/libexec/termux-api ] is not the right way to check whether Termux:API is installed. It consists of 2 sides, client (termux-api binary) and backend which is Termux:API add-on application. If the latter one doesn't exist, termux-api will hang.

agnostic-apollo commented 3 years ago

Running pm path com.termux.api should give you the apk installation path for Termux:API and is the reliable way to know for sure. It exits with exit code 1 if not found. But on newer android versions, you will get cmd: Failure calling service package: Failed transaction error since normal apps users can't run it, but privileged users like shell (use adb from android-tools package) or root can.

if pm path com.termux.api 1>/dev/null; then
    echo installed
fi
if su -c 'pm path com.termux.api 1>/dev/null'; then
    echo installed
fi

When running with adb, ensure you have already run adb connect. Also run adb devices and use the serial found for your current device and pass that as -s to adb shell command, otherwise if more than one devices found, adb command will fail with adb: more than one device/emulator.

if adb -s emulator-5554 shell 'pm path com.termux.api 1>/dev/null'; then
    echo installed
fi

Moreover, above way is also slow, since it has to make a call to the android package manager. Faster but slightly unreliable way would be to check if the /data/data/com.termux.api path exists which android should create at android app installation time and wouldn't require shell or root user since termux-app should be able to access the path due to sharedUserId (and technically without it too. Running [ -d /data/data/com.android.chrome ] && echo 1 works to check if directory exists but you can't access the contents with ls. Any app can check if another app is installed with this without any extra privileges if it knows the package name.)

[ -d /data/data/com.termux.api ] && echo 1

if [ -d /data/data/com.termux.api ]; then
    echo installed
fi
Freed-Wu commented 3 years ago

however, for non-termux user (as for me, it is u0_a205), Termux:API will hang whatever i do. why this phenomenon happen?

and if it cannot work for non-termux user, why it must hang not return a non-zero value?

thanks.

lgommans commented 3 years ago

This issue is being misunderstood I think. The replies are about detecting whether it's installed, but it seems the issue is that the process hangs.

I have a similar (or the same?) problem. Not everything hangs, for example reading the camera info works fine, but the sensors hang indefinitely when I just try to list them. Running $PREFIX/libexec/termux-api says an argument was expected, and when I do (no matter what it is) it just hangs forever. Running termux-sensor gives a help text, but termux-sensor -l hangs indefinitely. Using strace -f termux-sensor -l, there's a ton of output that I frankly can't understand (sometimes I see something helpful like waiting for a file or I can trace that it waits for a network packet) and it ends up hanging on accept4(3,. Not sure if that's an identical problem as what OP describes or a different one.

Edit: Oh hey it works if I run it from the terminal rather than from a computer via ssh. I double-checked logcat and this time spotted the stack trace, with accompanying messages, that I must have overlooked last time:

08-24 00:29:25.784 26649 26649 D AndroidRuntime: >>>>>> START com.android.internal.os.RuntimeInit uid 10159 <<<<<<
08-24 00:29:25.792 26649 26649 E libc    : Access denied finding property "persist.device_config.runtime_native_boot.profilebootclasspath"
08-24 00:29:25.792 26649 26649 E libc    : Access denied finding property "persist.device_config.runtime_native_boot.enable_apex_image"
08-24 00:29:25.792 26649 26649 I AndroidRuntime: Using default boot image
08-24 00:29:25.792 26649 26649 E libc    : Access denied finding property "persist.device_config.runtime_native_boot.disable_lock_profiling"
08-24 00:29:25.792 26649 26649 I AndroidRuntime: Leaving lock profiling enabled
08-24 00:29:25.792 26649 26649 E libc    : Access denied finding property "persist.device_config.runtime_native_boot.enable_generational_cc"
08-24 00:29:25.797 26649 26649 I app_process: Core platform API reporting enabled, enforcing=false
08-24 00:29:25.959 26649 26649 D app_process: Time zone APEX ICU file found: /apex/com.android.tzdata/etc/icu/icu_tzdata.dat
08-24 00:29:25.959 26649 26649 D app_process: I18n APEX ICU file found: /apex/com.android.i18n/etc/icu/icudt66l.dat
08-24 00:29:26.019 26649 26649 W app_process: JNI RegisterNativeMethods: attempt to register 0 native methods for android.media.AudioAttributes
08-24 00:29:26.033 26649 26649 D AndroidRuntime: Calling main entry com.termux.termuxam.Am
08-24 00:29:26.059 11455 11509 D CompatibilityChangeReporter: Compat change id reported: 135634846; UID 10159; state: DISABLED
08-24 00:29:26.061 11455 11510 D CompatibilityChangeReporter: Compat change id reported: 143937733; UID 10159; state: DISABLED
08-24 00:29:26.095 11325 11325 D Zygote  : Forked child process 26663
08-24 00:29:26.099 11455 11510 I ActivityManager: Start proc 26663:com.termux.api/u0a159 for broadcast {com.termux.api/com.termux.api.TermuxApiReceiver}
08-24 00:29:26.157   962   992 I adbd    : jdwp connection from 26663
08-24 00:29:26.212 26663 26663 D ApplicationLoaders: Returning zygote-cached class loader: /system/framework/android.test.base.jar
08-24 00:29:26.241 26663 26663 D NetworkSecurityConfig: No Network Security Config specified, using platform default
08-24 00:29:26.250 11455 12666 W ActivityManager: Background start not allowed: service Intent { act=list cmp=com.termux.api/.SensorAPI$SensorReaderService (has extras) } to com.termux.api/.SensorAPI$SensorReaderService from pid=26663 uid=10159 pkg=com.termux.api startFg?=false
08-24 00:29:26.242 26663 26663 D NetworkSecurityConfig: No Network Security Config specified, using platform default
08-24 00:29:26.253 26663 26663 E termux-api: Error in TermuxApiReceiver
08-24 00:29:26.253 26663 26663 E termux-api: java.lang.IllegalStateException: Not allowed to start service Intent { act=list cmp=com.termux.api/.SensorAPI$SensorReaderService (has extras) }: app is in background uid UidRecord{9cef9ac u0a159 RCVR bg:+1h2m30s337ms idle change:uncached procs:2 seq(0,0,0)}
08-24 00:29:26.253 26663 26663 E termux-api:    at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1715)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.app.ContextImpl.startService(ContextImpl.java:1670)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.content.ContextWrapper.startService(ContextWrapper.java:720)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.content.ContextWrapper.startService(ContextWrapper.java:720)
08-24 00:29:26.253 26663 26663 E termux-api:    at com.termux.api.SensorAPI.onReceive(SensorAPI.java:40)
08-24 00:29:26.253 26663 26663 E termux-api:    at com.termux.api.TermuxApiReceiver.doWork(TermuxApiReceiver.java:143)
08-24 00:29:26.253 26663 26663 E termux-api:    at com.termux.api.TermuxApiReceiver.onReceive(TermuxApiReceiver.java:21)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.app.ActivityThread.handleReceiver(ActivityThread.java:4026)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.app.ActivityThread.access$1400(ActivityThread.java:237)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1924)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.os.Handler.dispatchMessage(Handler.java:106)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.os.Looper.loop(Looper.java:223)
08-24 00:29:26.253 26663 26663 E termux-api:    at android.app.ActivityThread.main(ActivityThread.java:7664)
08-24 00:29:26.253 26663 26663 E termux-api:    at java.lang.reflect.Method.invoke(Native Method)
08-24 00:29:26.253 26663 26663 E termux-api:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
08-24 00:29:26.253 26663 26663 E termux-api:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
08-24 00:29:26.256 11455 12666 I ActivityManager: Killing 24284:com.android.shell/2000 (adj 995): empty #17
08-24 00:29:26.256 26649 26649 D AndroidRuntime: Shutting down VM
08-24 00:29:26.351 11325 11325 I Zygote  : Process 24284 exited due to signal 9 (Killed)

Running it in the foreground instead works. Rather annoying though, the point of automating this is that I am not typing that stuff in manually.

@Freed-Wu did you check (adb) logcat?

Freed-Wu commented 3 years ago

This issue is being misunderstood I think. The replies are about detecting whether it's installed, but it seems the issue is that the process hangs.

I have a similar (or the same?) problem. Not everything hangs...

I agree with you. I met the hang problem in both adb shell and terminal (after su). I have not done more researches about it. I feel confused by this situation...

lgommans commented 3 years ago

@Freed-Wu Check logcat if you have the same error.

Also I might recommend deepl.com for translation since you seem to not have understood my message fully. It is also hard to understand you. Deepl's english<>dutch translation is really good and it looks like they support chinese as well.


@Freed-Wu 检查logcat,如果你有同样的错误。

另外我可能会推荐deepl.com进行翻译,因为你似乎没有完全理解我的信息。我也很难理解你。Deepl的英语<>荷兰语翻译真的很好,而且看起来他们也支持中文。

agnostic-apollo commented 3 years ago

and if it cannot work for non-termux user, why it must hang not return a non-zero value?

The termux-api binary interacts with the Termux:API app via sockets, the app isn't running with root, so communications isn't possible, the app can't send back the result, hence command hangs. There are no checks in place in termux-api for whether caller is a non-termux user or not, so that a command isn't even sent to the app. Some commands like apt do have checks.

2021-08-07 18:13:34.651 8606-8637/com.termux.api E/termux-api: Error in ResultReturner
    java.io.IOException: Permission denied
        at android.net.LocalSocketImpl.connectLocal(Native Method)
        at android.net.LocalSocketImpl.connect(LocalSocketImpl.java:296)
        at android.net.LocalSocket.connect(LocalSocket.java:147)
        at com.termux.api.util.ResultReturner.lambda$returnData$0(ResultReturner.java:122)
        at com.termux.api.util.-$$Lambda$ResultReturner$oCU8JqHW5HLMrNZa40ThjAWcwzo.run(Unknown Source:8)
        at java.lang.Thread.run(Thread.java:919)

Basically, do not run with root. Running something like su 10xxx -c 'termux-wifi-connectioninfo' to run as termux user will fail as well, due to wrong capabilities/privileges, you will need something like this to work, which requires patching selinux policy as well. ~Moreover, termux doesn't provide setpriv and the mirrors for the one in stackexchange comment have expired, but attaching it. The one I compiled for termux from termux-packages was failing on android 7, but seemed to work on android 10 rooted emulator but magisk root script doesn't install supolicy so can't fully test it. Will look into it in future.~

setpriv_static_aarch64_v2.33.296-14690.zip

Update:

Termux util-linux package v2.37.2-1 provides setpriv now. Requires libcap-ng v0.8.3~pre1 or higher.

https://github.com/termux/termux-packages/pull/8198

E termux-api: java.lang.IllegalStateException: Not allowed to start service Intent { act=list cmp=com.termux.api/.SensorAPI$SensorReaderService (has extras) }: app is in background uid UidRecord{9cef9ac u0a159 RCVR bg:+1h2m30s337ms idle change:uncached procs:2 seq(0,0,0)}

Have you disabled battery optimizations for termux-api AND termux app? https://dontkillmyapp.com/

agnostic-apollo commented 3 years ago

Although, if running with root, then sending RUN_COMMAND intent in background mode that stores results in files should work. That way, termux app process would initiate the sockets so should work. In your root script, just wait for the result to be written to the output files in a while loop. Check https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent and termux/termux-app@2aafcf84

Freed-Wu commented 3 years ago

The termux-api binary interacts with the Termux:API app via sockets, the app isn't running with root, so communications isn't possible, the app can't send back the result, hence command hangs.

Thanks for your answer!

There are no checks in place in termux-api for whether caller is a non-termux user or not, so that a command isn't even sent to the app. Some commands like apt do have checks.

I know. If there are checks in termux-api, it will be great.

Basically, do not run with root... Will look into it in future.

Thanks!

Although, if running with root, then sending RUN_COMMAND intent in background mode that stores results in files should work.

Great. Thanks for your answer.