Termux-app: make TermuxService (com.termux.service_execute) available to other apps

Created on 10 Aug 2018  Â·  25Comments  Â·  Source: termux/termux-app

So, any app can use the TermuxService execute.

Only minor changes in AndroidManifest.xml are needed:
```
< permission android:name="com.termux.app.TermuxService">
< /permission>

  <service android:name="com.termux.app.TermuxService" android:permission="com.termux.app.TermuxService">
      <intent-filter>
        <action android:name="com.termux.service_execute" />
      </intent-filter>
    </service>

```

enhancement

Most helpful comment

but there's no actual info about how to do it here.

On Termux side: set allow-external-apps=true in ~/.termux/termux.properties.

On Your App side:

  1. Declare usage of com.termux.permission.RUN_COMMAND permission in AndroidManifest.xml.
  2. Create code which starts a new Termux session. Minimal example with top:
    .java Intent intent = new Intent(); intent.setClassName("com.termux", "com.termux.app.RunCommandService"); intent.setAction("com.termux.RUN_COMMAND"); intent.putExtra("com.termux.RUN_COMMAND_PATH", "/data/data/com.termux/files/usr/bin/top"); startService(intent);
  3. Compile and install application.
  4. Give permission com.termux.permission.RUN_COMMAND through Android OS settings or with ADB.

Closing issue as feature is already implemented and v0.95 is released.

All 25 comments

can you please clarify this? I am interested in executing streamlink which I have running in termux. I want to start the streamlink command from an android app

All similar issues have been closed in favour of this one, yes, but has there been any progress or concidering since the opening of this particular issue, 6 months ago?

any progress

Currently no, as we need to implement proper permission management so commands may be executed only by programs allowed by user.

Another thing that should be implemented is a way to access Termux files by third-party apps, again this will require implementing permissions.

Hi,

I took a look on how to do this.
As I am quite new on this, the approach can be wrong so don't hesitate to tell me

My usecase was to be able to use the TermuxService from the outside and especially from Easer.
To do so, I change the definition of TermuxService in AndroidManifest.xml like this:

        <service
            android:name="com.termux.app.TermuxService"
            android:exported="true"
            android:permission="com.termux.permission.TERMUX_SERVICE">
            <intent-filter>
                <action android:name="com.termux.service_execute" />
            </intent-filter>
        </service>

It seems that the intent-filter is important because without it, there is no dialog to ask the user on Easer to allow the custom permission.

I also need to define my custom permission:

    <permission android:name="com.termux.permission.TERMUX_SERVICE"
        android:label="@string/termux_permission_label"
        android:description="@string/termux_permission_description"
        android:icon="@drawable/ic_launcher"
        android:protectionLevel="dangerous"/>

Then I modify Easer to be able to access Termux.
To do so, I express the requirement of my permission by adding:

    <uses-permission android:name="com.termux.permission.TERMUX_SERVICE" /> 

in AndroidManifest.xml and I add the dynamic permission request in the code of Easer:

    @Override
    public boolean checkPermissions(@NonNull Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return PluginHelper.checkPermission(context, "com.termux.permission.TERMUX_SERVICE");
        } else {
            return true;
        }
//        return true;
    }

    @Override
    public void requestPermissions(@NonNull Activity activity, int requestCode) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            PluginHelper.requestPermission(activity, requestCode, "com.termux.permission.TERMUX_SERVICE");
        }
    }

Finally using run command plugin in Easer, I am able to run this following command:

am startservice --user 0 -a com.termux.service_execute -n com.termux/com.termux.app.TermuxService -d com.termux.file:/data/data/com.termux/files/home/.shortcuts/test

The test script should be available on .shortcuts directory.

What do you think about this approach ?

Changes are both available on https://github.com/edaubert/termux-app and https://github.com/edaubert/Easer if you want to try it. I can also provide a pull request if you are interested in. The changes in Termux are only about the AndroidManifest.xml and the string.xml to handle some translation.

@edaubert Seems okay. Can you open a PR ?

I really think that Idea in #302 is better and more secure. I.e. embed termux core or environment in another android app and then allow that Android App to execute Termux shell command.

