Start work on background jobs

This commit is contained in:
Fredrik Fornwall
2016-10-26 02:26:44 +02:00
parent 755513bb33
commit a0fa51eb92
2 changed files with 76 additions and 62 deletions

View File

@@ -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;
}
} }

View File

@@ -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) {