mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-07 03:05:18 +08:00
Start work on background jobs
This commit is contained in:
@@ -7,55 +7,71 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A background job launched by Termux.
|
* A background job launched by Termux.
|
||||||
*/
|
*/
|
||||||
public final class BackgroundJob {
|
public final class BackgroundJob {
|
||||||
|
|
||||||
private static final String LOG_TAG = "termux-background";
|
private static final String LOG_TAG = "termux-job";
|
||||||
|
|
||||||
final Process mProcess;
|
final Process mProcess;
|
||||||
|
|
||||||
public BackgroundJob(File cwd, File fileToExecute, String[] args) throws IOException {
|
public BackgroundJob(String cwd, String fileToExecute, final String[] args) {
|
||||||
String[] env = buildEnvironment(false, cwd.getAbsolutePath());
|
String[] env = buildEnvironment(false, cwd);
|
||||||
|
if (cwd == null) cwd = TermuxService.HOME_PATH;
|
||||||
|
|
||||||
String[] progArray = new String[args.length + 1];
|
String[] modifiedArgs;
|
||||||
|
if (args == null) {
|
||||||
|
modifiedArgs = new String[]{fileToExecute};
|
||||||
|
} else {
|
||||||
|
modifiedArgs = new String[args.length + 1];
|
||||||
|
modifiedArgs[0] = fileToExecute;
|
||||||
|
System.arraycopy(args, 0, modifiedArgs, 1, args.length);
|
||||||
|
}
|
||||||
|
final String[] progArray = modifiedArgs;
|
||||||
|
|
||||||
mProcess = Runtime.getRuntime().exec(progArray, env, cwd);
|
final String processDescription = Arrays.toString(progArray);
|
||||||
|
|
||||||
new Thread() {
|
Process process;
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
process = Runtime.getRuntime().exec(progArray, env, new File(cwd));
|
||||||
while (true) {
|
} catch (IOException e) {
|
||||||
try {
|
mProcess = null;
|
||||||
int exitCode = mProcess.waitFor();
|
// TODO: Visible error message?
|
||||||
if (exitCode == 0) {
|
Log.e(LOG_TAG, "Failed running background job: " + processDescription, e);
|
||||||
Log.i(LOG_TAG, "exited normally");
|
return;
|
||||||
return;
|
}
|
||||||
} else {
|
mProcess = process;
|
||||||
Log.i(LOG_TAG, "exited with exit code: " + exitCode);
|
final int pid = getPid(mProcess);
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// Ignore.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
|
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
Log.i(LOG_TAG, "[" + pid + "] starting: " + processDescription);
|
||||||
InputStream stdout = mProcess.getInputStream();
|
InputStream stdout = mProcess.getInputStream();
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout, StandardCharsets.UTF_8));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout, StandardCharsets.UTF_8));
|
||||||
String line;
|
String line;
|
||||||
try {
|
try {
|
||||||
// FIXME: Long lines.
|
// FIXME: Long lines.
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
Log.i(LOG_TAG, line);
|
Log.i(LOG_TAG, "[" + pid + "] stdout: " + line);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
Log.e(LOG_TAG, "Error reading output", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int exitCode = mProcess.waitFor();
|
||||||
|
if (exitCode == 0) {
|
||||||
|
Log.i(LOG_TAG, "[" + pid + "] exited normally");
|
||||||
|
} else {
|
||||||
|
Log.w(LOG_TAG, "[" + pid + "] exited with code: " + exitCode);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
// Ignore.
|
// Ignore.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +87,7 @@ public final class BackgroundJob {
|
|||||||
try {
|
try {
|
||||||
// FIXME: Long lines.
|
// FIXME: Long lines.
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
Log.e(LOG_TAG, line);
|
Log.i(LOG_TAG, "[" + pid + "] stderr: " + line);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Ignore.
|
// Ignore.
|
||||||
@@ -80,7 +96,7 @@ public final class BackgroundJob {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] buildEnvironment(boolean failSafe, String cwd) {
|
public static String[] buildEnvironment(boolean failSafe, String cwd) {
|
||||||
new File(TermuxService.HOME_PATH).mkdirs();
|
new File(TermuxService.HOME_PATH).mkdirs();
|
||||||
|
|
||||||
if (cwd == null) cwd = TermuxService.HOME_PATH;
|
if (cwd == null) cwd = TermuxService.HOME_PATH;
|
||||||
@@ -109,4 +125,18 @@ public final class BackgroundJob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getPid(Process p) {
|
||||||
|
int pid = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field f = p.getClass().getDeclaredField("pid");
|
||||||
|
f.setAccessible(true);
|
||||||
|
pid = f.getInt(p);
|
||||||
|
f.setAccessible(false);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
pid = -1;
|
||||||
|
}
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -119,21 +119,26 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
String executablePath = (executableUri == null ? null : executableUri.getPath());
|
String executablePath = (executableUri == null ? null : executableUri.getPath());
|
||||||
String[] arguments = (executableUri == null ? null : intent.getStringArrayExtra(EXTRA_ARGUMENTS));
|
String[] arguments = (executableUri == null ? null : intent.getStringArrayExtra(EXTRA_ARGUMENTS));
|
||||||
String cwd = intent.getStringExtra(EXTRA_CURRENT_WORKING_DIRECTORY);
|
String cwd = intent.getStringExtra(EXTRA_CURRENT_WORKING_DIRECTORY);
|
||||||
TerminalSession newSession = createTermSession(executablePath, arguments, cwd, false);
|
|
||||||
|
|
||||||
// Transform executable path to session name, e.g. "/bin/do-something.sh" => "do something.sh".
|
if (intent.getBooleanExtra("com.termux.execute.background", false)) {
|
||||||
if (executablePath != null) {
|
new BackgroundJob(cwd, executablePath, arguments);
|
||||||
int lastSlash = executablePath.lastIndexOf('/');
|
} else {
|
||||||
String name = (lastSlash == -1) ? executablePath : executablePath.substring(lastSlash + 1);
|
TerminalSession newSession = createTermSession(executablePath, arguments, cwd, false);
|
||||||
name = name.replace('-', ' ');
|
|
||||||
newSession.mSessionName = name;
|
// 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);
|
||||||
|
name = name.replace('-', ' ');
|
||||||
|
newSession.mSessionName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the newly created session the current one to be displayed:
|
||||||
|
TermuxPreferences.storeCurrentSession(this, newSession);
|
||||||
|
|
||||||
|
// Launch the main Termux app, which will now show to current session:
|
||||||
|
startActivity(new Intent(this, TermuxActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the newly created session the current one to be displayed:
|
|
||||||
TermuxPreferences.storeCurrentSession(this, newSession);
|
|
||||||
|
|
||||||
// Launch the main Termux app, which will now show to current session:
|
|
||||||
startActivity(new Intent(this, TermuxActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
|
||||||
} else if (action != null) {
|
} else if (action != null) {
|
||||||
Log.e(EmulatorDebug.LOG_TAG, "Unknown TermuxService action: '" + action + "'");
|
Log.e(EmulatorDebug.LOG_TAG, "Unknown TermuxService action: '" + action + "'");
|
||||||
}
|
}
|
||||||
@@ -236,28 +241,7 @@ public final class TermuxService extends Service implements SessionChangedCallba
|
|||||||
|
|
||||||
if (cwd == null) cwd = HOME_PATH;
|
if (cwd == null) cwd = HOME_PATH;
|
||||||
|
|
||||||
final String termEnv = "TERM=xterm-256color";
|
String[] env = BackgroundJob.buildEnvironment(failSafe, cwd);
|
||||||
final String homeEnv = "HOME=" + HOME_PATH;
|
|
||||||
final String prefixEnv = "PREFIX=" + PREFIX_PATH;
|
|
||||||
final String androidRootEnv = "ANDROID_ROOT=" + System.getenv("ANDROID_ROOT");
|
|
||||||
final String androidDataEnv = "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.
|
|
||||||
final String externalStorageEnv = "EXTERNAL_STORAGE=" + System.getenv("EXTERNAL_STORAGE");
|
|
||||||
String[] env;
|
|
||||||
if (failSafe) {
|
|
||||||
// Keep the default path so that system binaries can be used in the failsafe session.
|
|
||||||
final String pathEnv = "PATH=" + System.getenv("PATH");
|
|
||||||
env = new String[]{termEnv, homeEnv, prefixEnv, androidRootEnv, androidDataEnv, pathEnv, externalStorageEnv};
|
|
||||||
} else {
|
|
||||||
final String ps1Env = "PS1=$ ";
|
|
||||||
final String ldEnv = "LD_LIBRARY_PATH=" + PREFIX_PATH + "/lib";
|
|
||||||
final String langEnv = "LANG=en_US.UTF-8";
|
|
||||||
final String pathEnv = "PATH=" + PREFIX_PATH + "/bin:" + PREFIX_PATH + "/bin/applets";
|
|
||||||
final String pwdEnv = "PWD=" + cwd;
|
|
||||||
|
|
||||||
env = new String[]{termEnv, homeEnv, prefixEnv, ps1Env, ldEnv, langEnv, pathEnv, pwdEnv, androidRootEnv, androidDataEnv, externalStorageEnv};
|
|
||||||
}
|
|
||||||
|
|
||||||
String shellName;
|
String shellName;
|
||||||
if (executablePath == null) {
|
if (executablePath == null) {
|
||||||
|
Reference in New Issue
Block a user