13
13
import com .termux .shared .logger .Logger ;
14
14
import com .termux .shared .models .ExecutionCommand .ExecutionState ;
15
15
16
+ import java .io .DataOutputStream ;
16
17
import java .io .File ;
17
18
import java .io .IOException ;
19
+ import java .nio .charset .StandardCharsets ;
18
20
19
21
/**
20
22
* A class that maintains info for background Termux tasks run with {@link Runtime#exec(String[], String[], File)}.
@@ -92,7 +94,7 @@ public static TermuxTask execute(@NonNull final Context context, @NonNull Execut
92
94
93
95
if (isSynchronous ) {
94
96
try {
95
- termuxTask .executeInner ();
97
+ termuxTask .executeInner (context );
96
98
} catch (IllegalThreadStateException | InterruptedException e ) {
97
99
// TODO: Should either of these be handled or returned?
98
100
}
@@ -101,7 +103,7 @@ public static TermuxTask execute(@NonNull final Context context, @NonNull Execut
101
103
@ Override
102
104
public void run () {
103
105
try {
104
- termuxTask .executeInner ();
106
+ termuxTask .executeInner (context );
105
107
} catch (IllegalThreadStateException | InterruptedException e ) {
106
108
// TODO: Should either of these be handled or returned?
107
109
}
@@ -118,8 +120,10 @@ public void run() {
118
120
* If the processes finishes, then sets {@link ExecutionCommand#stdout}, {@link ExecutionCommand#stderr}
119
121
* and {@link ExecutionCommand#exitCode} for the {@link #mExecutionCommand} of the {@code termuxTask}
120
122
* and then calls {@link #processTermuxTaskResult(TermuxTask, ExecutionCommand) to process the result}.
123
+ *
124
+ * @param context The {@link Context} for operations.
121
125
*/
122
- private void executeInner () throws IllegalThreadStateException , InterruptedException {
126
+ private void executeInner (@ NonNull final Context context ) throws IllegalThreadStateException , InterruptedException {
123
127
final int pid = ShellUtils .getPid (mProcess );
124
128
125
129
Logger .logDebug (LOG_TAG , "Running \" " + mExecutionCommand .getCommandIdAndLabelLogString () + "\" TermuxTask with pid " + pid );
@@ -129,15 +133,42 @@ private void executeInner() throws IllegalThreadStateException, InterruptedExcep
129
133
mExecutionCommand .exitCode = null ;
130
134
131
135
132
-
133
- // setup stdout and stderr gobblers
136
+ // setup stdin, and stdout and stderr gobblers
137
+ DataOutputStream STDIN = new DataOutputStream ( mProcess . getOutputStream ());
134
138
StreamGobbler STDOUT = new StreamGobbler (pid + "-stdout" , mProcess .getInputStream (), mStdout );
135
139
StreamGobbler STDERR = new StreamGobbler (pid + "-stderr" , mProcess .getErrorStream (), mStderr );
136
140
137
141
// start gobbling
138
142
STDOUT .start ();
139
143
STDERR .start ();
140
144
145
+ if (mExecutionCommand .stdin != null && !mExecutionCommand .stdin .isEmpty ()) {
146
+ try {
147
+ STDIN .write ((mExecutionCommand .stdin + "\n " ).getBytes (StandardCharsets .UTF_8 ));
148
+ STDIN .flush ();
149
+ STDIN .close ();
150
+ //STDIN.write("exit\n".getBytes(StandardCharsets.UTF_8));
151
+ //STDIN.flush();
152
+ } catch (IOException e ){
153
+ if (e .getMessage ().contains ("EPIPE" ) || e .getMessage ().contains ("Stream closed" )) {
154
+ // Method most horrid to catch broken pipe, in which case we
155
+ // do nothing. The command is not a shell, the shell closed
156
+ // STDIN, the script already contained the exit command, etc.
157
+ // these cases we want the output instead of returning null.
158
+ } else {
159
+ // other issues we don't know how to handle, leads to
160
+ // returning null
161
+ mExecutionCommand .setStateFailed (ExecutionCommand .RESULT_CODE_FAILED , context .getString (R .string .error_exception_received_while_executing_termux_task_command , mExecutionCommand .getCommandIdAndLabelLogString (), e .getMessage ()), e );
162
+ mExecutionCommand .stdout = mStdout .toString ();
163
+ mExecutionCommand .stderr = mStderr .toString ();
164
+ mExecutionCommand .exitCode = -1 ;
165
+ TermuxTask .processTermuxTaskResult (this , null );
166
+ kill ();
167
+ return ;
168
+ }
169
+ }
170
+ }
171
+
141
172
// wait for our process to finish, while we gobble away in the background
142
173
int exitCode = mProcess .waitFor ();
143
174
@@ -146,6 +177,11 @@ private void executeInner() throws IllegalThreadStateException, InterruptedExcep
146
177
// needed in theory, and may even produce warnings, in "normal" Java
147
178
// they are required for guaranteed cleanup of resources, so lets be
148
179
// safe and do this on Android as well
180
+ try {
181
+ STDIN .close ();
182
+ } catch (IOException e ) {
183
+ // might be closed already
184
+ }
149
185
STDOUT .join ();
150
186
STDERR .join ();
151
187
mProcess .destroy ();
@@ -201,13 +237,20 @@ public void killIfExecuting(@NonNull final Context context, boolean processResul
201
237
}
202
238
203
239
if (mExecutionCommand .isExecuting ()) {
204
- int pid = ShellUtils .getPid (mProcess );
205
- try {
206
- // Send SIGKILL to process
207
- Os .kill (pid , OsConstants .SIGKILL );
208
- } catch (ErrnoException e ) {
209
- Logger .logWarn (LOG_TAG , "Failed to send SIGKILL to \" " + mExecutionCommand .getCommandIdAndLabelLogString () + "\" TermuxTask with pid " + pid + ": " + e .getMessage ());
210
- }
240
+ kill ();
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Kill this {@link TermuxTask} by sending a {@link OsConstants#SIGILL} to its {@link #mProcess}.
246
+ */
247
+ public void kill () {
248
+ int pid = ShellUtils .getPid (mProcess );
249
+ try {
250
+ // Send SIGKILL to process
251
+ Os .kill (pid , OsConstants .SIGKILL );
252
+ } catch (ErrnoException e ) {
253
+ Logger .logWarn (LOG_TAG , "Failed to send SIGKILL to \" " + mExecutionCommand .getCommandIdAndLabelLogString () + "\" TermuxTask with pid " + pid + ": " + e .getMessage ());
211
254
}
212
255
}
213
256
0 commit comments