mirror of
https://github.com/termux/termux-app
synced 2024-06-17 22:57:08 +00:00
Added|Fixed: NativeShell now works, fixed the Termux task notification not updating for NativeShell tasks. Added taskFinished callback for plugins and signalTask method for plugins to call.
This commit is contained in:
parent
44267d6582
commit
f459ee481e
|
@ -14,6 +14,7 @@ import android.os.Build;
|
|||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
@ -291,7 +292,7 @@ public final class TermuxService extends Service implements AppShell.AppShellCli
|
|||
|
||||
List<NativeShell> termuxNativeTasks = new ArrayList<>(mShellManager.mTermuxNativeTasks);
|
||||
for (int i = 0; i < termuxNativeTasks.size(); i++) {
|
||||
termuxNativeTasks.get(i).kill();
|
||||
termuxNativeTasks.get(i).kill(Process.SIGNAL_KILL);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pendingPluginExecutionCommands.size(); i++) {
|
||||
|
@ -442,7 +443,14 @@ public final class TermuxService extends Service implements AppShell.AppShellCli
|
|||
});
|
||||
client.terminated(exitCode, error);
|
||||
}, environment);
|
||||
shell[0].execute();
|
||||
mShellManager.mTermuxNativeTasks.add(shell[0]);
|
||||
|
||||
if (shell[0].execute()) {
|
||||
updateNotification();
|
||||
} else {
|
||||
// gets removed automatically by the callback
|
||||
return null;
|
||||
}
|
||||
return shell[0];
|
||||
}
|
||||
|
||||
|
|
|
@ -35,15 +35,13 @@ import com.termux.shared.net.socket.local.PeerCred;
|
|||
import com.termux.shared.shell.command.ExecutionCommand;
|
||||
import com.termux.shared.shell.command.runner.nativerunner.NativeShell;
|
||||
import com.termux.shared.termux.plugins.TermuxPluginUtils;
|
||||
import com.termux.shared.termux.shell.TermuxShellEnvironmentClient;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -284,13 +282,24 @@ public class PluginService extends Service
|
|||
public Task runTask(String commandPath, String[] arguments, ParcelFileDescriptor stdin, String workdir, String[] environment) {
|
||||
externalAppsOrThrow();
|
||||
if (commandPath == null) throw new NullPointerException("Passed commandPath is null");
|
||||
if (workdir == null) throw new NullPointerException("Passed workdir is null");
|
||||
if (stdin == null) throw new NullPointerException("Passed stdin is null");
|
||||
Plugin p = checkClient();
|
||||
BinderUtils.enforceRunCommandPermission(PluginService.this);
|
||||
|
||||
|
||||
|
||||
|
||||
List<String> env = (environment != null) ? Arrays.asList(environment) : new ArrayList<>();
|
||||
env.addAll(Arrays.asList(new TermuxShellEnvironmentClient().
|
||||
buildEnvironment(PluginService.this,
|
||||
false,
|
||||
workdir)));
|
||||
String[] realEnvironment = env.toArray(new String[0]);
|
||||
|
||||
|
||||
final Object sync = new Object();
|
||||
final RuntimeException[] ex = new RuntimeException[1];
|
||||
final Exception[] ex = new Exception[1];
|
||||
final boolean[] finished = {false};
|
||||
final NativeShell[] shell = new NativeShell[1];
|
||||
// create pipes
|
||||
|
@ -327,7 +336,8 @@ public class PluginService extends Service
|
|||
}
|
||||
in[1] = pipes[0];
|
||||
out[1] = pipes[1];
|
||||
|
||||
|
||||
// start the Task on the main thread, TermuxService is not synchronized itself
|
||||
mMainThreadHandler.post(() -> {
|
||||
TermuxService s = mTermuxService;
|
||||
if (s == null) {
|
||||
|
@ -346,31 +356,27 @@ public class PluginService extends Service
|
|||
cmd.stdinFD = stdin;
|
||||
cmd.stdoutFD = out[0];
|
||||
cmd.stderrFD = out[1];
|
||||
/*
|
||||
try {
|
||||
ParcelFileDescriptor od = out[0].dup();
|
||||
new Thread(() -> {
|
||||
|
||||
shell[0] = s.executeNativeShell(cmd, realEnvironment, (exitCode, error) -> {
|
||||
if (error != null) {
|
||||
ex[0] = error;
|
||||
} else {
|
||||
p.tasks.remove(shell[0].getPid());
|
||||
try {
|
||||
BufferedWriter w = new BufferedWriter(new FileWriter(od.getFileDescriptor()));
|
||||
w.write("test");
|
||||
w.flush();
|
||||
w.close();
|
||||
} catch (Exception ignored) {ignored.printStackTrace();}
|
||||
}).start();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
shell[0] = s.executeNativeShell(cmd, environment, (exitCode, error) -> {
|
||||
try {
|
||||
Logger.logDebug("NativeShell", "exit: "+exitCode);
|
||||
// TODO callback
|
||||
} catch (Exception ignored) {}
|
||||
p.callback.taskFinished(shell[0].getPid(), exitCode);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
});
|
||||
p.tasks.put(shell[0].getPid(), shell[0]);
|
||||
if (shell[0] != null) {
|
||||
p.tasks.put(shell[0].getPid(), shell[0]);
|
||||
} else {
|
||||
while (ex[0] == null) {
|
||||
// wait until the exception is caught if the Task could not be started
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
}
|
||||
synchronized (sync) {
|
||||
finished[0] = true;
|
||||
sync.notifyAll();
|
||||
|
@ -411,7 +417,7 @@ public class PluginService extends Service
|
|||
try {
|
||||
in[1].close();
|
||||
} catch (IOException ignored) {}
|
||||
throw ex[0];
|
||||
throw new RuntimeException(ex[0]);
|
||||
}
|
||||
|
||||
Task t = new Task();
|
||||
|
@ -421,7 +427,22 @@ public class PluginService extends Service
|
|||
return t;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean signalTask(int pid, int signal) {
|
||||
Plugin p = checkClient();
|
||||
BinderUtils.enforceRunCommandPermission(PluginService.this);
|
||||
|
||||
// only allow to signal processes that were started as Tasks by the plugin
|
||||
NativeShell shell = p.tasks.get(pid);
|
||||
if (shell != null) {
|
||||
shell.kill(signal);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void listenOnSocketFile(String name) {
|
||||
externalAppsOrThrow();
|
||||
|
|
|
@ -34,7 +34,13 @@ interface IPluginCallback {
|
|||
void socketConnection(String sockname, in ParcelFileDescriptor connection) = 2;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets called when a started Task exits.
|
||||
*
|
||||
* @param pid The pid of the task that exited.
|
||||
* @param code The exit code of the Task. Negative values indicate the Task was killed by a signal. The signal number is then {@code -code}.
|
||||
*/
|
||||
void taskFinished(int pid, int code) = 3;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -43,17 +43,33 @@ interface IPluginService {
|
|||
|
||||
/**
|
||||
* Runs a command in a Termux task in the background.
|
||||
* stdin, commandPath and workdir are required parameters.
|
||||
* stdin, commandPath and workdir are required parameters.<br>
|
||||
* When a Task exists, the {@link com.termux.plugin_aidl.IPluginCallback#taskFinished} callback gets invoked.
|
||||
*
|
||||
* @param commandPath The full absolute path of the command binary to run.
|
||||
* @param arguments The command line arguments for the command. The first argument should be the same as {@code commandPath} (this fill be the 0th argument).
|
||||
* @param stdin The {@link android.os.ParcelFileDescriptor} used for the standard input of the command. You can e.g. create a pipe and use the read end here.
|
||||
* @param workdir The working directory of the command, also as an absolute path.
|
||||
* @param environment Additional environment variables for the command. Can be {@code null}.
|
||||
* @return A {@link com.termux.plugin_aidl.Task} that represents the running Task. It contains pipes for reading stdout and stderr.
|
||||
*/
|
||||
Task runTask(String commandPath, in String[] arguments, in ParcelFileDescriptor stdin, String workdir, in String[] environment) = 3;
|
||||
|
||||
/**
|
||||
* Send a signal to a Task.
|
||||
* @param pid The pid of the Task to kill.
|
||||
* @param signal The signal number to use. Using {@code kill -l} in bash and other shells lists the signals with their numbers.
|
||||
* @return Returns true if there was a Task with this pid, false if there was none.
|
||||
*/
|
||||
boolean signalTask(int pid, int signal) = 4;
|
||||
|
||||
/**
|
||||
* This creates a socket file with name under {@link com.termux.shared.termux.TermuxConstants#TERMUX_PLUGINS_DIR_PATH}/<package name of caller>.
|
||||
* Connections are transferred to the plugin via the {@link com.termux.plugin_aidl.IPluginService#socketConnection} method.
|
||||
*
|
||||
* @param name Name of the socket file.
|
||||
*/
|
||||
void listenOnSocketFile(String name) = 4;
|
||||
void listenOnSocketFile(String name) = 5;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -62,7 +78,7 @@ interface IPluginService {
|
|||
* @param name Name of the file.
|
||||
* @þaram mode Mode to use.
|
||||
*/
|
||||
ParcelFileDescriptor openFile(String name, String mode) = 5;
|
||||
ParcelFileDescriptor openFile(String name, String mode) = 6;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
package com.termux.shared.shell.command.runner.nativerunner;
|
||||
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.termux.shared.shell.command.ExecutionCommand;
|
||||
import com.termux.terminal.JNI;
|
||||
|
||||
|
@ -42,7 +39,7 @@ public final class NativeShell
|
|||
void terminated(int exitCode, Exception error);
|
||||
}
|
||||
|
||||
public synchronized void execute() {
|
||||
public synchronized boolean execute() {
|
||||
try {
|
||||
pid = JNI.createTask(exe.executable, exe.workingDirectory, exe.arguments, env, exe.stdinFD.getFd(), exe.stdoutFD.getFd(), exe.stderrFD.getFd());
|
||||
new Thread(() -> {
|
||||
|
@ -50,7 +47,8 @@ public final class NativeShell
|
|||
client.terminated(exit, null);
|
||||
pid = -1;
|
||||
}).start();
|
||||
} catch (RuntimeException e) {
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
client.terminated(0, e);
|
||||
} finally {
|
||||
// close the ParcelFileDescriptors
|
||||
|
@ -64,11 +62,12 @@ public final class NativeShell
|
|||
exe.stderrFD.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized void kill() {
|
||||
public synchronized void kill(int signal) {
|
||||
if (pid != -1)
|
||||
Process.killProcess(pid);
|
||||
Process.sendSignal(pid, signal);
|
||||
}
|
||||
|
||||
public synchronized int getPid() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user