/* * Copyright (C) 2012-2019 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 android.os.Process; import androidx.annotation.AnyThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.jens.automation2.BuildConfig; /** * Utility class for logging and debug features that (by default) does nothing when not in debug mode */ @SuppressWarnings({"WeakerAccess", "UnusedReturnValue", "unused"}) @AnyThread 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 enable 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 { 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_POOL = 0x0008; public static final int LOG_NONE = 0x0000; public static final int LOG_ALL = 0xFFFF; private static int logTypes = LOG_ALL; @Nullable 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, @NonNull String typeIndicator, @NonNull 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(@NonNull 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(@NonNull 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(@NonNull String message) { logCommon(LOG_OUTPUT, "O", message); } /** *Log pool event
* * @param message The message to log */ public static void logPool(@NonNull String message) { logCommon(LOG_POOL, "P", 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 enable 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 * @return enabled? */ 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 * @return enabled and in debug mode? */ 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(@Nullable OnLogListener onLogListener) { logListener = onLogListener; } /** *Get the currently registered custom log handler
* * @return Current custom log handler or NULL if none is present */ @Nullable 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 enable 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()) && (Process.myUid() != 0)); } }