mirror of
https://github.com/fankes/termux-app.git
synced 2025-09-06 02:35:19 +08:00
Send PendingIntent back for pre-execution errors generated for RUN_COMMAND intent
If the pending intent is not null, then the errors will be sent back to the caller without notifying the user, since we will let the caller handle the errors himself. They will still be logged in logcat. However, if "allow-external-apps" is not true, then a flash and notification will be shown forcefully (regardless of "Plugin Execution Errors" toggle state), so that the user knows someone tried to run a command in termux context, since it may be malicious app or imported (tasker) plugin project and not the user himself. If a pending intent is also sent, then its creator is also logged and shown.
This commit is contained in:
@@ -20,7 +20,6 @@ import com.termux.app.utils.NotificationUtils;
|
||||
import com.termux.app.utils.PluginUtils;
|
||||
import com.termux.app.utils.TextDataUtils;
|
||||
import com.termux.models.ExecutionCommand;
|
||||
import com.termux.models.ExecutionCommand.ExecutionState;
|
||||
|
||||
/**
|
||||
* Third-party apps that are not part of termux world can run commands in termux context by either
|
||||
@@ -297,6 +296,8 @@ public class RunCommandService extends Service {
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Logger.logDebug(LOG_TAG, "onStartCommand");
|
||||
|
||||
if(intent == null) return Service.START_NOT_STICKY;;
|
||||
|
||||
// Run again in case service is already started and onCreate() is not called
|
||||
runStartForeground();
|
||||
|
||||
@@ -309,7 +310,7 @@ public class RunCommandService extends Service {
|
||||
if (!RUN_COMMAND_SERVICE.ACTION_RUN_COMMAND.equals(intent.getAction())) {
|
||||
errmsg = this.getString(R.string.error_run_command_service_invalid_intent_action, intent.getAction());
|
||||
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@@ -321,20 +322,20 @@ public class RunCommandService extends Service {
|
||||
executionCommand.commandLabel = TextDataUtils.getDefaultIfNull(intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_COMMAND_LABEL), "RUN_COMMAND Execution Intent Command");
|
||||
executionCommand.commandDescription = intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_COMMAND_DESCRIPTION);
|
||||
executionCommand.commandHelp = intent.getStringExtra(RUN_COMMAND_SERVICE.EXTRA_COMMAND_HELP);
|
||||
executionCommand.isPluginExecutionCommand = true;
|
||||
executionCommand.pluginPendingIntent = intent.getParcelableExtra(RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT);
|
||||
|
||||
|
||||
|
||||
if(!executionCommand.setState(ExecutionState.PRE_EXECUTION))
|
||||
return Service.START_NOT_STICKY;
|
||||
|
||||
|
||||
|
||||
// If "allow-external-apps" property to not set to "true", then just return
|
||||
// We enable force notifications if "allow-external-apps" policy is violated so that the
|
||||
// user knows someone tried to run a command in termux context, since it may be malicious
|
||||
// app or imported (tasker) plugin project and not the user himself. If a pending intent is
|
||||
// also sent, then its creator is also logged and shown.
|
||||
errmsg = PluginUtils.checkIfRunCommandServiceAllowExternalAppsPolicyIsViolated(this);
|
||||
if (errmsg != null) {
|
||||
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, true);
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@@ -344,7 +345,7 @@ public class RunCommandService extends Service {
|
||||
if (executionCommand.executable == null || executionCommand.executable.isEmpty()) {
|
||||
errmsg = this.getString(R.string.error_run_command_service_mandatory_extra_missing, RUN_COMMAND_SERVICE.EXTRA_COMMAND_PATH);
|
||||
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@@ -359,7 +360,7 @@ public class RunCommandService extends Service {
|
||||
if (errmsg != null) {
|
||||
errmsg += "\n" + this.getString(R.string.msg_executable_absolute_path, executionCommand.executable);
|
||||
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@@ -382,7 +383,7 @@ public class RunCommandService extends Service {
|
||||
if (errmsg != null) {
|
||||
errmsg += "\n" + this.getString(R.string.msg_working_directory_absolute_path, executionCommand.workingDirectory);
|
||||
executionCommand.setStateFailed(ExecutionCommand.RESULT_CODE_FAILED, errmsg, null);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand);
|
||||
PluginUtils.processPluginExecutionCommandError(this, LOG_TAG, executionCommand, false);
|
||||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
}
|
||||
|
@@ -93,6 +93,7 @@ public class TermuxSession {
|
||||
|
||||
if(executionCommand == null) return;
|
||||
|
||||
// Must be a normal command like foreground terminal session started by user, so just return
|
||||
if(!executionCommand.isPluginExecutionCommand) return;
|
||||
|
||||
if(terminalSession != null && !terminalSession.isRunning() && executionCommand.hasExecuted() && !executionCommand.isStateFailed()) {
|
||||
|
@@ -15,7 +15,7 @@ import com.termux.app.TermuxConstants;
|
||||
import com.termux.app.TermuxConstants.TERMUX_APP.TERMUX_SERVICE;
|
||||
import com.termux.app.activities.ReportActivity;
|
||||
import com.termux.app.settings.preferences.TermuxAppSharedPreferences;
|
||||
import com.termux.app.settings.preferences.TermuxPreferenceConstants;
|
||||
import com.termux.app.settings.preferences.TermuxPreferenceConstants.TERMUX_APP;
|
||||
import com.termux.app.settings.properties.SharedProperties;
|
||||
import com.termux.app.settings.properties.TermuxPropertyConstants;
|
||||
import com.termux.models.ReportInfo;
|
||||
@@ -38,9 +38,11 @@ public class PluginUtils {
|
||||
/**
|
||||
* Process {@link ExecutionCommand} result.
|
||||
*
|
||||
* The ExecutionCommand currentState must be greater or equal to {@link ExecutionCommand.ExecutionState#EXECUTED}.
|
||||
* If the {@link ExecutionCommand#isPluginExecutionCommand} is {@code true} and {@link ExecutionCommand#pluginPendingIntent}
|
||||
* is not {@code null}, then the result of commands is sent back to the {@link PendingIntent} creator.
|
||||
* The ExecutionCommand currentState must be greater or equal to
|
||||
* {@link ExecutionCommand.ExecutionState#EXECUTED}.
|
||||
* If the {@link ExecutionCommand#isPluginExecutionCommand} is {@code true} and
|
||||
* {@link ExecutionCommand#pluginPendingIntent} is not {@code null}, then the result of commands
|
||||
* are sent back to the {@link PendingIntent} creator.
|
||||
*
|
||||
* @param context The {@link Context} that will be used to send result intent to the {@link PendingIntent} creator.
|
||||
* @param logTag The log tag to use for logging.
|
||||
@@ -49,128 +51,95 @@ public class PluginUtils {
|
||||
public static void processPluginExecutionCommandResult(final Context context, String logTag, final ExecutionCommand executionCommand) {
|
||||
if (executionCommand == null) return;
|
||||
|
||||
logTag = TextDataUtils.getDefaultIfNull(logTag, LOG_TAG);
|
||||
|
||||
if(!executionCommand.hasExecuted()) {
|
||||
Logger.logWarn(LOG_TAG, "Ignoring call to processPluginExecutionCommandResult() since the execution command has not been ExecutionState.EXECUTED");
|
||||
Logger.logWarn(logTag, "Ignoring call to processPluginExecutionCommandResult() since the execution command has not been ExecutionState.EXECUTED");
|
||||
return;
|
||||
}
|
||||
|
||||
// Must be a normal command like foreground terminal session started by user
|
||||
if(!executionCommand.isPluginExecutionCommand)
|
||||
return;
|
||||
|
||||
logTag = TextDataUtils.getDefaultIfNull(logTag, LOG_TAG);
|
||||
|
||||
Logger.logDebug(LOG_TAG, executionCommand.toString());
|
||||
|
||||
boolean result = true;
|
||||
|
||||
// If pluginPendingIntent is null, then just return
|
||||
if(executionCommand.pluginPendingIntent == null) return;
|
||||
// If isPluginExecutionCommand is true and pluginPendingIntent is not null, then
|
||||
// send pluginPendingIntent to its creator with the result
|
||||
if(executionCommand.isPluginExecutionCommand && executionCommand.pluginPendingIntent != null) {
|
||||
String errmsg = executionCommand.errmsg;
|
||||
|
||||
|
||||
|
||||
// Send pluginPendingIntent to its creator
|
||||
final Bundle resultBundle = new Bundle();
|
||||
|
||||
Logger.logDebug(LOG_TAG, "Sending execution result for Execution Command \"" + executionCommand.getCommandIdAndLabelLogString() + "\" to " + executionCommand.pluginPendingIntent.getCreatorPackage());
|
||||
|
||||
String truncatedStdout = null;
|
||||
String truncatedStderr = null;
|
||||
String truncatedErrmsg = null;
|
||||
|
||||
String stdoutOriginalLength = (executionCommand.stdout == null) ? null: String.valueOf(executionCommand.stdout.length());
|
||||
String stderrOriginalLength = (executionCommand.stderr == null) ? null: String.valueOf(executionCommand.stderr.length());
|
||||
|
||||
if(executionCommand.stderr == null || executionCommand.stderr.isEmpty()) {
|
||||
truncatedStdout = TextDataUtils.getTruncatedCommandOutput(executionCommand.stdout, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES, false, false, false);
|
||||
} else if (executionCommand.stdout == null || executionCommand.stdout.isEmpty()) {
|
||||
truncatedStderr = TextDataUtils.getTruncatedCommandOutput(executionCommand.stderr, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES, false, false, false);
|
||||
} else {
|
||||
truncatedStdout = TextDataUtils.getTruncatedCommandOutput(executionCommand.stdout, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 2, false, false, false);
|
||||
truncatedStderr = TextDataUtils.getTruncatedCommandOutput(executionCommand.stderr, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 2, false, false, false);
|
||||
}
|
||||
|
||||
if(truncatedStdout != null && executionCommand.stdout != null && truncatedStdout.length() < executionCommand.stdout.length()){
|
||||
Logger.logWarn(logTag, "Execution Result for Execution Command \"" + executionCommand.getCommandIdAndLabelLogString() + "\" stdout length truncated from " + stdoutOriginalLength + " to " + truncatedStdout.length());
|
||||
executionCommand.stdout = truncatedStdout;
|
||||
}
|
||||
|
||||
if(truncatedStderr != null && executionCommand.stderr != null && truncatedStderr.length() < executionCommand.stderr.length()){
|
||||
Logger.logWarn(logTag, "Execution Result for Execution Command \"" + executionCommand.getCommandIdAndLabelLogString() + "\" stderr length truncated from " + stderrOriginalLength + " to " + truncatedStderr.length());
|
||||
executionCommand.stderr = truncatedStderr;
|
||||
}
|
||||
|
||||
|
||||
//Combine errmsg and stacktraces
|
||||
if(executionCommand.isStateFailed()) {
|
||||
executionCommand.errmsg = Logger.getMessageAndStackTracesString(executionCommand.errmsg, executionCommand.throwableList);
|
||||
}
|
||||
|
||||
String errmsgOriginalLength = (executionCommand.errmsg == null) ? null: String.valueOf(executionCommand.errmsg.length());
|
||||
|
||||
// trim from end to preseve start of stacktraces
|
||||
truncatedErrmsg = TextDataUtils.getTruncatedCommandOutput(executionCommand.errmsg, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 4, true, false, false);
|
||||
if(truncatedErrmsg != null && executionCommand.errmsg != null && truncatedErrmsg.length() < executionCommand.errmsg.length()){
|
||||
Logger.logWarn(logTag, "Execution Result for Execution Command \"" + executionCommand.getCommandIdAndLabelLogString() + "\" errmsg length truncated from " + errmsgOriginalLength + " to " + truncatedErrmsg.length());
|
||||
executionCommand.errmsg = truncatedErrmsg;
|
||||
}
|
||||
|
||||
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT, executionCommand.stdout);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH, stdoutOriginalLength);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR, executionCommand.stderr);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH, stderrOriginalLength);
|
||||
if (executionCommand.exitCode != null) resultBundle.putInt(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE, executionCommand.exitCode);
|
||||
if (executionCommand.errCode != null) resultBundle.putInt(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERR, executionCommand.errCode);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG, executionCommand.errmsg);
|
||||
|
||||
Intent resultIntent = new Intent();
|
||||
resultIntent.putExtra(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE, resultBundle);
|
||||
|
||||
if(context != null) {
|
||||
try {
|
||||
executionCommand.pluginPendingIntent.send(context, Activity.RESULT_OK, resultIntent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
// The caller doesn't want the result? That's fine, just ignore
|
||||
//Combine errmsg and stacktraces
|
||||
if (executionCommand.isStateFailed()) {
|
||||
errmsg = Logger.getMessageAndStackTracesString(executionCommand.errmsg, executionCommand.throwableList);
|
||||
}
|
||||
|
||||
// Send pluginPendingIntent to its creator
|
||||
result = sendPluginExecutionCommandResultPendingIntent(context, logTag, executionCommand.getCommandIdAndLabelLogString(), executionCommand.stdout, executionCommand.stderr, executionCommand.exitCode, executionCommand.errCode, errmsg, executionCommand.pluginPendingIntent);
|
||||
}
|
||||
|
||||
if(!executionCommand.isStateFailed())
|
||||
if(!executionCommand.isStateFailed() && result)
|
||||
executionCommand.setState(ExecutionCommand.ExecutionState.SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Proceses {@link ExecutionCommand} error.
|
||||
* Process {@link ExecutionCommand} error.
|
||||
*
|
||||
* The ExecutionCommand currentState must be equal to {@link ExecutionCommand.ExecutionState#FAILED}.
|
||||
* The {@link ExecutionCommand#errCode} must have been set to a value greater than {@link ExecutionCommand#RESULT_CODE_OK}.
|
||||
* The {@link ExecutionCommand#errCode} must have been set to a value greater than
|
||||
* {@link ExecutionCommand#RESULT_CODE_OK}.
|
||||
* The {@link ExecutionCommand#errmsg} and any {@link ExecutionCommand#throwableList} must also
|
||||
* be set with appropriate error info.
|
||||
* If the {@link TermuxPreferenceConstants.TERMUX_APP#KEY_PLUGIN_ERROR_NOTIFICATIONS_ENABLED} is
|
||||
*
|
||||
* If the {@link ExecutionCommand#isPluginExecutionCommand} is {@code true} and
|
||||
* {@link ExecutionCommand#pluginPendingIntent} is not {@code null}, then the errors of commands
|
||||
* are sent back to the {@link PendingIntent} creator.
|
||||
*
|
||||
* Otherwise if the {@link TERMUX_APP#KEY_PLUGIN_ERROR_NOTIFICATIONS_ENABLED} is
|
||||
* enabled, then a flash and a notification will be shown for the error as well
|
||||
* on the {@link #NOTIFICATION_CHANNEL_NAME_PLUGIN_COMMAND_ERRORS} channel.
|
||||
* on the {@link #NOTIFICATION_CHANNEL_NAME_PLUGIN_COMMAND_ERRORS} channel instead of just logging
|
||||
* the error.
|
||||
*
|
||||
* @param context The {@link Context} for operations.
|
||||
* @param logTag The log tag to use for logging.
|
||||
* @param executionCommand The {@link ExecutionCommand} that failed.
|
||||
* @param forceNotification If set to {@code true}, then a flash and notification will be shown
|
||||
* regardless of if pending intent is {@code null} or
|
||||
* {@link TERMUX_APP#KEY_PLUGIN_ERROR_NOTIFICATIONS_ENABLED}
|
||||
* is {@code false}.
|
||||
*/
|
||||
public static void processPluginExecutionCommandError(final Context context, String logTag, final ExecutionCommand executionCommand) {
|
||||
public static void processPluginExecutionCommandError(final Context context, String logTag, final ExecutionCommand executionCommand, boolean forceNotification) {
|
||||
if(context == null || executionCommand == null) return;
|
||||
|
||||
logTag = TextDataUtils.getDefaultIfNull(logTag, LOG_TAG);
|
||||
|
||||
if(!executionCommand.isStateFailed()) {
|
||||
Logger.logWarn(LOG_TAG, "Ignoring call to processPluginExecutionCommandError() since the execution command does not have ExecutionState.FAILED state");
|
||||
Logger.logWarn(logTag, "Ignoring call to processPluginExecutionCommandError() since the execution command does not have ExecutionState.FAILED state");
|
||||
return;
|
||||
}
|
||||
|
||||
// Log the error and any exception
|
||||
logTag = TextDataUtils.getDefaultIfNull(logTag, LOG_TAG);
|
||||
Logger.logStackTracesWithMessage(logTag, "(" + executionCommand.errCode + ") " + executionCommand.errmsg, executionCommand.throwableList);
|
||||
|
||||
|
||||
// If isPluginExecutionCommand is true and pluginPendingIntent is not null, then
|
||||
// send pluginPendingIntent to its creator with the errors
|
||||
if(executionCommand.isPluginExecutionCommand && executionCommand.pluginPendingIntent != null) {
|
||||
String errmsg = executionCommand.errmsg;
|
||||
|
||||
//Combine errmsg and stacktraces
|
||||
if (executionCommand.isStateFailed()) {
|
||||
errmsg = Logger.getMessageAndStackTracesString(executionCommand.errmsg, executionCommand.throwableList);
|
||||
}
|
||||
|
||||
sendPluginExecutionCommandResultPendingIntent(context, logTag, executionCommand.getCommandIdAndLabelLogString(), executionCommand.stdout, executionCommand.stderr, executionCommand.exitCode, executionCommand.errCode, errmsg, executionCommand.pluginPendingIntent);
|
||||
|
||||
// No need to show notifications if a pending intent was sent, let the caller handle the result himself
|
||||
if (!forceNotification) return;
|
||||
}
|
||||
|
||||
|
||||
TermuxAppSharedPreferences preferences = new TermuxAppSharedPreferences(context);
|
||||
// If user has disabled notifications for plugin, then just return
|
||||
if (!preferences.getPluginErrorNotificationsEnabled())
|
||||
if (!preferences.getPluginErrorNotificationsEnabled() && !forceNotification)
|
||||
return;
|
||||
|
||||
// Flash the errmsg
|
||||
@@ -199,6 +168,89 @@ public class PluginUtils {
|
||||
NotificationManager notificationManager = NotificationUtils.getNotificationManager(context);
|
||||
if(notificationManager != null)
|
||||
notificationManager.notify(nextNotificationId, builder.build());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Send {@link ExecutionCommand} result {@link PendingIntent} in the
|
||||
* {@link TERMUX_SERVICE#EXTRA_PLUGIN_RESULT_BUNDLE} bundle.
|
||||
*
|
||||
*
|
||||
* @param context The {@link Context} that will be used to send result intent to the {@link PendingIntent} creator.
|
||||
* @param logTag The log tag to use for logging.
|
||||
* @param label The label of {@link ExecutionCommand}.
|
||||
* @param stdout The stdout of {@link ExecutionCommand}.
|
||||
* @param stderr The stderr of {@link ExecutionCommand}.
|
||||
* @param exitCode The exitCode of {@link ExecutionCommand}.
|
||||
* @param errCode The errCode of {@link ExecutionCommand}.
|
||||
* @param errmsg The errmsg of {@link ExecutionCommand}.
|
||||
* @param pluginPendingIntent The pluginPendingIntent of {@link ExecutionCommand}.
|
||||
* @return Returns {@code true} if pluginPendingIntent was successfully send, otherwise [@code false}.
|
||||
*/
|
||||
public static boolean sendPluginExecutionCommandResultPendingIntent(Context context, String logTag, String label, String stdout, String stderr, Integer exitCode, Integer errCode, String errmsg, PendingIntent pluginPendingIntent) {
|
||||
if(context == null || pluginPendingIntent == null) return false;
|
||||
|
||||
logTag = TextDataUtils.getDefaultIfNull(logTag, LOG_TAG);
|
||||
|
||||
Logger.logDebug(logTag, "Sending execution result for Execution Command \"" + label + "\" to " + pluginPendingIntent.getCreatorPackage());
|
||||
|
||||
String truncatedStdout = null;
|
||||
String truncatedStderr = null;
|
||||
String truncatedErrmsg = null;
|
||||
|
||||
String stdoutOriginalLength = (stdout == null) ? null: String.valueOf(stdout.length());
|
||||
String stderrOriginalLength = (stderr == null) ? null: String.valueOf(stderr.length());
|
||||
|
||||
// Truncate stdout and stdout to max TRANSACTION_SIZE_LIMIT_IN_BYTES
|
||||
if(stderr == null || stderr.isEmpty()) {
|
||||
truncatedStdout = TextDataUtils.getTruncatedCommandOutput(stdout, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES, false, false, false);
|
||||
} else if (stdout == null || stdout.isEmpty()) {
|
||||
truncatedStderr = TextDataUtils.getTruncatedCommandOutput(stderr, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES, false, false, false);
|
||||
} else {
|
||||
truncatedStdout = TextDataUtils.getTruncatedCommandOutput(stdout, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 2, false, false, false);
|
||||
truncatedStderr = TextDataUtils.getTruncatedCommandOutput(stderr, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 2, false, false, false);
|
||||
}
|
||||
|
||||
if(truncatedStdout != null && truncatedStdout.length() < stdout.length()){
|
||||
Logger.logWarn(logTag, "Execution Result for Execution Command \"" + label + "\" stdout length truncated from " + stdoutOriginalLength + " to " + truncatedStdout.length());
|
||||
stdout = truncatedStdout;
|
||||
}
|
||||
|
||||
if(truncatedStderr != null && truncatedStderr.length() < stderr.length()){
|
||||
Logger.logWarn(logTag, "Execution Result for Execution Command \"" + label + "\" stderr length truncated from " + stderrOriginalLength + " to " + truncatedStderr.length());
|
||||
stderr = truncatedStderr;
|
||||
}
|
||||
|
||||
String errmsgOriginalLength = (errmsg == null) ? null: String.valueOf(errmsg.length());
|
||||
|
||||
// Truncate errmsg to max TRANSACTION_SIZE_LIMIT_IN_BYTES / 4
|
||||
// trim from end to preserve start of stacktraces
|
||||
truncatedErrmsg = TextDataUtils.getTruncatedCommandOutput(errmsg, TextDataUtils.TRANSACTION_SIZE_LIMIT_IN_BYTES / 4, true, false, false);
|
||||
if(truncatedErrmsg != null && truncatedErrmsg.length() < errmsg.length()){
|
||||
Logger.logWarn(logTag, "Execution Result for Execution Command \"" + label + "\" errmsg length truncated from " + errmsgOriginalLength + " to " + truncatedErrmsg.length());
|
||||
errmsg = truncatedErrmsg;
|
||||
}
|
||||
|
||||
|
||||
final Bundle resultBundle = new Bundle();
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT, stdout);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDOUT_ORIGINAL_LENGTH, stdoutOriginalLength);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR, stderr);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_STDERR_ORIGINAL_LENGTH, stderrOriginalLength);
|
||||
if (exitCode != null) resultBundle.putInt(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_EXIT_CODE, exitCode);
|
||||
if (errCode != null) resultBundle.putInt(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERR, errCode);
|
||||
resultBundle.putString(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE_ERRMSG, errmsg);
|
||||
|
||||
Intent resultIntent = new Intent();
|
||||
resultIntent.putExtra(TERMUX_SERVICE.EXTRA_PLUGIN_RESULT_BUNDLE, resultBundle);
|
||||
|
||||
try {
|
||||
pluginPendingIntent.send(context, Activity.RESULT_OK, resultIntent);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
// The caller doesn't want the result? That's fine, just ignore
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user