It is cleaner and less security concern than what is attempted by #804.

It is also better to have this "embedded" Termux to operate as different environment than an installed Termux.

Just my $0.02. In case it is still possible to pivot to an "embeded termux" vs the idea in this thread!

@HarisHashim Note that Termux environment requires specific executable path (/data/data/com.termux/files/usr). This cannot be changed without recompiling packages. Also no one (especially maintainers) want deal with 100500 patches and rewriting them on each package update.

Ping. Any news?

Wait, isn't this already possible? There are bunch of apps here that call termux scripts, e.g.

https://github.com/termux/termux-boot/blob/master/app/src/main/java/com/termux/boot/BootJobService.java

Calls a script during boot.

I haven't been able to redo that in my own app yet though. My use case would be to call certain script from my app, one would think this is basic thing for termux.

I'm trying with this code at the moment:

fun runTermuxScriptBackground(filePath: String, ctx: Context) {
    val scriptUri = Uri.Builder().scheme("com.termux.file").path(filePath).build()
    val intent = Intent("com.termux.service_execute", scriptUri)
    intent.setClassName("com.termux", "com.termux.app.TermuxService")
    intent.putExtra("com.termux.execute.background", true)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        ctx.startForegroundService(intent)
    } else {
        ctx.startService(intent)
    }
}

Not yet working though.

Wait, isn't this already possible? There are bunch of apps here that call termux scripts, e.g.

From third-party apps no.
TermuxService isn't exported.

@Ciantic, the README says:

note that this app needs to be signed with the same key as the main Termux app in order to have the permission to execute scripts, so it's probably only available to be used like this by termux add-ons, unless you build termux yourself, and sign it, then sign whatever app you want to be able to use the service with the same key.

Oh bummer, have to wait for the PR.

I've made a nice job service myself I want to run with a script, really dying to use it :)

Ping. Any development going on this? If not can you let me know what all I need to integrate from the core to be used in my own app.

I'm aware that the main reason there is no "real progress" on this is due to permissions. Maybe this could be simplified by taking a similar approach as the termux-tasker add-on: Let third-party apps call scripts only in $HOME/.third-party-integration/com.thirdparty.apk/.

There could even be a list of directories to check, so that there could be an termux-side-package for any third-party app that wants to integrate + the possibility to add custom scripts for users. The calling APK would just specify the script's name (e.g. "myscript.sh") and TermuxService (or any other receiver) would check for:

  • /var/lib/third-party-integration/com.thirdparty.apk/myscript.sh
  • $HOME/.third-party-integration/com.thirdparty.apk/myscript.sh

The first file to be found would be executed. And there would be not much to worry about permissions, since the scripts could not be dropped in the correct location without the user actually doing that.

Guys while you're at it, there is temporary workaround for this, as for my case I needed to run ipfs(it's an application) commands in my Android app and found that there is an ipfs package available on termux, I wanted to use termux to run the commands and return the results to my app, as it may seem complex, there is a simple solution for this, termux has nodejs package using it we can run a server in termux, which in turn can execute commands on termux using node-cmd package, put it all together and you get a server to which we can send commands from our Android app to execute on termux and the server returns the response back, which fulfills the requirement for the need of integrating the core in the first place,. I've seen that I can even open ports on Android using termux and use the ports in my Android app for communication (ipfs communication stuff which is my requirement, I haven't attached that part in the sample code below). I used this for my project.

You can see a sample code here for reference
https://github.com/gopikrishnanrmg/IPFS_Mobile_Test

The changelog for v0.95 links here, but there's no actual info about how to do it here. This line of a commit sheds some light on the matter

Thank you so much! :)

Get Outlook for Androidhttps://aka.ms/ghei36


