mirror of
				https://github.com/fankes/termux-app.git
				synced 2025-10-25 13:19:21 +08:00 
			
		
		
		
	Updated RunCommandService javadocs.
Documentation has been moved to https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent
This commit is contained in:
		| @@ -1,7 +1,5 @@ | ||||
| package com.termux.app; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.app.IntentService; | ||||
| import android.app.Notification; | ||||
| import android.app.NotificationManager; | ||||
| import android.app.Service; | ||||
| @@ -23,250 +21,11 @@ import com.termux.shared.data.DataUtils; | ||||
| import com.termux.app.models.ExecutionCommand; | ||||
|  | ||||
| /** | ||||
|  * 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. | ||||
|  * 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 "/". | ||||
|  * | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  * | ||||
|  * 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: | ||||
|  * ``` | ||||
|  * 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: | ||||
|  * ``` | ||||
|  * 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' | ||||
|  * | ||||
|  * | ||||
|  * | ||||
|  * | ||||
|  * 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. | ||||
|  * | ||||
|  * Check https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent for more info. | ||||
|  */ | ||||
| public class RunCommandService extends Service { | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user