1
0
mirror of https://github.com/termux/termux-app synced 2024-06-17 22:57:08 +00:00

Add ACTION_SERVICE_STOP intent to only stop a single AppShell

This commit is contained in:
Christian Landvogt 2024-01-28 21:58:49 +01:00
parent 8e3a8980a8
commit e3c8598462
3 changed files with 74 additions and 0 deletions

View File

@ -8,6 +8,7 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Build;
@ -154,6 +155,10 @@ public final class TermuxService extends Service implements AppShell.AppShellCli
Logger.logDebug(LOG_TAG, "ACTION_SERVICE_EXECUTE intent received");
actionServiceExecute(intent);
break;
case TERMUX_SERVICE.ACTION_SERVICE_STOP:
Logger.logDebug(LOG_TAG, "ACTION_SERVICE_STOP intent received");
actionServiceStop(intent);
break;
default:
Logger.logError(LOG_TAG, "Invalid action: \"" + action + "\"");
break;
@ -354,6 +359,23 @@ public final class TermuxService extends Service implements AppShell.AppShellCli
Logger.logDebug(LOG_TAG, "WakeLocks released successfully");
}
private void actionServiceStop(Intent intent) {
if (intent == null) {
Logger.logError(LOG_TAG, "Ignoring null intent to actionServiceStop");
return;
}
int gracePeriod = IntentUtils.getIntegerExtraIfSet(intent, TERMUX_SERVICE.EXTRA_TERMINATE_GRACE_PERIOD, 5000);
Uri executableUri = intent.getData();
String executable = UriUtils.getUriFilePathWithFragment(executableUri);
String shellName = ShellUtils.getExecutableBasename(executable);
AppShell appShell = getTermuxTaskForShellName(shellName);
if (appShell != null) {
appShell.terminateIfExecuting(getApplicationContext(), gracePeriod, true);
}
}
/** Process {@link TERMUX_SERVICE#ACTION_SERVICE_EXECUTE} intent to execute a shell command in
* a foreground TermuxSession or in a background TermuxTask. */
private void actionServiceExecute(Intent intent) {

View File

@ -1,6 +1,7 @@
package com.termux.shared.shell.command.runner.app;
import android.content.Context;
import android.os.Handler;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@ -245,6 +246,37 @@ public final class AppShell {
AppShell.processAppShellResult(this, null);
}
/**
* Terminate this {@link AppShell} by sending a {@link OsConstants#SIGTERM} to its {@link #mProcess}
* if it is still executing. After {@code gracePeriodMsec} milliseconds {@link OsConstants#SIGTERM} is
* signalled.
*
* @param context The {@link Context} for operations.
* @param gracePeriodMsec The delay after which a SIGKILL is send.
* @param processResult If set to {@code true}, then the {@link #processAppShellResult(AppShell, ExecutionCommand)}
* will be called to process the failure.
*/
public void terminateIfExecuting(@NonNull final Context context, long gracePeriodMsec, boolean processResult) {
if (gracePeriodMsec == 0) {
killIfExecuting(context, processResult);
return;
}
// If execution command has already finished executing, then no need to process results or sending any signals
if (mExecutionCommand.hasExecuted()) {
Logger.logDebug(LOG_TAG, "Ignoring sending SIGTERM or SIGKILL to \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" AppShell since it has already finished executing");
return;
}
Logger.logDebug(LOG_TAG, "Send SIGTERM to \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" AppShell");
if (mExecutionCommand.isExecuting()) {
term();
}
(new Handler()).postDelayed(() -> killIfExecuting(context, processResult), gracePeriodMsec);
}
/**
* Kill this {@link AppShell} by sending a {@link OsConstants#SIGILL} to its {@link #mProcess}
* if its still executing.
@ -274,6 +306,20 @@ public final class AppShell {
}
}
/**
* Terminate this {@link AppShell} by sending a {@link OsConstants#SIGTERM} to its {@link #mProcess}.
*/
public void term() {
int pid = ShellUtils.getPid(mProcess);
try {
// Send SIGKILL to process
Os.kill(pid, OsConstants.SIGTERM);
} catch (ErrnoException e) {
Logger.logWarn(LOG_TAG, "Failed to send SIGTERM to \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" AppShell with pid " + pid + ": " + e.getMessage());
}
}
/**
* Kill this {@link AppShell} by sending a {@link OsConstants#SIGILL} to its {@link #mProcess}.
*/

View File

@ -993,6 +993,9 @@ public final class TermuxConstants {
/** Intent action to execute command with TERMUX_SERVICE */
public static final String ACTION_SERVICE_EXECUTE = TERMUX_PACKAGE_NAME + ".service_execute"; // Default: "com.termux.service_execute"
/** Intent action to execute command with TERMUX_SERVICE */
public static final String ACTION_SERVICE_STOP = TERMUX_PACKAGE_NAME + ".service_execution_stop"; // Default: "com.termux.service_execute"
/** Uri scheme for paths sent via intent to TERMUX_SERVICE */
public static final String URI_SCHEME_SERVICE_EXECUTE = TERMUX_PACKAGE_NAME + ".file"; // Default: "com.termux.file"
/** Intent {@code String[]} extra for arguments to the executable of the command for the TERMUX_SERVICE.ACTION_SERVICE_EXECUTE intent */
@ -1046,6 +1049,9 @@ public final class TermuxConstants {
* be created in {@link #EXTRA_RESULT_DIRECTORY} if {@link #EXTRA_RESULT_SINGLE_FILE} is
* {@code false} for the TERMUX_SERVICE.ACTION_SERVICE_EXECUTE intent */
public static final String EXTRA_RESULT_FILES_SUFFIX = TERMUX_PACKAGE_NAME + ".execute.result_files_suffix"; // Default: "com.termux.execute.result_files_suffix"
/** Intent {@code long} extra for graceperiod between SIGTERM and SIGKILL
* for the TERMUX_SERVICE.ACTION_SERVICE_STOP intent */
public static final String EXTRA_TERMINATE_GRACE_PERIOD = TERMUX_PACKAGE_NAME + ".execute.stop.delay";