mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-07 03:05:18 +08:00
Partially integrate ExectionCommand into TermuxService and BackgroundJob
The TERMUX_SERVICE.ACTION_SERVICE_EXECUTE intent received will be managed by the ExectionCommand now. The cwd and failsafe have been renamed to workingDirectory and isFailsafe.
This commit is contained in:
@@ -7,6 +7,8 @@ import android.os.Bundle;
|
||||
|
||||
import com.termux.BuildConfig;
|
||||
import com.termux.app.utils.Logger;
|
||||
import com.termux.models.ExecutionCommand;
|
||||
import com.termux.models.ExecutionCommand.ExecutionState;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
@@ -26,28 +28,33 @@ import java.util.List;
|
||||
*/
|
||||
public final class BackgroundJob {
|
||||
|
||||
final Process mProcess;
|
||||
Process mProcess;
|
||||
|
||||
private static final String LOG_TAG = "BackgroundJob";
|
||||
|
||||
public BackgroundJob(String cwd, String fileToExecute, final String[] args, final TermuxService service){
|
||||
this(cwd, fileToExecute, args, service, null);
|
||||
public BackgroundJob(String executable, final String[] arguments, String workingDirectory, final TermuxService service){
|
||||
this(new ExecutionCommand(TermuxService.getNextExecutionId(), executable, arguments, workingDirectory, false, false), service);
|
||||
}
|
||||
|
||||
public BackgroundJob(String cwd, String fileToExecute, final String[] args, final TermuxService service, PendingIntent pendingIntent) {
|
||||
String[] env = buildEnvironment(false, cwd);
|
||||
if (cwd == null || cwd.isEmpty()) cwd = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
public BackgroundJob(ExecutionCommand executionCommand, final TermuxService service) {
|
||||
String[] env = buildEnvironment(false, executionCommand.workingDirectory);
|
||||
|
||||
final String[] progArray = setupProcessArgs(fileToExecute, args);
|
||||
final String processDescription = Arrays.toString(progArray);
|
||||
if (executionCommand.workingDirectory == null || executionCommand.workingDirectory.isEmpty())
|
||||
executionCommand.workingDirectory = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
|
||||
final String[] commandArray = setupProcessArgs(executionCommand.executable, executionCommand.arguments);
|
||||
final String commandDescription = Arrays.toString(commandArray);
|
||||
|
||||
if(!executionCommand.setState(ExecutionState.EXECUTING))
|
||||
return;
|
||||
|
||||
Process process;
|
||||
try {
|
||||
process = Runtime.getRuntime().exec(progArray, env, new File(cwd));
|
||||
process = Runtime.getRuntime().exec(commandArray, env, new File(executionCommand.workingDirectory));
|
||||
} catch (IOException e) {
|
||||
mProcess = null;
|
||||
// TODO: Visible error message?
|
||||
Logger.logStackTraceWithMessage(LOG_TAG, "Failed running background job: " + processDescription, e);
|
||||
Logger.logStackTraceWithMessage(LOG_TAG, "Failed running background job: " + commandDescription, e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -79,7 +86,7 @@ public final class BackgroundJob {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
Logger.logDebug(LOG_TAG, "[" + pid + "] starting: " + processDescription);
|
||||
Logger.logDebug(LOG_TAG, "[" + pid + "] starting: " + commandDescription);
|
||||
InputStream stdout = mProcess.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout, StandardCharsets.UTF_8));
|
||||
|
||||
@@ -109,16 +116,21 @@ public final class BackgroundJob {
|
||||
errThread.join();
|
||||
result.putString("stderr", errResult.toString());
|
||||
|
||||
if(!executionCommand.setState(ExecutionState.EXECUTED))
|
||||
return;
|
||||
|
||||
Intent data = new Intent();
|
||||
data.putExtra("result", result);
|
||||
|
||||
if(pendingIntent != null) {
|
||||
if(executionCommand.pluginPendingIntent != null) {
|
||||
try {
|
||||
pendingIntent.send(service.getApplicationContext(), Activity.RESULT_OK, data);
|
||||
executionCommand.pluginPendingIntent.send(service.getApplicationContext(), Activity.RESULT_OK, data);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
// The caller doesn't want the result? That's fine, just ignore
|
||||
}
|
||||
}
|
||||
|
||||
executionCommand.setState(ExecutionState.SUCCESS);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
@@ -133,10 +145,10 @@ public final class BackgroundJob {
|
||||
}
|
||||
}
|
||||
|
||||
static String[] buildEnvironment(boolean failSafe, String cwd) {
|
||||
static String[] buildEnvironment(boolean isFailSafe, String workingDirectory) {
|
||||
TermuxConstants.TERMUX_HOME_DIR.mkdirs();
|
||||
|
||||
if (cwd == null || cwd.isEmpty()) cwd = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
if (workingDirectory == null || workingDirectory.isEmpty()) workingDirectory = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
|
||||
List<String> environment = new ArrayList<>();
|
||||
|
||||
@@ -159,13 +171,13 @@ public final class BackgroundJob {
|
||||
addToEnvIfPresent(environment, "ANDROID_RUNTIME_ROOT");
|
||||
addToEnvIfPresent(environment, "ANDROID_TZDATA_ROOT");
|
||||
|
||||
if (failSafe) {
|
||||
if (isFailSafe) {
|
||||
// Keep the default path so that system binaries can be used in the failsafe session.
|
||||
environment.add("PATH= " + System.getenv("PATH"));
|
||||
} else {
|
||||
environment.add("LANG=en_US.UTF-8");
|
||||
environment.add("PATH=" + TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH);
|
||||
environment.add("PWD=" + cwd);
|
||||
environment.add("PWD=" + workingDirectory);
|
||||
environment.add("TMPDIR=" + TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH);
|
||||
}
|
||||
|
||||
@@ -186,7 +198,7 @@ public final class BackgroundJob {
|
||||
}
|
||||
}
|
||||
|
||||
static String[] setupProcessArgs(String fileToExecute, String[] args) {
|
||||
static String[] setupProcessArgs(String fileToExecute, String[] arguments) {
|
||||
// The file to execute may either be:
|
||||
// - An elf file, in which we execute it directly.
|
||||
// - A script file without shebang, which we execute with our standard shell $PREFIX/bin/sh instead of the
|
||||
@@ -236,7 +248,7 @@ public final class BackgroundJob {
|
||||
List<String> result = new ArrayList<>();
|
||||
if (interpreter != null) result.add(interpreter);
|
||||
result.add(fileToExecute);
|
||||
if (args != null) Collections.addAll(result, args);
|
||||
if (arguments != null) Collections.addAll(result, arguments);
|
||||
return result.toArray(new String[0]);
|
||||
}
|
||||
|
||||
|
@@ -263,8 +263,8 @@ public final class TermuxActivity extends Activity implements ServiceConnection
|
||||
Intent i = getIntent();
|
||||
if (i != null && Intent.ACTION_RUN.equals(i.getAction())) {
|
||||
// Android 7.1 app shortcut from res/xml/shortcuts.xml.
|
||||
boolean failSafe = i.getBooleanExtra(TERMUX_ACTIVITY.ACTION_FAILSAFE_SESSION, false);
|
||||
mTermuxSessionClient.addNewSession(failSafe, null);
|
||||
boolean isFailSafe = i.getBooleanExtra(TERMUX_ACTIVITY.ACTION_FAILSAFE_SESSION, false);
|
||||
mTermuxSessionClient.addNewSession(isFailSafe, null);
|
||||
} else {
|
||||
mTermuxSessionClient.setCurrentSession(mTermuxSessionClient.getCurrentStoredSessionOrLast());
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import com.termux.R;
|
||||
@@ -28,16 +27,15 @@ import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
|
||||
import com.termux.app.terminal.TermuxSessionClient;
|
||||
import com.termux.app.terminal.TermuxSessionClientBase;
|
||||
import com.termux.app.utils.Logger;
|
||||
import com.termux.app.utils.PluginUtils;
|
||||
import com.termux.app.utils.TextDataUtils;
|
||||
import com.termux.models.ExecutionCommand;
|
||||
import com.termux.models.ExecutionCommand.ExecutionState;
|
||||
import com.termux.terminal.TerminalEmulator;
|
||||
import com.termux.terminal.TerminalSession;
|
||||
import com.termux.terminal.TerminalSessionClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -55,7 +53,9 @@ import java.util.List;
|
||||
public final class TermuxService extends Service {
|
||||
|
||||
private static final String NOTIFICATION_CHANNEL_ID = "termux_notification_channel";
|
||||
private static final int NOTIFICATION_ID = 1337;
|
||||
public static final int NOTIFICATION_ID = 1337;
|
||||
|
||||
private static int EXECUTION_ID = 1000;
|
||||
|
||||
/** This service is only bound from inside the same process and never uses IPC. */
|
||||
class LocalBinder extends Binder {
|
||||
@@ -275,36 +275,45 @@ public final class TermuxService extends Service {
|
||||
|
||||
/** Process action to execute a shell command in a foreground session or in background. */
|
||||
private void actionServiceExecute(Intent intent) {
|
||||
Uri executableUri = intent.getData();
|
||||
String executablePath = (executableUri == null ? null : executableUri.getPath());
|
||||
if (intent == null){
|
||||
Logger.logError(LOG_TAG, "Ignoring null intent to actionServiceExecute");
|
||||
return;
|
||||
}
|
||||
|
||||
String[] arguments = (executableUri == null ? null : intent.getStringArrayExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS));
|
||||
String cwd = intent.getStringExtra(TERMUX_SERVICE.EXTRA_WORKDIR);
|
||||
ExecutionCommand executionCommand = new ExecutionCommand(getNextExecutionId());
|
||||
|
||||
PendingIntent pendingIntent = intent.getParcelableExtra(TERMUX_SERVICE.EXTRA_PENDING_INTENT);
|
||||
executionCommand.executableUri = intent.getData();
|
||||
|
||||
int sessionAction = TextDataUtils.getIntStoredAsStringFromBundle(intent.getExtras(),
|
||||
TERMUX_SERVICE.EXTRA_SESSION_ACTION, TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY);
|
||||
if(executionCommand.executableUri != null) {
|
||||
executionCommand.executable = executionCommand.executableUri.getPath();
|
||||
executionCommand.arguments = intent.getStringArrayExtra(TERMUX_SERVICE.EXTRA_ARGUMENTS);
|
||||
}
|
||||
|
||||
if (intent.getBooleanExtra(TERMUX_SERVICE.EXTRA_BACKGROUND, false)) {
|
||||
executeBackgroundCommand(executablePath, arguments, cwd, pendingIntent);
|
||||
executionCommand.workingDirectory = intent.getStringExtra(TERMUX_SERVICE.EXTRA_WORKDIR);
|
||||
executionCommand.inBackground = intent.getBooleanExtra(TERMUX_SERVICE.EXTRA_BACKGROUND, false);
|
||||
executionCommand.isFailsafe = intent.getBooleanExtra(TERMUX_ACTIVITY.ACTION_FAILSAFE_SESSION, false);
|
||||
executionCommand.sessionAction = intent.getStringExtra(TERMUX_SERVICE.EXTRA_SESSION_ACTION);
|
||||
executionCommand.commandLabel = TextDataUtils.getDefaultIfNull(intent.getStringExtra(TERMUX_SERVICE.EXTRA_COMMAND_LABEL), "Execution Intent Command");
|
||||
executionCommand.commandDescription = intent.getStringExtra(TERMUX_SERVICE.EXTRA_COMMAND_DESCRIPTION);
|
||||
executionCommand.commandHelp = intent.getStringExtra(TERMUX_SERVICE.EXTRA_COMMAND_HELP);
|
||||
executionCommand.pluginAPIHelp = intent.getStringExtra(TERMUX_SERVICE.EXTRA_PLUGIN_API_HELP);
|
||||
executionCommand.isPluginExecutionCommand = true;
|
||||
executionCommand.pluginPendingIntent = intent.getParcelableExtra(TERMUX_SERVICE.EXTRA_PENDING_INTENT);
|
||||
|
||||
if (executionCommand.inBackground) {
|
||||
executeBackgroundCommand(executionCommand);
|
||||
} else {
|
||||
executeForegroundCommand(intent, executablePath, arguments, cwd, sessionAction);
|
||||
executeForegroundCommand(executionCommand);
|
||||
}
|
||||
}
|
||||
|
||||
/** Execute a shell command in background with {@link BackgroundJob}. */
|
||||
private void executeBackgroundCommand(String executablePath, String[] arguments, String cwd, PendingIntent pendingIntent) {
|
||||
private void executeBackgroundCommand(ExecutionCommand executionCommand) {
|
||||
Logger.logDebug(LOG_TAG, "Starting background command");
|
||||
|
||||
final String pendingIntentCreator;
|
||||
if(pendingIntent != null) pendingIntentCreator = pendingIntent.getCreatorPackage(); else pendingIntentCreator = null;
|
||||
Logger.logDebug(LOG_TAG, executionCommand.toString());
|
||||
|
||||
PluginUtils.dumpExecutionIntentToLog(Log.DEBUG, LOG_TAG, null, executablePath, Arrays.asList(arguments), cwd, true, new HashMap<String, Object>() {{
|
||||
put("pendingIntentCreator", pendingIntentCreator);
|
||||
}});
|
||||
|
||||
BackgroundJob task = new BackgroundJob(cwd, executablePath, arguments, this, pendingIntent);
|
||||
BackgroundJob task = new BackgroundJob(executionCommand, this);
|
||||
|
||||
mBackgroundTasks.add(task);
|
||||
updateNotification();
|
||||
@@ -319,22 +328,20 @@ public final class TermuxService extends Service {
|
||||
}
|
||||
|
||||
/** Execute a shell command in a foreground terminal session. */
|
||||
private void executeForegroundCommand(Intent intent, String executablePath, String[] arguments, String cwd, int sessionAction) {
|
||||
private void executeForegroundCommand(ExecutionCommand executionCommand) {
|
||||
Logger.logDebug(LOG_TAG, "Starting foreground command");
|
||||
|
||||
boolean failsafe = intent.getBooleanExtra(TERMUX_ACTIVITY.ACTION_FAILSAFE_SESSION, false);
|
||||
if(!executionCommand.setState(ExecutionState.EXECUTING))
|
||||
return;
|
||||
|
||||
PluginUtils.dumpExecutionIntentToLog(Log.DEBUG, LOG_TAG, null, executablePath, Arrays.asList(arguments), cwd, false, new HashMap<String, Object>() {{
|
||||
put("sessionAction", sessionAction);
|
||||
put("failsafe", failsafe);
|
||||
}});
|
||||
Logger.logDebug(LOG_TAG, executionCommand.toString());
|
||||
|
||||
TerminalSession newSession = createTerminalSession(executablePath, arguments, cwd, failsafe);
|
||||
TerminalSession newSession = createTerminalSession(executionCommand.executable, executionCommand.arguments, executionCommand.workingDirectory, executionCommand.isFailsafe);
|
||||
|
||||
// Transform executable path to session name, e.g. "/bin/do-something.sh" => "do something.sh".
|
||||
if (executablePath != null) {
|
||||
int lastSlash = executablePath.lastIndexOf('/');
|
||||
String name = (lastSlash == -1) ? executablePath : executablePath.substring(lastSlash + 1);
|
||||
if (executionCommand.executable != null) {
|
||||
int lastSlash = executionCommand.executable.lastIndexOf('/');
|
||||
String name = (lastSlash == -1) ? executionCommand.executable : executionCommand.executable.substring(lastSlash + 1);
|
||||
name = name.replace('-', ' ');
|
||||
newSession.mSessionName = name;
|
||||
}
|
||||
@@ -344,7 +351,7 @@ public final class TermuxService extends Service {
|
||||
if(mTermuxSessionClient != null)
|
||||
mTermuxSessionClient.terminalSessionListNotifyUpdated();
|
||||
|
||||
handleSessionAction(sessionAction, newSession);
|
||||
handleSessionAction(TextDataUtils.getIntFromString(executionCommand.sessionAction, TERMUX_SERVICE.VALUE_EXTRA_SESSION_ACTION_SWITCH_TO_NEW_SESSION_AND_OPEN_ACTIVITY), newSession);
|
||||
}
|
||||
|
||||
private void setCurrentStoredSession(TerminalSession newSession) {
|
||||
@@ -390,16 +397,16 @@ public final class TermuxService extends Service {
|
||||
}
|
||||
|
||||
/** Create a terminal session. */
|
||||
public TerminalSession createTerminalSession(String executablePath, String[] arguments, String cwd, boolean failSafe) {
|
||||
public TerminalSession createTerminalSession(String executablePath, String[] arguments, String workingDirectory, boolean isFailSafe) {
|
||||
TermuxConstants.TERMUX_HOME_DIR.mkdirs();
|
||||
|
||||
if (cwd == null || cwd.isEmpty()) cwd = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
if (workingDirectory == null || workingDirectory.isEmpty()) workingDirectory = TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
|
||||
String[] env = BackgroundJob.buildEnvironment(failSafe, cwd);
|
||||
String[] env = BackgroundJob.buildEnvironment(isFailSafe, workingDirectory);
|
||||
boolean isLoginShell = false;
|
||||
|
||||
if (executablePath == null) {
|
||||
if (!failSafe) {
|
||||
if (!isFailSafe) {
|
||||
for (String shellBinary : new String[]{"login", "bash", "zsh"}) {
|
||||
File shellFile = new File(TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH, shellBinary);
|
||||
if (shellFile.canExecute()) {
|
||||
@@ -426,7 +433,7 @@ public final class TermuxService extends Service {
|
||||
args[0] = processName;
|
||||
if (processArgs.length > 1) System.arraycopy(processArgs, 1, args, 1, processArgs.length - 1);
|
||||
|
||||
TerminalSession session = new TerminalSession(executablePath, cwd, args, env, getTermuxSessionClient());
|
||||
TerminalSession session = new TerminalSession(executablePath, workingDirectory, args, env, getTermuxSessionClient());
|
||||
mTerminalSessions.add(session);
|
||||
updateNotification();
|
||||
|
||||
@@ -569,8 +576,8 @@ public final class TermuxService extends Service {
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,importance);
|
||||
channel.setDescription(channelDescription);
|
||||
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
manager.createNotificationChannel(channel);
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
/** Update the shown foreground service notification after making any changes that affect it. */
|
||||
@@ -593,4 +600,8 @@ public final class TermuxService extends Service {
|
||||
return mTerminalSessions;
|
||||
}
|
||||
|
||||
synchronized public static int getNextExecutionId() {
|
||||
return EXECUTION_ID++;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -182,7 +182,7 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
}, -1, null, -1, null, null);
|
||||
}
|
||||
|
||||
public void addNewSession(boolean failSafe, String sessionName) {
|
||||
public void addNewSession(boolean isFailSafe, String sessionName) {
|
||||
if (mActivity.getTermuxService().getSessions().size() >= MAX_SESSIONS) {
|
||||
new AlertDialog.Builder(mActivity).setTitle(R.string.max_terminals_reached_title).setMessage(R.string.max_terminals_reached_message)
|
||||
.setPositiveButton(android.R.string.ok, null).show();
|
||||
@@ -196,7 +196,7 @@ public class TermuxSessionClient extends TermuxSessionClientBase {
|
||||
workingDirectory = currentSession.getCwd();
|
||||
}
|
||||
|
||||
TerminalSession newSession = mActivity.getTermuxService().createTerminalSession(null, null, workingDirectory, failSafe);
|
||||
TerminalSession newSession = mActivity.getTermuxService().createTerminalSession(null, null, workingDirectory, isFailSafe);
|
||||
if (sessionName != null) {
|
||||
newSession.mSessionName = sessionName;
|
||||
}
|
||||
|
Reference in New Issue
Block a user