Initial commit
This commit is contained in:
		
							
								
								
									
										80
									
								
								app/src/main/java/eu/chainfire/libsuperuser/Application.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								app/src/main/java/eu/chainfire/libsuperuser/Application.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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) {
 | 
			
		||||
            // will never happen
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										242
									
								
								app/src/main/java/eu/chainfire/libsuperuser/Debug.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								app/src/main/java/eu/chainfire/libsuperuser/Debug.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,242 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.jens.automation2.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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Enable or disable debug mode</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>By default, debug mode is enabled for development
 | 
			
		||||
     * builds and disabled for exported APKs - see
 | 
			
		||||
     * BuildConfig.DEBUG</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param enable Enable debug mode ?
 | 
			
		||||
     */	
 | 
			
		||||
    public static void setDebug(boolean enable) { 
 | 
			
		||||
        debug = enable; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Is debug mode enabled ?</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @return Debug mode enabled
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean getDebug() { 
 | 
			
		||||
        return debug;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ----- LOGGING -----
 | 
			
		||||
 | 
			
		||||
    public interface OnLogListener {
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Log a message (internal)</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>Current debug and enabled logtypes decide what gets logged - 
 | 
			
		||||
     * even if a custom callback is registered</p>  
 | 
			
		||||
     * 
 | 
			
		||||
     * @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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }	
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Log a "general" message</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>These messages are infrequent and mostly occur at startup/shutdown or on error</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param message The message to log
 | 
			
		||||
     */
 | 
			
		||||
    public static void log(String message) {
 | 
			
		||||
        logCommon(LOG_GENERAL, "G", message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Log a "per-command" message</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>This could produce a lot of output if the client runs many commands in the session</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param message The message to log
 | 
			
		||||
     */
 | 
			
		||||
    public static void logCommand(String message) {
 | 
			
		||||
        logCommon(LOG_COMMAND, "C", message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Log a line of stdout/stderr output</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>This could produce a lot of output if the shell commands are noisy</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param message The message to log
 | 
			
		||||
     */
 | 
			
		||||
    public static void logOutput(String message) {
 | 
			
		||||
        logCommon(LOG_OUTPUT, "O", message);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Enable or disable logging specific types of message</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>You may | (or) LOG_* constants together. Note that
 | 
			
		||||
     * debug mode must also be enabled for actual logging to
 | 
			
		||||
     * occur.</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param type LOG_* constants
 | 
			
		||||
     * @param enable Enable or disable
 | 
			
		||||
     */
 | 
			
		||||
    public static void setLogTypeEnabled(int type, boolean enable) { 
 | 
			
		||||
        if (enable) {
 | 
			
		||||
            logTypes |= type;
 | 
			
		||||
        } else {
 | 
			
		||||
            logTypes &= ~type;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Is logging for specific types of messages enabled ?</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>You may | (or) LOG_* constants together, to learn if
 | 
			
		||||
     * <b>all</b> passed message types are enabled for logging. Note
 | 
			
		||||
     * that debug mode must also be enabled for actual logging
 | 
			
		||||
     * to occur.</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param type LOG_* constants
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean getLogTypeEnabled(int type) { 
 | 
			
		||||
        return ((logTypes & type) == type); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Is logging for specific types of messages enabled ?</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>You may | (or) LOG_* constants together, to learn if
 | 
			
		||||
     * <b>all</b> message types are enabled for logging. Takes
 | 
			
		||||
     * debug mode into account for the result.</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param type LOG_* constants
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean getLogTypeEnabledEffective(int type) {
 | 
			
		||||
        return getDebug() && getLogTypeEnabled(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Register a custom log handler</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>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.</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param onLogListener Custom log listener or NULL to revert to default
 | 
			
		||||
     */
 | 
			
		||||
    public static void setOnLogListener(OnLogListener onLogListener) {
 | 
			
		||||
        logListener = onLogListener;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Get the currently registered custom log handler</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @return Current custom log handler or NULL if none is present 
 | 
			
		||||
     */
 | 
			
		||||
    public static OnLogListener getOnLogListener() {
 | 
			
		||||
        return logListener;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ----- SANITY CHECKS -----
 | 
			
		||||
 | 
			
		||||
    private static boolean sanityChecks = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Enable or disable sanity checks</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>Enables or disables the library crashing when su is called 
 | 
			
		||||
     * from the main thread.</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param enable Enable or disable
 | 
			
		||||
     */
 | 
			
		||||
    public static void setSanityChecksEnabled(boolean enable) {
 | 
			
		||||
        sanityChecks = enable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Are sanity checks enabled ?</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>Note that debug mode must also be enabled for actual
 | 
			
		||||
     * sanity checks to occur.</p> 
 | 
			
		||||
     * 
 | 
			
		||||
     * @return True if enabled
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean getSanityChecksEnabled() {
 | 
			
		||||
        return sanityChecks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Are sanity checks enabled ?</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>Takes debug mode into account for the result.</p> 
 | 
			
		||||
     * 
 | 
			
		||||
     * @return True if enabled
 | 
			
		||||
     */
 | 
			
		||||
    public static boolean getSanityChecksEnabledEffective() {
 | 
			
		||||
        return getDebug() && getSanityChecksEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>Are we running on the main thread ?</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @return Running on main thread ?
 | 
			
		||||
     */	
 | 
			
		||||
    public static boolean onMainThread() {
 | 
			
		||||
        return ((Looper.myLooper() != null) && (Looper.myLooper() == Looper.getMainLooper()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Base receiver to extend to catch notifications when overlays should be
 | 
			
		||||
 * hidden.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 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 <em>require</em> root, you still need to <em>request</em>
 | 
			
		||||
 * it, and the user must grant it.
 | 
			
		||||
 * </p>
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Note that the word overlay as used here should be interpreted as "any view or
 | 
			
		||||
 * window possibly obscuring SuperSU dialogs".
 | 
			
		||||
 * </p>
 | 
			
		||||
 */
 | 
			
		||||
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 <em>should</em> be hidden or <em>may</em> be shown
 | 
			
		||||
     * again.
 | 
			
		||||
     * 
 | 
			
		||||
     * @param hide Should overlays be hidden?
 | 
			
		||||
     */
 | 
			
		||||
    public abstract void onHideOverlays(boolean hide);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1757
									
								
								app/src/main/java/eu/chainfire/libsuperuser/Shell.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1757
									
								
								app/src/main/java/eu/chainfire/libsuperuser/Shell.java
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										105
									
								
								app/src/main/java/eu/chainfire/libsuperuser/StreamGobbler.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								app/src/main/java/eu/chainfire/libsuperuser/StreamGobbler.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 {		
 | 
			
		||||
        /**
 | 
			
		||||
         * <p>Line callback</p>
 | 
			
		||||
         * 
 | 
			
		||||
         * <p>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</p>
 | 
			
		||||
         * 
 | 
			
		||||
         * @param line String that was gobbled
 | 
			
		||||
         */
 | 
			
		||||
        void onLine(String line);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String shell = null;
 | 
			
		||||
    private BufferedReader reader = null;
 | 
			
		||||
    private List<String> writer = null;
 | 
			
		||||
    private OnLineListener listener = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>StreamGobbler constructor</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>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)</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @param shell Name of the shell
 | 
			
		||||
     * @param inputStream InputStream to read from
 | 
			
		||||
     * @param outputList List<String> to write to, or null
 | 
			
		||||
     */
 | 
			
		||||
    public StreamGobbler(String shell, InputStream inputStream, List<String> outputList) {
 | 
			
		||||
        this.shell = shell;
 | 
			
		||||
        reader = new BufferedReader(new InputStreamReader(inputStream));
 | 
			
		||||
        writer = outputList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <p>StreamGobbler constructor</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * <p>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)</p>
 | 
			
		||||
     * 
 | 
			
		||||
     * @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;
 | 
			
		||||
            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) {
 | 
			
		||||
            // reader probably closed, expected exit condition
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // make sure our stream is closed and resources will be freed
 | 
			
		||||
        try {
 | 
			
		||||
            reader.close();
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            // read already closed
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user