termux-app/app/src/main/java/com/termux/app/RunCommandService.java

459 lines
25 KiB
Java
Raw Normal View History

package com.termux.app;
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
import android.app.Activity;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import com.termux.R;
import com.termux.shared.termux.TermuxConstants;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
import com.termux.shared.file.FileUtils;
import com.termux.shared.logger.Logger;
import com.termux.shared.notification.NotificationUtils;
import com.termux.app.utils.PluginUtils;
import com.termux.shared.data.DataUtils;
import com.termux.app.models.ExecutionCommand;
/**
2021-02-27 08:23:37 +00:00
* Third-party apps that are not part of termux world can run commands in termux context by either
* sending an intent to RunCommandService or becoming a plugin host for the termux-tasker plugin
* client.
*
* For the {@link RUN_COMMAND_SERVICE#ACTION_RUN_COMMAND} intent to work, here are the requirements:
*
* 1. `com.termux.permission.RUN_COMMAND` permission (Mandatory)
* The Intent sender/third-party app must request the `com.termux.permission.RUN_COMMAND`
* permission in its `AndroidManifest.xml` and it should be granted by user to the app through the
* app's `App Info` `Permissions` page in Android Settings, likely under `Additional Permissions`.
* This is a security measure to prevent any other apps from running commands in `Termux` context
* which do not have the required permission granted to them.
*
* For `Tasker` you can grant it with:
* `Android Settings` -> `Apps` -> `Tasker` -> `Permissions` -> `Additional permissions` ->
* `Run commands in Termux environment`.
*
* 2. `allow-external-apps` property (Mandatory)
* The `allow-external-apps` property must be set to "true" in `~/.termux/termux.properties` in
* Termux app, regardless of if the executable path is inside or outside the `~/.termux/tasker/`
* directory. Check https://github.com/termux/termux-tasker#allow-external-apps-property-optional
* for more info.
*
* 3. `Draw Over Apps` permission (Optional)
* For android `>= 10` there are new
* [restrictions](https://developer.android.com/guide/components/activities/background-starts)
* that prevent activities from starting from the background. This prevents the background
* {@link TermuxService} from starting a terminal session in the foreground and running the
* commands until the user manually clicks `Termux` notification in the status bar dropdown
* notifications list. This only affects commands that are to be executed in a terminal
* session and not the background ones. `Termux` version `>= 0.100`
* requests the `Draw Over Apps` permission so that users can bypass this restriction so
* that commands can automatically start running without user intervention.
* You can grant `Termux` the `Draw Over Apps` permission from its `App Info` activity:
* `Android Settings` -> `Apps` -> `Termux` -> `Advanced` -> `Draw over other apps`.
*
* 4. `Storage` permission (Optional)
* Termux app must be granted `Storage` permission if the executable is accessing or working
* directory is set to path in external shared storage. The common paths which usually refer to
* it are `~/storage`, `/sdcard`, `/storage/emulated/0` etc.
* You can grant `Termux` the `Storage` permission from its `App Info` activity:
* For Android version < 11:
* `Android Settings` -> `Apps` -> `Termux` -> `Permissions` -> `Storage`.
* For Android version >= 11
* `Android Settings` -> `Apps` -> `Termux` -> `Permissions` -> `Files and media` ->
* `Allowed management of all files`.
* NOTE: For Android version >= 11, sometimes you will get `Permission Denied` errors for
* external shared storage even when you have granted `Files and media` permission. To solve
* this, Deny the permission and then Allow it again and restart Termux.
* Also check https://wiki.termux.com/wiki/Termux-setup-storage
*
* 5. Battery Optimizations (May be mandatory depending on device)
* Some devices kill apps aggressively or prevent apps from starting from background.
* If Termux is running into such problems, then exempt it from such restrictions.
* The user may also disable battery optimizations for Termux to reduce the chances of Termux
* being killed by Android even further due to violation of not being able to call
* `startForeground()` within ~5s of service start in android >= 8.
* Check https://dontkillmyapp.com/ for device specfic info to opt-out of battery optimiations.
*
* You may also want to check https://github.com/termux/termux-tasker
*
*
*
* The {@link RUN_COMMAND_SERVICE#ACTION_RUN_COMMAND} intent expects the following extras:
*
* 1. The **mandatory** {@code String} {@link RUN_COMMAND_SERVICE#EXTRA_COMMAND_PATH} extra for
* absolute path of command.
* 2. The {@code String[]} {@link RUN_COMMAND_SERVICE#EXTRA_ARGUMENTS} extra for any arguments to
* pass to command.
* 3. The {@code String} {@link RUN_COMMAND_SERVICE#EXTRA_WORKDIR} extra for current working directory
* of command. This defaults to {@link TermuxConstants#TERMUX_HOME_DIR_PATH}.
* 4. The {@code boolean} {@link RUN_COMMAND_SERVICE#EXTRA_BACKGROUND} extra whether to run command
* in background or foreground terminal session. This defaults to {@code false}.
* 5. The {@code String} {@link RUN_COMMAND_SERVICE#EXTRA_SESSION_ACTION} extra for for session action
* of foreground commands. This defaults to
* {@link TERMUX_SERVICE#VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY}.
* 6. The {@code String} {@link RUN_COMMAND_SERVICE#EXTRA_COMMAND_LABEL} extra for label of the command.
* 7. The markdown {@code String} {@link RUN_COMMAND_SERVICE#EXTRA_COMMAND_DESCRIPTION} extra for
* description of the command. This should ideally be get short.
* 8. The markdown {@code String} {@link RUN_COMMAND_SERVICE#EXTRA_COMMAND_HELP} extra for help of
* the command. This can add details about the command. 3rd party apps can provide more info
* to users for setting up commands. Ideally a url link should be provided that goes into full
* details.
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
* 9. The {@code Parcelable} {@link RUN_COMMAND_SERVICE#EXTRA_PENDING_INTENT} extra containing the
* pending intent with which result of commands should be returned to the caller. The results
* will be sent in the {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE} bundle. This is optional
* and only needed if caller wants the results back.
*
*
* The {@link RUN_COMMAND_SERVICE#EXTRA_COMMAND_PATH} and {@link RUN_COMMAND_SERVICE#EXTRA_WORKDIR}
* can optionally be prefixed with "$PREFIX/" or "~/" if an absolute path is not to be given.
* The "$PREFIX/" will expand to {@link TermuxConstants#TERMUX_PREFIX_DIR_PATH} and
* "~/" will expand to {@link TermuxConstants#TERMUX_HOME_DIR_PATH}, followed by a forward slash "/".
2020-09-18 17:22:35 +00:00
*
*
* The `EXTRA_COMMAND_*` extras are used for logging and are their values are provided to users in case
* of failure in a popup. The popup shown is in commonmark-spec markdown using markwon library so
* make sure to follow its formatting rules. Also make sure to end lines with 2 blank spaces to prevent
* word-wrap wherever needed.
* It's the users and 3rd party apps responsibility to use them wisely. There are also android
* internal intent size limits (roughly 500KB) that must not exceed when sending intents so make sure
* the combined size of ALL extras is less than that.
* There are also limits on the arguments size you can pass to commands or the full command string
* length that can be run, which is likely equal to 131072 bytes or 128KB on an android device.
* Check https://github.com/termux/termux-tasker#arguments-and-result-data-limits for more details.
*
*
*
* If your third-party app is targeting sdk 30 (android 11), then it needs to add `com.termux`
* package to the `queries` element or request `QUERY_ALL_PACKAGES` permission in its
* `AndroidManifest.xml`. Otherwise it will get `PackageSetting{...... com.termux/......} BLOCKED`
* errors in logcat and `RUN_COMMAND` won't work.
* https://developer.android.com/training/basics/intents/package-visibility#package-name
*
*
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
* Its probably wiser for apps to import the {@link TermuxConstants} class and use the variables
* provided for actions and extras instead of using hardcoded string values.
*
* Sample code to run command "top" with java:
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
* ```
* 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");
* intent.putExtra("com.termux.RUN_COMMAND_ARGUMENTS", new String[]{"-n", "5"});
* intent.putExtra("com.termux.RUN_COMMAND_WORKDIR", "/data/data/com.termux/files/home");
* intent.putExtra("com.termux.RUN_COMMAND_BACKGROUND", false);
* intent.putExtra("com.termux.RUN_COMMAND_SESSION_ACTION", "0");
* startService(intent);
* ```
*
* Sample code to run command "top" with "am startservice" command:
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
* ```
2021-02-27 08:23:37 +00:00
* am startservice --user 0 -n com.termux/com.termux.app.RunCommandService \
* -a com.termux.RUN_COMMAND \
* --es com.termux.RUN_COMMAND_PATH '/data/data/com.termux/files/usr/bin/top' \
* --esa com.termux.RUN_COMMAND_ARGUMENTS '-n,5' \
* --es com.termux.RUN_COMMAND_WORKDIR '/data/data/com.termux/files/home' \
* --ez com.termux.RUN_COMMAND_BACKGROUND 'false' \
* --es com.termux.RUN_COMMAND_SESSION_ACTION '0'
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
*
*
*
*
* The {@link RUN_COMMAND_SERVICE#ACTION_RUN_COMMAND} intent returns the following extras
* in the {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE} bundle if a pending intent is sent by the
* called in {@code Parcelable} {@link RUN_COMMAND_SERVICE#EXTRA_PENDING_INTENT} extra:
*
* For foreground commands ({@link RUN_COMMAND_SERVICE#EXTRA_BACKGROUND} is `false`):
* - {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT} will contain session transcript.
* - {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDERR} will be null since its not used.
* - {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE} will contain exit code of session.
* For background commands ({@link RUN_COMMAND_SERVICE#EXTRA_BACKGROUND} is `true`):
* - {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT} will contain stdout of commands.
* - {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDERR} will contain stderr of commands.
* - {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE} will contain exit code of command.
*
* The {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH} and
* {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH} will contain
* the original length of stdout and stderr respectively. This is useful to detect cases where
* stdout and stderr was too large to be sent back via an intent, otherwise
*
* The internal errors raised by termux outside the shell will be sent in the the
* {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_ERR} and {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG}
* extras. These will contain errors like if starting a termux command failed or if the user manually
* exited the termux sessions or android killed the termux service before the commands had finished executing.
* The err value will be {@link Activity#RESULT_OK}(-1) if no internal errors are raised.
*
* Note that if stdout or stderr are too large in length, then a {@link android.os.TransactionTooLargeException}
* exception will be raised when the pending intent is sent back containing the results, But it cannot
* be caught by the intent sender and intent will silently fail with logcat entries for the exception
* raised internally by android os components. To prevent this, the stdout and stderr sent
* back will be truncated from the start to max 100KB combined. The original length of stdout and
* stderr will be provided in
* {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH} and
* {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH} extras respectively, so
* that the caller can check if either of them were truncated. The errmsg will also be truncated
* from end to max 25KB to preserve start of stacktraces.
*
*
*
* If your app (not shell) wants to receive termux session command results, then put the
* pending intent for your app like for an {@link IntentService} in the "com.termux.RUN_COMMAND_PENDING_INTENT"
* extra.
* ```
* // Create intent for your IntentService class
* Intent pluginResultsServiceIntent = new Intent(MainActivity.this, PluginResultsService.class);
* // Create PendingIntent that will be used by termux service to send result of commands back to PluginResultsService
* PendingIntent pendingIntent = PendingIntent.getService(context, 1, pluginResultsServiceIntent, PendingIntent.FLAG_ONE_SHOT);
* intent.putExtra("com.termux.RUN_COMMAND_PENDING_INTENT", pendingIntent);
* ```
*
*
* Declare `PluginResultsService` entry in AndroidManifest.xml
* ```
* <service android:name=".PluginResultsService" />
* ```
*
*
* Define the `PluginResultsService` class
* ```
* public class PluginResultsService extends IntentService {
*
* public static final String PLUGIN_SERVICE_LABEL = "PluginResultsService";
*
* private static final String LOG_TAG = "PluginResultsService";
*
* public PluginResultsService(){
* super(PLUGIN_SERVICE_LABEL);
* }
*
* @Override
* protected void onHandleIntent(@Nullable Intent intent) {
* if (intent == null) return;
*
* if(intent.getComponent() != null)
* Log.d(LOG_TAG, PLUGIN_SERVICE_LABEL + " received execution result from " + intent.getComponent().toString());
*
*
* final Bundle resultBundle = intent.getBundleExtra("result");
* if (resultBundle == null) {
* Log.e(LOG_TAG, "The intent does not contain the result bundle at the \"result\" key.");
* return;
* }
*
* Log.d(LOG_TAG, "stdout:\n```\n" + resultBundle.getString("stdout", "") + "\n```\n" +
* "stdout_original_length: `" + resultBundle.getString("stdout_original_length") + "`\n" +
* "stderr:\n```\n" + resultBundle.getString("stderr", "") + "\n```\n" +
* "stderr_original_length: `" + resultBundle.getString("stderr_original_length") + "`\n" +
* "exitCode: `" + resultBundle.getInt("exitCode") + "`\n" +
* "errCode: `" + resultBundle.getInt("err") + "`\n" +
* "errmsg: `" + resultBundle.getString("errmsg", "") + "`");
* }
*
* }
*```
*
*
*
*
*
* A service that receives {@link RUN_COMMAND_SERVICE#ACTION_RUN_COMMAND} intent from third party apps and
* plugins that contains info on command execution and forwards the extras to {@link TermuxService}
* for the actual execution.
*/
public class RunCommandService extends Service {
Implement GUI based Termux settings manager and a centralized logging framework The settings activity can be accessed by long pressing on terminal view and selecting "Settings" from the popup shown. It uses the Android's Preference framework. Currently only debugging preferences to set log level and enabling terminal view key logging are provided. The Preference framework by default uses the keys set in `app:key` attribute in the respective preferences XML file to store the values in the default `SharedPreferences` file of the app. However, since we rely on `TermuxPreferenceConstants` and `TermuxPropertyConstants` classes to define key names so that they can be easily shared between termux and its plugin apps, we provide our own `PreferenceDataStore` for storing key/value pairs. The key name in the XML file can optionally be the same. Check `DebuggingPreferencesFragment` class for a sample. Each new preference category fragment should be added to `app/settings/` with its data store. This commit may allow support to be added for modifying `termux.properties` file directly from the UI but that requires more work, since writing to property files with comments require in-place modification. The `Logger` class provides various static functions for logging that should be used from now on instead of directly calling android `Log.*` functions. The log level is automatically loaded from shared preferences at application startup via `TermuxApplication` and set in the static `Logger.CURRENT_LOG_LEVEL` variable. Changing the log level through the settings activity also changes the log level immediately. The 4 supported log levels are: - LOG_LEVEL_OFF which will log nothing. - LOG_LEVEL_NORMAL which will start logging error, warn and info messages and stacktraces. - LOG_LEVEL_DEBUG which will start logging debug messages. - LOG_LEVEL_VERBOSE which will start logging verbose messages. The default log level is `LOG_LEVEL_NORMAL` which will not log debug or verbose messages. Contributors can add useful log entries at those levels where ever they feel is appropriate so that it allows users and devs to more easily help solve issues or find bugs, specially without having to recompile termux after having to manually add general log entries to the source. DO NOT log data that may have private info of users like command arguments at log levels below debug, like `BackgroundJob` was doing previously. Logging to file support may be added later, will require log file rotation support and storage permissions.
2021-03-13 11:49:29 +00:00
private static final String LOG_TAG = "RunCommandService";
class LocalBinder extends Binder {
public final RunCommandService service = RunCommandService.this;
}
private final IBinder mBinder = new RunCommandService.LocalBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
Logger.logVerbose(LOG_TAG, "onCreate");
runStartForeground();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.logDebug(LOG_TAG, "onStartCommand");
if(intent == null) return Service.START_NOT_STICKY;
// Run again in case service is already started and onCreate() is not called
runStartForeground();
ExecutionCommand executionCommand = new ExecutionCommand();
2021-04-06 07:21:22 +00:00
executionCommand.pluginAPIHelp = this.getString(R.string.error_run_command_service_api_help, RUN_COMMAND_SERVICE.RUN_COMMAND_API_HELP_URL);
String errmsg;
// If invalid action passed, then just return
if (!RUN_COMMAND_SERVICE.ACTION_RUN_COMMAND.equals(intent.getAction())) {
2021-03-24 01:15:45 +00:00
errmsg = this.getString(R.string.error_run_command_service_invalid_intent_action, intent.getAction());
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
return Service.START_NOT_STICKY;
}
executionCommand.executable = intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_COMMAND_PATH);
executionCommand.arguments = intent.getStringArrayExtra(RUN_COMMAND_SERVICE.EXTRA_ARGUMENTS);
executionCommand.workingDirectory = intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_WORKDIR);
executionCommand.inBackground = intent.getBooleanExtra(RUN_COMMAND_SERVICE.EXTRA_BACKGROUND, false);
executionCommand.sessionAction = intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_SESSION_ACTION);
2021-03-28 04:08:45 +00:00
executionCommand.commandLabel = DataUtils.getDefaultIfNull(intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_COMMAND_LABEL), "RUN_COMMAND Execution Intent Command");
executionCommand.commandDescription = intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_COMMAND_DESCRIPTION);
executionCommand.commandHelp = intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_COMMAND_HELP);
executionCommand.isPluginExecutionCommand = true;
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
executionCommand.pluginPendingIntent = intent.getParcelableExtra(RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT);
// If "allow-external-apps" property to not set to "true", then just return
// We enable force notifications if "allow-external-apps" policy is violated so that the
// user knows someone tried to run a command in termux context, since it may be malicious
// app or imported (tasker) plugin project and not the user himself. If a pending intent is
// also sent, then its creator is also logged and shown.
errmsg = PluginUtils.checkIfRunCommandServiceAllowExternalAppsPolicyIsViolated(this);
if (errmsg != null) {
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, true);
return Service.START_NOT_STICKY;
}
// If executable is null or empty, then exit here instead of getting canonical path which would expand to "/"
if (executionCommand.executable == null || executionCommand.executable.isEmpty()) {
errmsg = this.getString(R.string.error_run_command_service_mandatory_extra_missing, RUN_COMMAND_SERVICE.EXTRA_COMMAND_PATH);
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
return Service.START_NOT_STICKY;
}
// Get canonical path of executable
executionCommand.executable = FileUtils.getCanonicalPath(executionCommand.executable, null, true);
// If executable is not a regular file, or is not readable or executable, then just return
// Setting of missing read and execute permissions is not done
errmsg = FileUtils.validateRegularFileExistenceAndPermissions(this, "executable", executionCommand.executable, null,
PluginUtils.PLUGIN_EXECUTABLE_FILE_PERMISSIONS, true, true,
false);
if (errmsg != null) {
2021-03-24 01:15:45 +00:00
errmsg += "\n" + this.getString(R.string.msg_executable_absolute_path, executionCommand.executable);
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
return Service.START_NOT_STICKY;
}
// If workingDirectory is not null or empty
if (executionCommand.workingDirectory != null && !executionCommand.workingDirectory.isEmpty()) {
// Get canonical path of workingDirectory
executionCommand.workingDirectory = FileUtils.getCanonicalPath(executionCommand.workingDirectory, null, true);
// If workingDirectory is not a directory, or is not readable or writable, then just return
// Creation of missing directory and setting of read, write and execute permissions are only done if workingDirectory is
// under {@link TermuxConstants#TERMUX_FILES_DIR_PATH}
// We try to set execute permissions, but ignore if they are missing, since only read and write permissions are required
// for working directories.
errmsg = FileUtils.validateDirectoryFileExistenceAndPermissions(this, "working", executionCommand.workingDirectory, TermuxConstants.TERMUX_FILES_DIR_PATH, true,
PluginUtils.PLUGIN_WORKING_DIRECTORY_PERMISSIONS, true, true,
true, true);
if (errmsg != null) {
2021-03-24 01:15:45 +00:00
errmsg += "\n" + this.getString(R.string.msg_working_directory_absolute_path, executionCommand.workingDirectory);
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
return Service.START_NOT_STICKY;
}
}
executionCommand.executableUri = new Uri.Builder().scheme(TERMUX_SERVICE.URI_SCHEME_SERVICE_EXECUTE).path(FileUtils.getExpandedTermuxPath(executionCommand.executable)).build();
Logger.logVerbose(LOG_TAG, executionCommand.toString());
// Create execution intent with the action TERMUX_SERVICE#ACTION_SERVICE_EXECUTE to be sent to the TERMUX_SERVICE
Intent execIntent = new Intent(TERMUX_SERVICE.ACTION_SERVICE_EXECUTE, executionCommand.executableUri);
execIntent.setClass(this, TermuxService.class);
execIntent.putExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS, executionCommand.arguments);
if (executionCommand.workingDirectory != null && !executionCommand.workingDirectory.isEmpty()) execIntent.putExtra(TERMUX_SERVICE.EXTRA_WORKDIR, executionCommand.workingDirectory);
execIntent.putExtra(TERMUX_SERVICE.EXTRA_BACKGROUND, executionCommand.inBackground);
execIntent.putExtra(TERMUX_SERVICE.EXTRA_SESSION_ACTION, executionCommand.sessionAction);
execIntent.putExtra(TERMUX_SERVICE.EXTRA_COMMAND_LABEL, executionCommand.commandLabel);
execIntent.putExtra(TERMUX_SERVICE.EXTRA_COMMAND_DESCRIPTION, executionCommand.commandDescription);
execIntent.putExtra(TERMUX_SERVICE.EXTRA_COMMAND_HELP, executionCommand.commandHelp);
execIntent.putExtra(TERMUX_SERVICE.EXTRA_PLUGIN_API_HELP, executionCommand.pluginAPIHelp);
Add support for sending back background and foreground command results for RUN_COMMAND intent and foreground command results for Termux:Tasker Previously, termux only supported getting result of BACKGROUND commands back if they were started via Termux:Tasker plugin. Getting back result of foreground commands was not possible with any way. Now with RUN_COMMAND intent or Termux:Tasker, the third party apps and users can get the foreground command results as well. Note that by "foreground results" we only mean the session transcript. The session transcript will contain both stdout and stderr combined, basically anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes for interactive sessions. Getting separate stdout and stderr can currently only be done with background commands. Moreover, with RUN_COMMAND intent, third party apps and users can get the background commands results as well. This means separate extras for stdout and stderr. The exit code will also be returned for either case. ### RUN_COMMAND intent The result extras are returned in the TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE bundle via the pending intent received. The RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT extra can be used to send the pending intent with which termux should return the result bundle. The pending intent can be received back by the app with an IntentService. Check RunCommandService for reference implementation. For foreground commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is false): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain session transcript. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will be null since its not used. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of session. For background commands (RUN_COMMAND_SERVICE.EXTRA_BACKGROUND is true): - EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT will contain stdout of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_STDERR will contain stderr of commands. - EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE will contain exit code of command. The internal errors raised by termux outside the shell will be sent in the the EXTRA_PLUGIN_RESULT_BUNDLE_ERR and EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG extras. These will contain errors like if starting a termux command failed or if the user manually exited the termux sessions or android killed the termux service before the commands had finished executing. The err value will be Activity.RESULT_OK(-1) if no internal errors are raised. The stdout and stderr will be truncated from the start to max 100KB combined and errmsg will also be truncated from end to max 25KB. This is necessary to prevent TransactionTooLargeException exceptions from being raised if stdout or stderr are too large in length. The original length of stdout and stderr will be provided in EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH and EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH extras respectively, so that the caller can check if either of them were truncated. ### Termux:Tasker Support for Termux:Tasker for getting back result of foreground commands will require an update to it since it currently immediately returns control to plugin host app like Tasker without waiting if a foreground command is to be executed.
2021-03-25 18:05:55 +00:00
execIntent.putExtra(TERMUX_SERVICE.EXTRA_PENDING_INTENT, executionCommand.pluginPendingIntent);
// Start TERMUX_SERVICE and pass it execution intent
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
this.startForegroundService(execIntent);
} else {
this.startService(execIntent);
}
runStopForeground();
return Service.START_NOT_STICKY;
}
private void runStartForeground() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setupNotificationChannel();
startForeground(TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_ID, buildNotification());
}
}
private void runStopForeground() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true);
}
}
private Notification buildNotification() {
// Build the notification
Notification.Builder builder = NotificationUtils.geNotificationBuilder(this,
TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_LOW,
TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_NAME, null, null,
null, NotificationUtils.NOTIFICATION_MODE_SILENT);
if(builder == null) return null;
// No need to show a timestamp:
builder.setShowWhen(false);
// Set notification icon
builder.setSmallIcon(R.drawable.ic_service_notification);
// Set background color for small notification icon
builder.setColor(0xFF607D8B);
return builder.build();
}
private void setupNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
NotificationUtils.setupNotificationChannel(this, TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_ID,
TermuxConstants.TERMUX_RUN_COMMAND_NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
}
}