mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-09 12:04:03 +08:00
Changed!: Move Termux specific classes to com.termux.shared.termux package
This will allow segregation of Termux utils/classes from general ones and also allow easier management of GPLv3 License for Termux classes
This commit is contained in:
@@ -16,7 +16,7 @@ import com.termux.shared.models.ResultConfig;
|
||||
import com.termux.shared.models.ResultData;
|
||||
import com.termux.shared.models.errors.FunctionErrno;
|
||||
import com.termux.shared.models.errors.ResultSenderErrno;
|
||||
import com.termux.shared.termux.AndroidUtils;
|
||||
import com.termux.shared.android.AndroidUtils;
|
||||
import com.termux.shared.termux.TermuxConstants.RESULT_SENDER;
|
||||
|
||||
public class ResultSender {
|
||||
|
@@ -1,269 +0,0 @@
|
||||
package com.termux.shared.shell;
|
||||
|
||||
import android.content.Context;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.termux.shared.R;
|
||||
import com.termux.shared.models.ExecutionCommand;
|
||||
import com.termux.shared.models.ResultData;
|
||||
import com.termux.shared.models.errors.Errno;
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.terminal.TerminalSession;
|
||||
import com.termux.terminal.TerminalSessionClient;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A class that maintains info for foreground Termux sessions.
|
||||
* It also provides a way to link each {@link TerminalSession} with the {@link ExecutionCommand}
|
||||
* that started it.
|
||||
*/
|
||||
public class TermuxSession {
|
||||
|
||||
private final TerminalSession mTerminalSession;
|
||||
private final ExecutionCommand mExecutionCommand;
|
||||
private final TermuxSessionClient mTermuxSessionClient;
|
||||
private final boolean mSetStdoutOnExit;
|
||||
|
||||
private static final String LOG_TAG = "TermuxSession";
|
||||
|
||||
private TermuxSession(@NonNull final TerminalSession terminalSession, @NonNull final ExecutionCommand executionCommand,
|
||||
final TermuxSessionClient termuxSessionClient, final boolean setStdoutOnExit) {
|
||||
this.mTerminalSession = terminalSession;
|
||||
this.mExecutionCommand = executionCommand;
|
||||
this.mTermuxSessionClient = termuxSessionClient;
|
||||
this.mSetStdoutOnExit = setStdoutOnExit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start execution of an {@link ExecutionCommand} with {@link Runtime#exec(String[], String[], File)}.
|
||||
*
|
||||
* The {@link ExecutionCommand#executable}, must be set, {@link ExecutionCommand#commandLabel},
|
||||
* {@link ExecutionCommand#arguments} and {@link ExecutionCommand#workingDirectory} may optionally
|
||||
* be set.
|
||||
*
|
||||
* If {@link ExecutionCommand#executable} is {@code null}, then a default shell is automatically
|
||||
* chosen.
|
||||
*
|
||||
* @param context The {@link Context} for operations.
|
||||
* @param executionCommand The {@link ExecutionCommand} containing the information for execution command.
|
||||
* @param terminalSessionClient The {@link TerminalSessionClient} interface implementation.
|
||||
* @param termuxSessionClient The {@link TermuxSessionClient} interface implementation.
|
||||
* @param shellEnvironmentClient The {@link ShellEnvironmentClient} interface implementation.
|
||||
* @param sessionName The optional {@link TerminalSession} name.
|
||||
* @param setStdoutOnExit If set to {@code true}, then the {@link ResultData#stdout}
|
||||
* available in the {@link TermuxSessionClient#onTermuxSessionExited(TermuxSession)}
|
||||
* callback will be set to the {@link TerminalSession} transcript. The session
|
||||
* transcript will contain both stdout and stderr combined, basically
|
||||
* anything sent to the the pseudo terminal /dev/pts, including PS1 prefixes.
|
||||
* Set this to {@code true} only if the session transcript is required,
|
||||
* since this requires extra processing to get it.
|
||||
* @return Returns the {@link TermuxSession}. This will be {@code null} if failed to start the execution command.
|
||||
*/
|
||||
public static TermuxSession execute(@NonNull final Context context, @NonNull ExecutionCommand executionCommand,
|
||||
@NonNull final TerminalSessionClient terminalSessionClient, final TermuxSessionClient termuxSessionClient,
|
||||
@NonNull final ShellEnvironmentClient shellEnvironmentClient,
|
||||
final String sessionName, final boolean setStdoutOnExit) {
|
||||
if (executionCommand.workingDirectory == null || executionCommand.workingDirectory.isEmpty())
|
||||
executionCommand.workingDirectory = shellEnvironmentClient.getDefaultWorkingDirectoryPath();
|
||||
if (executionCommand.workingDirectory.isEmpty())
|
||||
executionCommand.workingDirectory = "/";
|
||||
|
||||
String[] environment = shellEnvironmentClient.buildEnvironment(context, executionCommand.isFailsafe, executionCommand.workingDirectory);
|
||||
|
||||
String defaultBinPath = shellEnvironmentClient.getDefaultBinPath();
|
||||
if (defaultBinPath.isEmpty())
|
||||
defaultBinPath = "/system/bin";
|
||||
|
||||
boolean isLoginShell = false;
|
||||
if (executionCommand.executable == null) {
|
||||
if (!executionCommand.isFailsafe) {
|
||||
for (String shellBinary : new String[]{"login", "bash", "zsh"}) {
|
||||
File shellFile = new File(defaultBinPath, shellBinary);
|
||||
if (shellFile.canExecute()) {
|
||||
executionCommand.executable = shellFile.getAbsolutePath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (executionCommand.executable == null) {
|
||||
// Fall back to system shell as last resort:
|
||||
// Do not start a login shell since ~/.profile may cause startup failure if its invalid.
|
||||
// /system/bin/sh is provided by mksh (not toybox) and does load .mkshrc but for android its set
|
||||
// to /system/etc/mkshrc even though its default is ~/.mkshrc.
|
||||
// So /system/etc/mkshrc must still be valid for failsafe session to start properly.
|
||||
// https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:external/mksh/src/main.c;l=663
|
||||
// https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:external/mksh/src/main.c;l=41
|
||||
// https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:external/mksh/Android.bp;l=114
|
||||
executionCommand.executable = "/system/bin/sh";
|
||||
} else {
|
||||
isLoginShell = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String[] processArgs = shellEnvironmentClient.setupProcessArgs(executionCommand.executable, executionCommand.arguments);
|
||||
|
||||
executionCommand.executable = processArgs[0];
|
||||
String processName = (isLoginShell ? "-" : "") + ShellUtils.getExecutableBasename(executionCommand.executable);
|
||||
|
||||
String[] arguments = new String[processArgs.length];
|
||||
arguments[0] = processName;
|
||||
if (processArgs.length > 1) System.arraycopy(processArgs, 1, arguments, 1, processArgs.length - 1);
|
||||
|
||||
executionCommand.arguments = arguments;
|
||||
|
||||
if (executionCommand.commandLabel == null)
|
||||
executionCommand.commandLabel = processName;
|
||||
|
||||
if (!executionCommand.setState(ExecutionCommand.ExecutionState.EXECUTING)) {
|
||||
executionCommand.setStateFailed(Errno.ERRNO_FAILED.getCode(), context.getString(R.string.error_failed_to_execute_termux_session_command, executionCommand.getCommandIdAndLabelLogString()));
|
||||
TermuxSession.processTermuxSessionResult(null, executionCommand);
|
||||
return null;
|
||||
}
|
||||
|
||||
Logger.logDebugExtended(LOG_TAG, executionCommand.toString());
|
||||
|
||||
Logger.logDebug(LOG_TAG, "Running \"" + executionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession");
|
||||
TerminalSession terminalSession = new TerminalSession(executionCommand.executable, executionCommand.workingDirectory, executionCommand.arguments, environment, executionCommand.terminalTranscriptRows, terminalSessionClient);
|
||||
|
||||
if (sessionName != null) {
|
||||
terminalSession.mSessionName = sessionName;
|
||||
}
|
||||
|
||||
return new TermuxSession(terminalSession, executionCommand, termuxSessionClient, setStdoutOnExit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that this {@link TermuxSession} has finished. This should be called when
|
||||
* {@link TerminalSessionClient#onSessionFinished(TerminalSession)} callback is received by the caller.
|
||||
*
|
||||
* If the processes has finished, then sets {@link ResultData#stdout}, {@link ResultData#stderr}
|
||||
* and {@link ResultData#exitCode} for the {@link #mExecutionCommand} of the {@code termuxTask}
|
||||
* and then calls {@link #processTermuxSessionResult(TermuxSession, ExecutionCommand)} to process the result}.
|
||||
*
|
||||
*/
|
||||
public void finish() {
|
||||
// If process is still running, then ignore the call
|
||||
if (mTerminalSession.isRunning()) return;
|
||||
|
||||
int exitCode = mTerminalSession.getExitStatus();
|
||||
|
||||
if (exitCode == 0)
|
||||
Logger.logDebug(LOG_TAG, "The \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession exited normally");
|
||||
else
|
||||
Logger.logDebug(LOG_TAG, "The \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession exited with code: " + exitCode);
|
||||
|
||||
// If the execution command has already failed, like SIGKILL was sent, then don't continue
|
||||
if (mExecutionCommand.isStateFailed()) {
|
||||
Logger.logDebug(LOG_TAG, "Ignoring setting \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession state to ExecutionState.EXECUTED and processing results since it has already failed");
|
||||
return;
|
||||
}
|
||||
|
||||
mExecutionCommand.resultData.exitCode = exitCode;
|
||||
|
||||
if (this.mSetStdoutOnExit)
|
||||
mExecutionCommand.resultData.stdout.append(ShellUtils.getTerminalSessionTranscriptText(mTerminalSession, true, false));
|
||||
|
||||
if (!mExecutionCommand.setState(ExecutionCommand.ExecutionState.EXECUTED))
|
||||
return;
|
||||
|
||||
TermuxSession.processTermuxSessionResult(this, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill this {@link TermuxSession} by sending a {@link OsConstants#SIGILL} to its {@link #mTerminalSession}
|
||||
* if its still executing.
|
||||
*
|
||||
* @param context The {@link Context} for operations.
|
||||
* @param processResult If set to {@code true}, then the {@link #processTermuxSessionResult(TermuxSession, ExecutionCommand)}
|
||||
* will be called to process the failure.
|
||||
*/
|
||||
public void killIfExecuting(@NonNull final Context context, boolean processResult) {
|
||||
// If execution command has already finished executing, then no need to process results or send SIGKILL
|
||||
if (mExecutionCommand.hasExecuted()) {
|
||||
Logger.logDebug(LOG_TAG, "Ignoring sending SIGKILL to \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession since it has already finished executing");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.logDebug(LOG_TAG, "Send SIGKILL to \"" + mExecutionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession");
|
||||
if (mExecutionCommand.setStateFailed(Errno.ERRNO_FAILED.getCode(), context.getString(R.string.error_sending_sigkill_to_process))) {
|
||||
if (processResult) {
|
||||
mExecutionCommand.resultData.exitCode = 137; // SIGKILL
|
||||
|
||||
// Get whatever output has been set till now in case its needed
|
||||
if (this.mSetStdoutOnExit)
|
||||
mExecutionCommand.resultData.stdout.append(ShellUtils.getTerminalSessionTranscriptText(mTerminalSession, true, false));
|
||||
|
||||
TermuxSession.processTermuxSessionResult(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Send SIGKILL to process
|
||||
mTerminalSession.finishIfRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the results of {@link TermuxSession} or {@link ExecutionCommand}.
|
||||
*
|
||||
* Only one of {@code termuxSession} and {@code executionCommand} must be set.
|
||||
*
|
||||
* If the {@code termuxSession} and its {@link #mTermuxSessionClient} are not {@code null},
|
||||
* then the {@link TermuxSession.TermuxSessionClient#onTermuxSessionExited(TermuxSession)}
|
||||
* callback will be called.
|
||||
*
|
||||
* @param termuxSession The {@link TermuxSession}, which should be set if
|
||||
* {@link #execute(Context, ExecutionCommand, TerminalSessionClient, TermuxSessionClient, ShellEnvironmentClient, String, boolean)}
|
||||
* successfully started the process.
|
||||
* @param executionCommand The {@link ExecutionCommand}, which should be set if
|
||||
* {@link #execute(Context, ExecutionCommand, TerminalSessionClient, TermuxSessionClient, ShellEnvironmentClient, String, boolean)}
|
||||
* failed to start the process.
|
||||
*/
|
||||
private static void processTermuxSessionResult(final TermuxSession termuxSession, ExecutionCommand executionCommand) {
|
||||
if (termuxSession != null)
|
||||
executionCommand = termuxSession.mExecutionCommand;
|
||||
|
||||
if (executionCommand == null) return;
|
||||
|
||||
if (executionCommand.shouldNotProcessResults()) {
|
||||
Logger.logDebug(LOG_TAG, "Ignoring duplicate call to process \"" + executionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession result");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.logDebug(LOG_TAG, "Processing \"" + executionCommand.getCommandIdAndLabelLogString() + "\" TermuxSession result");
|
||||
|
||||
if (termuxSession != null && termuxSession.mTermuxSessionClient != null) {
|
||||
termuxSession.mTermuxSessionClient.onTermuxSessionExited(termuxSession);
|
||||
} else {
|
||||
// If a callback is not set and execution command didn't fail, then we set success state now
|
||||
// Otherwise, the callback host can set it himself when its done with the termuxSession
|
||||
if (!executionCommand.isStateFailed())
|
||||
executionCommand.setState(ExecutionCommand.ExecutionState.SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
public TerminalSession getTerminalSession() {
|
||||
return mTerminalSession;
|
||||
}
|
||||
|
||||
public ExecutionCommand getExecutionCommand() {
|
||||
return mExecutionCommand;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public interface TermuxSessionClient {
|
||||
|
||||
/**
|
||||
* Callback function for when {@link TermuxSession} exits.
|
||||
*
|
||||
* @param termuxSession The {@link TermuxSession} that exited.
|
||||
*/
|
||||
void onTermuxSessionExited(TermuxSession termuxSession);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
package com.termux.shared.shell;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class TermuxShellEnvironmentClient implements ShellEnvironmentClient {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getDefaultWorkingDirectoryPath() {
|
||||
return TermuxShellUtils.getDefaultWorkingDirectoryPath();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getDefaultBinPath() {
|
||||
return TermuxShellUtils.getDefaultBinPath();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String[] buildEnvironment(Context currentPackageContext, boolean isFailSafe, String workingDirectory) {
|
||||
return TermuxShellUtils.buildEnvironment(currentPackageContext, isFailSafe, workingDirectory);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String[] setupProcessArgs(@NonNull String fileToExecute, String[] arguments) {
|
||||
return TermuxShellUtils.setupProcessArgs(fileToExecute, arguments);
|
||||
}
|
||||
|
||||
}
|
@@ -1,205 +0,0 @@
|
||||
package com.termux.shared.shell;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.termux.shared.models.errors.Error;
|
||||
import com.termux.shared.termux.TermuxConstants;
|
||||
import com.termux.shared.file.FileUtils;
|
||||
import com.termux.shared.logger.Logger;
|
||||
import com.termux.shared.packages.PackageUtils;
|
||||
import com.termux.shared.termux.TermuxUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TermuxShellUtils {
|
||||
|
||||
public static String TERMUX_VERSION_NAME;
|
||||
public static String TERMUX_IS_DEBUGGABLE_BUILD;
|
||||
public static String TERMUX_APP_PID;
|
||||
public static String TERMUX_APK_RELEASE;
|
||||
|
||||
public static String TERMUX_API_VERSION_NAME;
|
||||
|
||||
public static String getDefaultWorkingDirectoryPath() {
|
||||
return TermuxConstants.TERMUX_HOME_DIR_PATH;
|
||||
}
|
||||
|
||||
public static String getDefaultBinPath() {
|
||||
return TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH;
|
||||
}
|
||||
|
||||
public static String[] buildEnvironment(Context currentPackageContext, boolean isFailSafe, String workingDirectory) {
|
||||
TermuxConstants.TERMUX_HOME_DIR.mkdirs();
|
||||
|
||||
if (workingDirectory == null || workingDirectory.isEmpty())
|
||||
workingDirectory = getDefaultWorkingDirectoryPath();
|
||||
|
||||
List<String> environment = new ArrayList<>();
|
||||
|
||||
loadTermuxEnvVariables(currentPackageContext);
|
||||
|
||||
if (TERMUX_VERSION_NAME != null)
|
||||
environment.add("TERMUX_VERSION=" + TERMUX_VERSION_NAME);
|
||||
if (TERMUX_IS_DEBUGGABLE_BUILD != null)
|
||||
environment.add("TERMUX_IS_DEBUGGABLE_BUILD=" + TERMUX_IS_DEBUGGABLE_BUILD);
|
||||
if (TERMUX_APP_PID != null)
|
||||
environment.add("TERMUX_APP_PID=" + TERMUX_APP_PID);
|
||||
if (TERMUX_APK_RELEASE != null)
|
||||
environment.add("TERMUX_APK_RELEASE=" + TERMUX_APK_RELEASE);
|
||||
|
||||
if (TERMUX_API_VERSION_NAME != null)
|
||||
environment.add("TERMUX_API_VERSION=" + TERMUX_API_VERSION_NAME);
|
||||
|
||||
environment.add("TERM=xterm-256color");
|
||||
environment.add("COLORTERM=truecolor");
|
||||
environment.add("HOME=" + TermuxConstants.TERMUX_HOME_DIR_PATH);
|
||||
environment.add("PREFIX=" + TermuxConstants.TERMUX_PREFIX_DIR_PATH);
|
||||
environment.add("BOOTCLASSPATH=" + System.getenv("BOOTCLASSPATH"));
|
||||
environment.add("ANDROID_ROOT=" + System.getenv("ANDROID_ROOT"));
|
||||
environment.add("ANDROID_DATA=" + System.getenv("ANDROID_DATA"));
|
||||
// EXTERNAL_STORAGE is needed for /system/bin/am to work on at least
|
||||
// Samsung S7 - see https://plus.google.com/110070148244138185604/posts/gp8Lk3aCGp3.
|
||||
environment.add("EXTERNAL_STORAGE=" + System.getenv("EXTERNAL_STORAGE"));
|
||||
|
||||
// These variables are needed if running on Android 10 and higher.
|
||||
addToEnvIfPresent(environment, "ANDROID_ART_ROOT");
|
||||
addToEnvIfPresent(environment, "DEX2OATBOOTCLASSPATH");
|
||||
addToEnvIfPresent(environment, "ANDROID_I18N_ROOT");
|
||||
addToEnvIfPresent(environment, "ANDROID_RUNTIME_ROOT");
|
||||
addToEnvIfPresent(environment, "ANDROID_TZDATA_ROOT");
|
||||
|
||||
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=" + workingDirectory);
|
||||
environment.add("TMPDIR=" + TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH);
|
||||
}
|
||||
|
||||
return environment.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static void addToEnvIfPresent(List<String> environment, String name) {
|
||||
String value = System.getenv(name);
|
||||
if (value != null) {
|
||||
environment.add(name + "=" + value);
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] setupProcessArgs(@NonNull 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
|
||||
// system /system/bin/sh. The system shell may vary and may not work at all due to LD_LIBRARY_PATH.
|
||||
// - A file with shebang, which we try to handle with e.g. /bin/foo -> $PREFIX/bin/foo.
|
||||
String interpreter = null;
|
||||
try {
|
||||
File file = new File(fileToExecute);
|
||||
try (FileInputStream in = new FileInputStream(file)) {
|
||||
byte[] buffer = new byte[256];
|
||||
int bytesRead = in.read(buffer);
|
||||
if (bytesRead > 4) {
|
||||
if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') {
|
||||
// Elf file, do nothing.
|
||||
} else if (buffer[0] == '#' && buffer[1] == '!') {
|
||||
// Try to parse shebang.
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 2; i < bytesRead; i++) {
|
||||
char c = (char) buffer[i];
|
||||
if (c == ' ' || c == '\n') {
|
||||
if (builder.length() == 0) {
|
||||
// Skip whitespace after shebang.
|
||||
} else {
|
||||
// End of shebang.
|
||||
String executable = builder.toString();
|
||||
if (executable.startsWith("/usr") || executable.startsWith("/bin")) {
|
||||
String[] parts = executable.split("/");
|
||||
String binary = parts[parts.length - 1];
|
||||
interpreter = TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH + "/" + binary;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No shebang and no ELF, use standard shell.
|
||||
interpreter = TermuxConstants.TERMUX_BIN_PREFIX_DIR_PATH + "/sh";
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore.
|
||||
}
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
if (interpreter != null) result.add(interpreter);
|
||||
result.add(fileToExecute);
|
||||
if (arguments != null) Collections.addAll(result, arguments);
|
||||
return result.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public static void clearTermuxTMPDIR(boolean onlyIfExists) {
|
||||
// Existence check before clearing may be required since clearDirectory() will automatically
|
||||
// re-create empty directory if doesn't exist, which should not be done for things like
|
||||
// termux-reset (d6eb5e35). Moreover, TMPDIR must be a directory and not a symlink, this can
|
||||
// also allow users who don't want TMPDIR to be cleared automatically on termux exit, since
|
||||
// it may remove files still being used by background processes (#1159).
|
||||
if(onlyIfExists && !FileUtils.directoryFileExists(TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH, false))
|
||||
return;
|
||||
|
||||
Error error;
|
||||
error = FileUtils.clearDirectory("$TMPDIR", FileUtils.getCanonicalPath(TermuxConstants.TERMUX_TMP_PREFIX_DIR_PATH, null));
|
||||
if (error != null) {
|
||||
Logger.logErrorExtended(error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadTermuxEnvVariables(Context currentPackageContext) {
|
||||
String termuxAPKReleaseOld = TERMUX_APK_RELEASE;
|
||||
TERMUX_VERSION_NAME = TERMUX_IS_DEBUGGABLE_BUILD = TERMUX_APP_PID = TERMUX_APK_RELEASE = null;
|
||||
|
||||
// Check if Termux app is installed and not disabled
|
||||
if (TermuxUtils.isTermuxAppInstalled(currentPackageContext) == null) {
|
||||
// This function may be called by a different package like a plugin, so we get version for Termux package via its context
|
||||
Context termuxPackageContext = TermuxUtils.getTermuxPackageContext(currentPackageContext);
|
||||
if (termuxPackageContext != null) {
|
||||
TERMUX_VERSION_NAME = PackageUtils.getVersionNameForPackage(termuxPackageContext);
|
||||
TERMUX_IS_DEBUGGABLE_BUILD = PackageUtils.isAppForPackageADebuggableBuild(termuxPackageContext) ? "1" : "0";
|
||||
|
||||
TERMUX_APP_PID = TermuxUtils.getTermuxAppPID(currentPackageContext);
|
||||
|
||||
// Getting APK signature is a slightly expensive operation, so do it only when needed
|
||||
if (termuxAPKReleaseOld == null) {
|
||||
String signingCertificateSHA256Digest = PackageUtils.getSigningCertificateSHA256DigestForPackage(termuxPackageContext);
|
||||
if (signingCertificateSHA256Digest != null)
|
||||
TERMUX_APK_RELEASE = TermuxUtils.getAPKRelease(signingCertificateSHA256Digest).replaceAll("[^a-zA-Z]", "_").toUpperCase();
|
||||
} else {
|
||||
TERMUX_APK_RELEASE = termuxAPKReleaseOld;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TERMUX_API_VERSION_NAME = null;
|
||||
|
||||
// Check if Termux:API app is installed and not disabled
|
||||
if (TermuxUtils.isTermuxAPIAppInstalled(currentPackageContext) == null) {
|
||||
// This function may be called by a different package like a plugin, so we get version for Termux:API package via its context
|
||||
Context termuxAPIPackageContext = TermuxUtils.getTermuxAPIPackageContext(currentPackageContext);
|
||||
if (termuxAPIPackageContext != null)
|
||||
TERMUX_API_VERSION_NAME = PackageUtils.getVersionNameForPackage(termuxAPIPackageContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user