From: sudomain notifications@github.com
Sent: Friday, July 3, 2020 9:45:33 PM
To: termux/termux-app termux-app@noreply.github.com
Cc: Gopikrishnan Rajeev gopikrishnan.rmg@live.in; Comment comment@noreply.github.com
Subject: Re: [termux/termux-app] make TermuxService (com.termux.service_execute) available to other apps (#804)

The changelog for v0.95 links here, but there's no actual info about how to do it here. This line of a commit sheds some light on the matterhttps://github.com/termux/termux-app/commit/db3ff7b24a2cb8c84b00cc5cec083361018569a1#diff-ce2c83bede81bdf3c44d9adc68f68975R18

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHubhttps://github.com/termux/termux-app/issues/804#issuecomment-653612005, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AFBABI3OZDMF5OESYZTD6X3RZX72LANCNFSM4FO6ALRQ.

but there's no actual info about how to do it here.

On Termux side: set allow-external-apps=true in ~/.termux/termux.properties.

On Your App side:

  1. Declare usage of com.termux.permission.RUN_COMMAND permission in AndroidManifest.xml.
  2. Create code which starts a new Termux session. Minimal example with top:
    .java Intent intent = new Intent(); intent.setClassName("com.termux", "com.termux.app.RunCommandService"); intent.setAction("com.termux.RUN_COMMAND"); intent.putExtra("com.termux.RUN_COMMAND_PATH", "/data/data/com.termux/files/usr/bin/top"); startService(intent);
  3. Compile and install application.
  4. Give permission com.termux.permission.RUN_COMMAND through Android OS settings or with ADB.

Closing issue as feature is already implemented and v0.95 is released.

If someone needs to do this without using _intention_, for any strange reason or just "_because I can", you can install node.js (pkg install nodejs), start a local server that receives the script and executes it. (exec)

Remember, this isn't secure.

@iagows yeah, that's what I posted above

but there's no actual info about how to do it here.

On Termux side: set allow-external-apps=true in ~/.termux/termux.properties.

On Your App side:

1. Declare usage of `com.termux.permission.RUN_COMMAND` permission in AndroidManifest.xml.

2. Create code which starts a new Termux session. Minimal example with `top`:
   ```java
   Intent intent = new Intent();
   intent.setClassName("com.termux", "com.termux.app.RunCommandService");
   intent.setAction("com.termux.RUN_COMMAND");
   intent.putExtra("com.termux.RUN_COMMAND_PATH", "/data/data/com.termux/files/usr/bin/top");
   startService(intent);
   ```

3. Compile and install application.

4. Give permission `com.termux.permission.RUN_COMMAND` through Android OS settings or with ADB.

_Closing issue as feature is already implemented and v0.95 is released._

Thanks for the example, that works great.
But is it possible to run a custom .sh script file ?
Tried to set my custom script path in RUN_COMMAND_PATH but got an error :
exec("/data/data/com.termux/files/home/.scripts/script.sh") no such file or directory.

My script is executable and has the shebang #!$PREFIX/bin/bash

My script is executable and has the shebang #!$PREFIX/bin/bash

Do you literally have $PREFIX in the shebang? environmental variables are (at least generally) not supported in shebangs (https://unix.stackexchange.com/questions/20880/how-can-i-use-environment-variables-in-my-shebang)

@Grimler91 Hum, you're right. I used to test with the full path but i switched to $PREFIX for whatever reason...
Thank you for pointing this out.

Can confirm that it's working with the full shebang but i'm wondering :

  • With RUN_COMMAND_BACKGROUND true, everything is ok
  • With RUN_COMMAND_BACKGROUND false and termux is not running, it's not working (error in my app)
  • With RUN_COMMAND_BACKGROUND false and termux is running, it's working but termux doesn't launch itself automatically and when i open it, the session is empty (a simple echo "hello" doesn't return anything)

Maybe i'm missing something simple but is there a way to make termux open when i start the intent and view the result of my script ?

Maybe i'm missing something simple but is there a way to make termux open when i start the intent and view the result of my script ?

There is a pending PR that will open the session automatically, there is a suggested workaround until it is merged and released in the first post of that PR (sleep 1; am start --user 0 -n com.termux/com.termux.app.TermuxActivity)

Oh nice, i'll be waiting for the next release then.
Thank you !

Was this page helpful?
0 / 5 - 0 ratings