diff --git a/build.sbt b/build.sbt index 5a83ff5c..1edc6161 100644 --- a/build.sbt +++ b/build.sbt @@ -30,6 +30,7 @@ libraryDependencies ++= Seq( "dnsjava" % "dnsjava" % "2.1.7", "com.github.kevinsawicki" % "http-request" % "6.0", "commons-net" % "commons-net" % "3.3", + "eu.chainfire" % "libsuperuser" % "1.0.0.201510071325", "com.google.zxing" % "android-integration" % "3.2.1", "net.glxn.qrgen" % "android" % "2.0", "com.google.android.gms" % "play-services-base" % "8.3.0", diff --git a/src/main/java/eu/chainfire/libsuperuser/Application.java b/src/main/java/eu/chainfire/libsuperuser/Application.java deleted file mode 100644 index a439517f..00000000 --- a/src/main/java/eu/chainfire/libsuperuser/Application.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.chainfire.libsuperuser; - -import android.content.Context; -import android.os.Handler; -import android.widget.Toast; - -/** - * Base application class to extend from, solving some issues with - * toasts and AsyncTasks you are likely to run into - */ -public class Application extends android.app.Application { - /** - * Shows a toast message - * - * @param context Any context belonging to this application - * @param message The message to show - */ - public static void toast(Context context, String message) { - // this is a static method so it is easier to call, - // as the context checking and casting is done for you - - if (context == null) return; - - if (!(context instanceof Application)) { - context = context.getApplicationContext(); - } - - if (context instanceof Application) { - final Context c = context; - final String m = message; - - ((Application)context).runInApplicationThread(new Runnable() { - @Override - public void run() { - Toast.makeText(c, m, Toast.LENGTH_LONG).show(); - } - }); - } - } - - private static Handler mApplicationHandler = new Handler(); - - /** - * Run a runnable in the main application thread - * - * @param r Runnable to run - */ - public void runInApplicationThread(Runnable r) { - mApplicationHandler.post(r); - } - - @Override - public void onCreate() { - super.onCreate(); - - try { - // workaround bug in AsyncTask, can show up (for example) when you toast from a service - // this makes sure AsyncTask's internal handler is created from the right (main) thread - Class.forName("android.os.AsyncTask"); - } catch (ClassNotFoundException e) { - } - } -} diff --git a/src/main/java/eu/chainfire/libsuperuser/Debug.java b/src/main/java/eu/chainfire/libsuperuser/Debug.java deleted file mode 100644 index 5b1e4381..00000000 --- a/src/main/java/eu/chainfire/libsuperuser/Debug.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.chainfire.libsuperuser; - -import android.os.Looper; -import android.util.Log; - -import com.github.shadowsocks.BuildConfig; - -/** - * Utility class for logging and debug features that (by default) does nothing when not in debug mode - */ -public class Debug { - - // ----- DEBUGGING ----- - - private static boolean debug = BuildConfig.DEBUG; - - /** - *
Enable or disable debug mode
- * - *By default, debug mode is enabled for development - * builds and disabled for exported APKs - see - * BuildConfig.DEBUG
- * - * @param enabled Enable debug mode ? - */ - public static void setDebug(boolean enable) { - debug = enable; - } - - /** - *Is debug mode enabled ?
- * - * @return Debug mode enabled - */ - public static boolean getDebug() { - return debug; - } - - // ----- LOGGING ----- - - public interface OnLogListener { - public void onLog(int type, String typeIndicator, String message); - } - - public static final String TAG = "libsuperuser"; - - public static final int LOG_GENERAL = 0x0001; - public static final int LOG_COMMAND = 0x0002; - public static final int LOG_OUTPUT = 0x0004; - - public static final int LOG_NONE = 0x0000; - public static final int LOG_ALL = 0xFFFF; - - private static int logTypes = LOG_ALL; - - private static OnLogListener logListener = null; - - /** - *Log a message (internal)
- * - *Current debug and enabled logtypes decide what gets logged - - * even if a custom callback is registered
- * - * @param type Type of message to log - * @param typeIndicator String indicator for message type - * @param message The message to log - */ - private static void logCommon(int type, String typeIndicator, String message) { - if (debug && ((logTypes & type) == type)) { - if (logListener != null) { - logListener.onLog(type, typeIndicator, message); - } else { - Log.d(TAG, "[" + TAG + "][" + typeIndicator + "]" + (!message.startsWith("[") && !message.startsWith(" ") ? " " : "") + message); - } - } - } - - /** - *Log a "general" message
- * - *These messages are infrequent and mostly occur at startup/shutdown or on error
- * - * @param message The message to log - */ - public static void log(String message) { - logCommon(LOG_GENERAL, "G", message); - } - - /** - *Log a "per-command" message
- * - *This could produce a lot of output if the client runs many commands in the session
- * - * @param message The message to log - */ - public static void logCommand(String message) { - logCommon(LOG_COMMAND, "C", message); - } - - /** - *Log a line of stdout/stderr output
- * - *This could produce a lot of output if the shell commands are noisy
- * - * @param message The message to log - */ - public static void logOutput(String message) { - logCommon(LOG_OUTPUT, "O", message); - } - - /** - *Enable or disable logging specific types of message
- * - *You may | (or) LOG_* constants together. Note that - * debug mode must also be enabled for actual logging to - * occur.
- * - * @param type LOG_* constants - * @param enabled Enable or disable - */ - public static void setLogTypeEnabled(int type, boolean enable) { - if (enable) { - logTypes |= type; - } else { - logTypes &= ~type; - } - } - - /** - *Is logging for specific types of messages enabled ?
- * - *You may | (or) LOG_* constants together, to learn if - * all passed message types are enabled for logging. Note - * that debug mode must also be enabled for actual logging - * to occur.
- * - * @param type LOG_* constants - */ - public static boolean getLogTypeEnabled(int type) { - return ((logTypes & type) == type); - } - - /** - *Is logging for specific types of messages enabled ?
- * - *You may | (or) LOG_* constants together, to learn if - * all message types are enabled for logging. Takes - * debug mode into account for the result.
- * - * @param type LOG_* constants - */ - public static boolean getLogTypeEnabledEffective(int type) { - return getDebug() && getLogTypeEnabled(type); - } - - /** - *Register a custom log handler
- * - *Replaces the log method (write to logcat) with your own - * handler. Whether your handler gets called is still dependent - * on debug mode and message types being enabled for logging.
- * - * @param onLogListener Custom log listener or NULL to revert to default - */ - public static void setOnLogListener(OnLogListener onLogListener) { - logListener = onLogListener; - } - - /** - *Get the currently registered custom log handler
- * - * @return Current custom log handler or NULL if none is present - */ - public static OnLogListener getOnLogListener() { - return logListener; - } - - // ----- SANITY CHECKS ----- - - private static boolean sanityChecks = true; - - /** - *Enable or disable sanity checks
- * - *Enables or disables the library crashing when su is called - * from the main thread.
- * - * @param enabled Enable or disable - */ - public static void setSanityChecksEnabled(boolean enable) { - sanityChecks = enable; - } - - /** - *Are sanity checks enabled ?
- * - *Note that debug mode must also be enabled for actual - * sanity checks to occur.
- * - * @return True if enabled - */ - public static boolean getSanityChecksEnabled() { - return sanityChecks; - } - - /** - *Are sanity checks enabled ?
- * - *Takes debug mode into account for the result.
- * - * @return True if enabled - */ - public static boolean getSanityChecksEnabledEffective() { - return getDebug() && getSanityChecksEnabled(); - } - - /** - *Are we running on the main thread ?
- * - * @return Running on main thread ? - */ - public static boolean onMainThread() { - return ((Looper.myLooper() != null) && (Looper.myLooper() == Looper.getMainLooper())); - } - -} diff --git a/src/main/java/eu/chainfire/libsuperuser/HideOverlaysReceiver.java b/src/main/java/eu/chainfire/libsuperuser/HideOverlaysReceiver.java deleted file mode 100644 index 4b4ce5a8..00000000 --- a/src/main/java/eu/chainfire/libsuperuser/HideOverlaysReceiver.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.chainfire.libsuperuser; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -/** - *- * Base receiver to extend to catch notifications when overlays should be - * hidden. - *
- *- * Tapjacking protection in SuperSU prevents some dialogs from receiving user - * input when overlays are present. For security reasons this notification is - * only sent to apps that have previously been granted root access, so even if - * your app does not require root, you still need to request - * it, and the user must grant it. - *
- *- * Note that the word overlay as used here should be interpreted as "any view or - * window possibly obscuring SuperSU dialogs". - *
- */ -public abstract class HideOverlaysReceiver extends BroadcastReceiver { - public static final String ACTION_HIDE_OVERLAYS = "eu.chainfire.supersu.action.HIDE_OVERLAYS"; - public static final String CATEGORY_HIDE_OVERLAYS = Intent.CATEGORY_INFO; - public static final String EXTRA_HIDE_OVERLAYS = "eu.chainfire.supersu.extra.HIDE"; - - @Override - public final void onReceive(Context context, Intent intent) { - if (intent.hasExtra(EXTRA_HIDE_OVERLAYS)) { - onHideOverlays(intent.getBooleanExtra(EXTRA_HIDE_OVERLAYS, false)); - } - } - - /** - * Called when overlays should be hidden or may be shown - * again. - * - * @param hide Should overlays be hidden? - */ - public abstract void onHideOverlays(boolean hide); -} diff --git a/src/main/java/eu/chainfire/libsuperuser/Shell.java b/src/main/java/eu/chainfire/libsuperuser/Shell.java deleted file mode 100644 index cf48036a..00000000 --- a/src/main/java/eu/chainfire/libsuperuser/Shell.java +++ /dev/null @@ -1,1736 +0,0 @@ -/* - * Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.chainfire.libsuperuser; - -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import android.os.Handler; -import android.os.Looper; - -import eu.chainfire.libsuperuser.StreamGobbler.OnLineListener; - -/** - * Class providing functionality to execute commands in a (root) shell - */ -public class Shell { - /** - *- * Runs commands using the supplied shell, and returns the output, or null - * in case of errors. - *
- *- * This method is deprecated and only provided for backwards compatibility. - * Use {@link #run(String, String[], String[], boolean)} instead, and see - * that same method for usage notes. - *
- * - * @param shell The shell to use for executing the commands - * @param commands The commands to execute - * @param wantSTDERR Return STDERR in the output ? - * @return Output of the commands, or null in case of an error - */ - @Deprecated - public static List- * Runs commands using the supplied shell, and returns the output, or null - * in case of errors. - *
- *- * Note that due to compatibility with older Android versions, wantSTDERR is - * not implemented using redirectErrorStream, but rather appended to the - * output. STDOUT and STDERR are thus not guaranteed to be in the correct - * order in the output. - *
- *- * Note as well that this code will intentionally crash when run in debug - * mode from the main thread of the application. You should always execute - * shell commands from a background thread. - *
- *- * When in debug mode, the code will also excessively log the commands - * passed to and the output returned from the shell. - *
- *- * Though this function uses background threads to gobble STDOUT and STDERR - * so a deadlock does not occur if the shell produces massive output, the - * output is still stored in a List<String>, and as such doing - * something like 'ls -lR /' will probably have you run out of - * memory. - *
- * - * @param shell The shell to use for executing the commands - * @param commands The commands to execute - * @param environment List of all environment variables (in 'key=value' - * format) or null for defaults - * @param wantSTDERR Return STDERR in the output ? - * @return Output of the commands, or null in case of an error - */ - public static List- * Detects the version of the su binary installed (if any), if supported - * by the binary. Most binaries support two different version numbers, - * the public version that is displayed to users, and an internal - * version number that is used for version number comparisons. Returns - * null if su not available or retrieving the version isn't supported. - *
- *- * Note that su binary version and GUI (APK) version can be completely - * different. - *
- *- * This function caches its result to improve performance on multiple - * calls - *
- * - * @param internal Request human-readable version or application - * internal version - * @return String containing the su version or null - */ - public static synchronized String version(boolean internal) { - int idx = internal ? 0 : 1; - if (suVersion[idx] == null) { - String version = null; - - List- * Clears results cached by isSELinuxEnforcing() and version(boolean - * internal) calls. - *
- *- * Most apps should never need to call this, as neither enforcing status - * nor su version is likely to change on a running device - though it is - * not impossible. - *
- */ - public static synchronized void clearCachedResults() { - isSELinuxEnforcing = null; - suVersion[0] = null; - suVersion[1] = null; - } - } - - private interface OnResult { - // for any onCommandResult callback - public static final int WATCHDOG_EXIT = -1; - public static final int SHELL_DIED = -2; - - // for Interactive.open() callbacks only - public static final int SHELL_EXEC_FAILED = -3; - public static final int SHELL_WRONG_UID = -4; - public static final int SHELL_RUNNING = 0; - } - - /** - * Command result callback, notifies the recipient of the completion of a - * command block, including the (last) exit code, and the full output - */ - public interface OnCommandResultListener extends OnResult { - /** - *- * Command result callback - *
- *- * Depending on how and on which thread the shell was created, this - * callback may be executed on one of the gobbler threads. In that case, - * it is important the callback returns as quickly as possible, as - * delays in this callback may pause the native process or even result - * in a deadlock - *
- *- * See {@link Shell.Interactive} for threading details - *
- * - * @param commandCode Value previously supplied to addCommand - * @param exitCode Exit code of the last command in the block - * @param output All output generated by the command block - */ - public void onCommandResult(int commandCode, int exitCode, List- * Command result callback - *
- *- * Depending on how and on which thread the shell was created, this - * callback may be executed on one of the gobbler threads. In that case, - * it is important the callback returns as quickly as possible, as - * delays in this callback may pause the native process or even result - * in a deadlock - *
- *- * See {@link Shell.Interactive} for threading details - *
- * - * @param commandCode Value previously supplied to addCommand - * @param exitCode Exit code of the last command in the block - */ - public void onCommandResult(int commandCode, int exitCode); - } - - /** - * Internal class to store command block properties - */ - private static class Command { - private static int commandCounter = 0; - - private final String[] commands; - private final int code; - private final OnCommandResultListener onCommandResultListener; - private final OnCommandLineListener onCommandLineListener; - private final String marker; - - public Command(String[] commands, int code, - OnCommandResultListener onCommandResultListener, - OnCommandLineListener onCommandLineListener) { - this.commands = commands; - this.code = code; - this.onCommandResultListener = onCommandResultListener; - this.onCommandLineListener = onCommandLineListener; - this.marker = UUID.randomUUID().toString() + String.format("-%08x", ++commandCounter); - } - } - - /** - * Builder class for {@link Shell.Interactive} - */ - public static class Builder { - private Handler handler = null; - private boolean autoHandler = true; - private String shell = "sh"; - private boolean wantSTDERR = false; - private List- * Set a custom handler that will be used to post all callbacks to - *
- *- * See {@link Shell.Interactive} for further details on threading and - * handlers - *
- * - * @param handler Handler to use - * @return This Builder object for method chaining - */ - public Builder setHandler(Handler handler) { - this.handler = handler; - return this; - } - - /** - *- * Automatically create a handler if possible ? Default to true - *
- *- * See {@link Shell.Interactive} for further details on threading and - * handlers - *
- * - * @param autoHandler Auto-create handler ? - * @return This Builder object for method chaining - */ - public Builder setAutoHandler(boolean autoHandler) { - this.autoHandler = autoHandler; - return this; - } - - /** - * Set shell binary to use. Usually "sh" or "su", do not use a full path - * unless you have a good reason to - * - * @param shell Shell to use - * @return This Builder object for method chaining - */ - public Builder setShell(String shell) { - this.shell = shell; - return this; - } - - /** - * Convenience function to set "sh" as used shell - * - * @return This Builder object for method chaining - */ - public Builder useSH() { - return setShell("sh"); - } - - /** - * Convenience function to set "su" as used shell - * - * @return This Builder object for method chaining - */ - public Builder useSU() { - return setShell("su"); - } - - /** - * Set if error output should be appended to command block result output - * - * @param wantSTDERR Want error output ? - * @return This Builder object for method chaining - */ - public Builder setWantSTDERR(boolean wantSTDERR) { - this.wantSTDERR = wantSTDERR; - return this; - } - - /** - * Add or update an environment variable - * - * @param key Key of the environment variable - * @param value Value of the environment variable - * @return This Builder object for method chaining - */ - public Builder addEnvironment(String key, String value) { - environment.put(key, value); - return this; - } - - /** - * Add or update environment variables - * - * @param addEnvironment Map of environment variables - * @return This Builder object for method chaining - */ - public Builder addEnvironment(Map- * Add a command to execute, with a callback to be called on completion - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param command Command to execute - * @param code User-defined value passed back to the callback - * @param onCommandResultListener Callback to be called on completion - * @return This Builder object for method chaining - */ - public Builder addCommand(String command, int code, - OnCommandResultListener onCommandResultListener) { - return addCommand(new String[] { - command - }, code, onCommandResultListener); - } - - /** - * Add commands to execute - * - * @param commands Commands to execute - * @return This Builder object for method chaining - */ - public Builder addCommand(List- * Add commands to execute, with a callback to be called on completion - * (of all commands) - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param commands Commands to execute - * @param code User-defined value passed back to the callback - * @param onCommandResultListener Callback to be called on completion - * (of all commands) - * @return This Builder object for method chaining - */ - public Builder addCommand(List- * Add commands to execute, with a callback to be called on completion - * (of all commands) - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param commands Commands to execute - * @param code User-defined value passed back to the callback - * @param onCommandResultListener Callback to be called on completion - * (of all commands) - * @return This Builder object for method chaining - */ - public Builder addCommand(String[] commands, int code, - OnCommandResultListener onCommandResultListener) { - this.commands.add(new Command(commands, code, onCommandResultListener, null)); - return this; - } - - /** - *- * Set a callback called for every line output to STDOUT by the shell - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param onLineListener Callback to be called for each line - * @return This Builder object for method chaining - */ - public Builder setOnSTDOUTLineListener(OnLineListener onLineListener) { - this.onSTDOUTLineListener = onLineListener; - return this; - } - - /** - *- * Set a callback called for every line output to STDERR by the shell - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param onLineListener Callback to be called for each line - * @return This Builder object for method chaining - */ - public Builder setOnSTDERRLineListener(OnLineListener onLineListener) { - this.onSTDERRLineListener = onLineListener; - return this; - } - - /** - *- * Enable command timeout callback - *
- *- * This will invoke the onCommandResult() callback with exitCode - * WATCHDOG_EXIT if a command takes longer than watchdogTimeout seconds - * to complete. - *
- *- * If a watchdog timeout occurs, it generally means that the Interactive - * session is out of sync with the shell process. The caller should - * close the current session and open a new one. - *
- * - * @param watchdogTimeout Timeout, in seconds; 0 to disable - * @return This Builder object for method chaining - */ - public Builder setWatchdogTimeout(int watchdogTimeout) { - this.watchdogTimeout = watchdogTimeout; - return this; - } - - /** - *- * Enable/disable reduced logcat output - *
- *- * Note that this is a global setting - *
- * - * @param useMinimal true for reduced output, false for full output - * @return This Builder object for method chaining - */ - public Builder setMinimalLogging(boolean useMinimal) { - Debug.setLogTypeEnabled(Debug.LOG_COMMAND | Debug.LOG_OUTPUT, !useMinimal); - return this; - } - - /** - * Construct a {@link Shell.Interactive} instance, and start the shell - */ - public Interactive open() { - return new Interactive(this, null); - } - - /** - * Construct a {@link Shell.Interactive} instance, try to start the - * shell, and call onCommandResultListener to report success or failure - * - * @param onCommandResultListener Callback to return shell open status - */ - public Interactive open(OnCommandResultListener onCommandResultListener) { - return new Interactive(this, onCommandResultListener); - } - } - - /** - *- * An interactive shell - initially created with {@link Shell.Builder} - - * that executes blocks of commands you supply in the background, optionally - * calling callbacks as each block completes. - *
- *- * STDERR output can be supplied as well, but due to compatibility with - * older Android versions, wantSTDERR is not implemented using - * redirectErrorStream, but rather appended to the output. STDOUT and STDERR - * are thus not guaranteed to be in the correct order in the output. - *
- *- * Note as well that the close() and waitForIdle() methods will - * intentionally crash when run in debug mode from the main thread of the - * application. Any blocking call should be run from a background thread. - *
- *- * When in debug mode, the code will also excessively log the commands - * passed to and the output returned from the shell. - *
- *- * Though this function uses background threads to gobble STDOUT and STDERR - * so a deadlock does not occur if the shell produces massive output, the - * output is still stored in a List<String>, and as such doing - * something like 'ls -lR /' will probably have you run out of - * memory when using a {@link Shell.OnCommandResultListener}. A work-around - * is to not supply this callback, but using (only) - * {@link Shell.Builder#setOnSTDOUTLineListener(OnLineListener)}. This way, - * an internal buffer will not be created and wasting your memory. - *
- *- * On which thread the callbacks execute is dependent on your - * initialization. You can supply a custom Handler using - * {@link Shell.Builder#setHandler(Handler)} if needed. If you do not supply - * a custom Handler - unless you set - * {@link Shell.Builder#setAutoHandler(boolean)} to false - a Handler will - * be auto-created if the thread used for instantiation of the object has a - * Looper. - *
- *- * If no Handler was supplied and it was also not auto-created, all - * callbacks will be called from either the STDOUT or STDERR gobbler - * threads. These are important threads that should be blocked as little as - * possible, as blocking them may in rare cases pause the native process or - * even create a deadlock. - *
- *- * The main thread must certainly have a Looper, thus if you call - * {@link Shell.Builder#open()} from the main thread, a handler will (by - * default) be auto-created, and all the callbacks will be called on the - * main thread. While this is often convenient and easy to code with, you - * should be aware that if your callbacks are 'expensive' to execute, this - * may negatively impact UI performance. - *
- *- * Background threads usually do not have a Looper, so calling - * {@link Shell.Builder#open()} from such a background thread will (by - * default) result in all the callbacks being executed in one of the gobbler - * threads. You will have to make sure the code you execute in these - * callbacks is thread-safe. - *
- */ - public static class Interactive { - private final Handler handler; - private final boolean autoHandler; - private final String shell; - private final boolean wantSTDERR; - private final List- * Add a command to execute, with a callback to be called on completion - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param command Command to execute - * @param code User-defined value passed back to the callback - * @param onCommandResultListener Callback to be called on completion - */ - public void addCommand(String command, int code, - OnCommandResultListener onCommandResultListener) { - addCommand(new String[] { - command - }, code, onCommandResultListener); - } - - /** - *- * Add a command to execute, with a callback. This callback gobbles the - * output line by line without buffering it and also returns the result - * code on completion. - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param command Command to execute - * @param code User-defined value passed back to the callback - * @param onCommandLineListener Callback - */ - public void addCommand(String command, int code, OnCommandLineListener onCommandLineListener) { - addCommand(new String[] { - command - }, code, onCommandLineListener); - } - - /** - * Add commands to execute - * - * @param commands Commands to execute - */ - public void addCommand(List- * Add commands to execute, with a callback to be called on completion - * (of all commands) - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param commands Commands to execute - * @param code User-defined value passed back to the callback - * @param onCommandResultListener Callback to be called on completion - * (of all commands) - */ - public void addCommand(List- * Add commands to execute, with a callback. This callback gobbles the - * output line by line without buffering it and also returns the result - * code on completion. - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param commands Commands to execute - * @param code User-defined value passed back to the callback - * @param onCommandLineListener Callback - */ - public void addCommand(List- * Add commands to execute, with a callback to be called on completion - * (of all commands) - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param commands Commands to execute - * @param code User-defined value passed back to the callback - * @param onCommandResultListener Callback to be called on completion - * (of all commands) - */ - public synchronized void addCommand(String[] commands, int code, - OnCommandResultListener onCommandResultListener) { - this.commands.add(new Command(commands, code, onCommandResultListener, null)); - runNextCommand(); - } - - /** - *- * Add commands to execute, with a callback. This callback gobbles the - * output line by line without buffering it and also returns the result - * code on completion. - *
- *- * The thread on which the callback executes is dependent on various - * factors, see {@link Shell.Interactive} for further details - *
- * - * @param commands Commands to execute - * @param code User-defined value passed back to the callback - * @param onCommandLineListener Callback - */ - public synchronized void addCommand(String[] commands, int code, - OnCommandLineListener onCommandLineListener) { - this.commands.add(new Command(commands, code, null, onCommandLineListener)); - runNextCommand(); - } - - /** - * Run the next command if any and if ready, signals idle state if no - * commands left - */ - private void runNextCommand() { - runNextCommand(true); - } - - /** - * Called from a ScheduledThreadPoolExecutor timer thread every second - * when there is an outstanding command - */ - private synchronized void handleWatchdog() { - final int exitCode; - - if (watchdog == null) - return; - if (watchdogTimeout == 0) - return; - - if (!isRunning()) { - exitCode = OnCommandResultListener.SHELL_DIED; - Debug.log(String.format("[%s%%] SHELL_DIED", shell.toUpperCase(Locale.ENGLISH))); - } else if (watchdogCount++ < watchdogTimeout) { - return; - } else { - exitCode = OnCommandResultListener.WATCHDOG_EXIT; - Debug.log(String.format("[%s%%] WATCHDOG_EXIT", shell.toUpperCase(Locale.ENGLISH))); - } - - if (handler != null) { - postCallback(command, exitCode, buffer); - } - - // prevent multiple callbacks for the same command - command = null; - buffer = null; - idle = true; - - watchdog.shutdown(); - watchdog = null; - kill(); - } - - /** - * Start the periodic timer when a command is submitted - */ - private void startWatchdog() { - if (watchdogTimeout == 0) { - return; - } - watchdogCount = 0; - watchdog = new ScheduledThreadPoolExecutor(1); - watchdog.scheduleAtFixedRate(new Runnable() { - @Override - public void run() { - handleWatchdog(); - } - }, 1, 1, TimeUnit.SECONDS); - } - - /** - * Disable the watchdog timer upon command completion - */ - private void stopWatchdog() { - if (watchdog != null) { - watchdog.shutdownNow(); - watchdog = null; - } - } - - /** - * Run the next command if any and if ready - * - * @param notifyIdle signals idle state if no commands left ? - */ - private void runNextCommand(boolean notifyIdle) { - // must always be called from a synchronized method - - boolean running = isRunning(); - if (!running) - idle = true; - - if (running && idle && (commands.size() > 0)) { - Command command = commands.get(0); - commands.remove(0); - - buffer = null; - lastExitCode = 0; - lastMarkerSTDOUT = null; - lastMarkerSTDERR = null; - - if (command.commands.length > 0) { - try { - if (command.onCommandResultListener != null) { - // no reason to store the output if we don't have an - // OnCommandResultListener - // user should catch the output with an - // OnLineListener in this case - buffer = Collections.synchronizedList(new ArrayList- * Wait for idle state. As this is a blocking call, you should not call - * it from the main UI thread. If you do so and debug mode is enabled, - * this method will intentionally crash your app. - *
- *- * If not interrupted, this method will not return until all commands - * have finished executing. Note that this does not necessarily mean - * that all the callbacks have fired yet. - *
- *- * If no Handler is used, all callbacks will have been executed when - * this method returns. If a Handler is used, and this method is called - * from a different thread than associated with the Handler's Looper, - * all callbacks will have been executed when this method returns as - * well. If however a Handler is used but this method is called from the - * same thread as associated with the Handler's Looper, there is no way - * to know. - *
- *- * In practice this means that in most simple cases all callbacks will - * have completed when this method returns, but if you actually depend - * on this behavior, you should make certain this is indeed the case. - *
- *- * See {@link Shell.Interactive} for further details on threading and - * handlers - *
- * - * @return True if wait complete, false if wait interrupted - */ - public boolean waitForIdle() { - if (Debug.getSanityChecksEnabledEffective() && Debug.onMainThread()) { - Debug.log(ShellOnMainThreadException.EXCEPTION_WAIT_IDLE); - throw new ShellOnMainThreadException(ShellOnMainThreadException.EXCEPTION_WAIT_IDLE); - } - - if (isRunning()) { - synchronized (idleSync) { - while (!idle) { - try { - idleSync.wait(); - } catch (InterruptedException e) { - return false; - } - } - } - - if ((handler != null) && - (handler.getLooper() != null) && - (handler.getLooper() != Looper.myLooper())) { - // If the callbacks are posted to a different thread than - // this one, we can wait until all callbacks have called - // before returning. If we don't use a Handler at all, the - // callbacks are already called before we get here. If we do - // use a Handler but we use the same Looper, waiting here - // would actually block the callbacks from being called - - synchronized (callbackSync) { - while (callbacks > 0) { - try { - callbackSync.wait(); - } catch (InterruptedException e) { - return false; - } - } - } - } - } - - return true; - } - - /** - * Are we using a Handler to post callbacks ? - * - * @return Handler used ? - */ - public boolean hasHandler() { - return (handler != null); - } - } -} diff --git a/src/main/java/eu/chainfire/libsuperuser/ShellNotClosedException.java b/src/main/java/eu/chainfire/libsuperuser/ShellNotClosedException.java deleted file mode 100644 index 2a44083e..00000000 --- a/src/main/java/eu/chainfire/libsuperuser/ShellNotClosedException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.chainfire.libsuperuser; - -/** - * Exception class used to notify developer that a shell was not close()d - */ -@SuppressWarnings("serial") -public class ShellNotClosedException extends RuntimeException { - public static final String EXCEPTION_NOT_CLOSED = "Application did not close() interactive shell"; - - public ShellNotClosedException() { - super(EXCEPTION_NOT_CLOSED); - } -} diff --git a/src/main/java/eu/chainfire/libsuperuser/ShellOnMainThreadException.java b/src/main/java/eu/chainfire/libsuperuser/ShellOnMainThreadException.java deleted file mode 100644 index 69732e3b..00000000 --- a/src/main/java/eu/chainfire/libsuperuser/ShellOnMainThreadException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.chainfire.libsuperuser; - -/** - * Exception class used to crash application when shell commands are executed - * from the main thread, and we are in debug mode. - */ -@SuppressWarnings("serial") -public class ShellOnMainThreadException extends RuntimeException { - public static final String EXCEPTION_COMMAND = "Application attempted to run a shell command from the main thread"; - public static final String EXCEPTION_NOT_IDLE = "Application attempted to wait for a non-idle shell to close on the main thread"; - public static final String EXCEPTION_WAIT_IDLE = "Application attempted to wait for a shell to become idle on the main thread"; - - public ShellOnMainThreadException(String message) { - super(message); - } -} diff --git a/src/main/java/eu/chainfire/libsuperuser/StreamGobbler.java b/src/main/java/eu/chainfire/libsuperuser/StreamGobbler.java deleted file mode 100644 index 73052154..00000000 --- a/src/main/java/eu/chainfire/libsuperuser/StreamGobbler.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2012-2014 Jorrit "Chainfire" Jongma - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.chainfire.libsuperuser; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.List; - -/** - * Thread utility class continuously reading from an InputStream - */ -public class StreamGobbler extends Thread { - /** - * Line callback interface - */ - public interface OnLineListener { - /** - *Line callback
- * - *This callback should process the line as quickly as possible. - * Delays in this callback may pause the native process or even - * result in a deadlock
- * - * @param line String that was gobbled - */ - public void onLine(String line); - } - - private String shell = null; - private BufferedReader reader = null; - private ListStreamGobbler constructor
- * - *We use this class because shell STDOUT and STDERR should be read as quickly as - * possible to prevent a deadlock from occurring, or Process.waitFor() never - * returning (as the buffer is full, pausing the native process)
- * - * @param shell Name of the shell - * @param inputStream InputStream to read from - * @param outputList ListStreamGobbler constructor
- * - *We use this class because shell STDOUT and STDERR should be read as quickly as - * possible to prevent a deadlock from occurring, or Process.waitFor() never - * returning (as the buffer is full, pausing the native process)
- * - * @param shell Name of the shell - * @param inputStream InputStream to read from - * @param onLineListener OnLineListener callback - */ - public StreamGobbler(String shell, InputStream inputStream, OnLineListener onLineListener) { - this.shell = shell; - reader = new BufferedReader(new InputStreamReader(inputStream)); - listener = onLineListener; - } - - @Override - public void run() { - // keep reading the InputStream until it ends (or an error occurs) - try { - String line = null; - while ((line = reader.readLine()) != null) { - Debug.logOutput(String.format("[%s] %s", shell, line)); - if (writer != null) writer.add(line); - if (listener != null) listener.onLine(line); - } - } catch (IOException e) { - } - - // make sure our stream is closed and resources will be freed - try { - reader.close(); - } catch (IOException e) { - } - } -}