Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ACTION_SERVICE_STOP intent to only stop a single AppShell #3821

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions app/src/main/java/com/termux/app/TermuxService.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ public int onStartCommand(Intent intent, int flags, int startId) {
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;
Expand Down Expand Up @@ -354,6 +358,25 @@ private void actionReleaseWakeLock(boolean updateNotification) {
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;
}

String shellName = IntentUtils.getStringExtraIfSet(intent, TERMUX_SERVICE.EXTRA_SHELL_NAME, null);
if (shellName == null) {
Logger.logError(LOG_TAG, "Ignoring intent since it did not contain explicit shell name");
return;
}

int gracePeriod = IntentUtils.getIntegerExtraIfSet(intent, TERMUX_SERVICE.EXTRA_TERMINATE_GRACE_PERIOD, 5000);
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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -245,6 +246,37 @@ private void executeInner(@NonNull final Context context) throws IllegalThreadSt
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.
Expand Down Expand Up @@ -274,6 +306,20 @@ public void killIfExecuting(@NonNull final Context context, boolean processResul
}
}


/**
* 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}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,9 @@ public static final class TERMUX_SERVICE {
/** 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 stop command execution with TERMUX_SERVICE */
public static final String ACTION_SERVICE_STOP = TERMUX_PACKAGE_NAME + ".service_execution_stop"; // Default: "com.termux.service_execution_stop"

/** 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 */
Expand Down Expand Up @@ -1046,6 +1049,9 @@ public static final class TERMUX_SERVICE {
* 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"; // Default: "com.termux.execute.stop.delay"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be stop_delay

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied

Copy link
Member

@agnostic-apollo agnostic-apollo Feb 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extra name was also different. Both should be same with respective case, naming them sigkill_delay_on_stop makes it more clear on function of extra.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will have to rename gracePeriod and gracePeriodMsec as well




Expand Down