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