Class Shell

java.lang.Object
com.topjohnwu.superuser.Shell
All Implemented Interfaces:
Closeable, AutoCloseable

public abstract class Shell extends Object implements Closeable
A class providing APIs to an interactive Unix shell.

Similar to threads where there is a special "main thread", libsu also has the concept of the "main shell". For each process, there is a single globally shared "main shell" that is constructed on-demand and cached.

To obtain/create the main shell, use the static Shell.getShell(...) methods. Developers can use these high level APIs to access the main shell:

  • Field Details

    • UNKNOWN

      public static final int UNKNOWN
      Shell status: Unknown. One possible result of getStatus().

      Constant value -1.

      See Also:
    • NON_ROOT_SHELL

      public static final int NON_ROOT_SHELL
      Shell status: Non-root shell. One possible result of getStatus().

      Constant value 0.

      See Also:
    • ROOT_SHELL

      public static final int ROOT_SHELL
      Shell status: Root shell. One possible result of getStatus().

      Constant value 1.

      See Also:
    • FLAG_NON_ROOT_SHELL

      public static final int FLAG_NON_ROOT_SHELL
      If set, create a non-root shell.

      Constant value 1.

      See Also:
    • FLAG_MOUNT_MASTER

      public static final int FLAG_MOUNT_MASTER
      If set, create a root shell with the --mount-master option.

      Constant value 2.

      See Also:
    • EXECUTOR

      @NonNull public static Executor EXECUTOR
      The Executor that manages all worker threads used in libsu.

      Note: If the developer decides to replace the default Executor, keep in mind that each Shell instance requires at least 3 threads to operate properly.

    • enableVerboseLogging

      public static boolean enableVerboseLogging
      Set to true to enable verbose logging throughout the library.
    • enableLegacyStderrRedirection

      public static boolean enableLegacyStderrRedirection
      This flag exists for compatibility reasons. DO NOT use unless necessary.

      If enabled, STDERR outputs will be redirected to the STDOUT output list when a Shell.Job is configured with Shell.Job.to(List). Since the Shell.cmd(...) methods are functionally equivalent to Shell.getShell().newJob().add(...).to(new ArrayList<>()), this variable also affects the behavior of those methods.

      Note: The recommended way to redirect STDERR output to STDOUT is to assign the same list to both STDOUT and STDERR with Shell.Job.to(List, List). The behavior of this flag is unintuitive and error prone.

  • Constructor Details

    • Shell

      public Shell()
  • Method Details

    • setDefaultBuilder

      public static void setDefaultBuilder(Shell.Builder builder)
      Override the default Shell.Builder.

      This shell builder will be used to construct the main shell. Set this before the main shell is created anywhere in the program.

    • getShell

      @NonNull public static Shell getShell()
      Get the main shell instance.

      If getCachedShell() returns null, the default Shell.Builder will be used to construct a new Shell.

      Unless already cached, this method blocks until the main shell is created. The process could take a very long time (e.g. root permission request prompt), so be extra careful when calling this method from the main thread!

      A good practice is to "preheat" the main shell during app initialization (e.g. the splash screen) by either calling this method in a background thread or calling getShell(GetShellCallback) so subsequent calls to this function returns immediately.

      Returns:
      the cached/created main shell instance.
      See Also:
    • getShell

      public static void getShell(@NonNull Shell.GetShellCallback callback)
      Get the main shell instance asynchronously via a callback.

      If getCachedShell() returns null, the default Shell.Builder will be used to construct a new Shell in a background thread. The cached/created shell instance is returned to the callback on the main thread.

      Parameters:
      callback - invoked when a shell is acquired.
    • getShell

      public static void getShell(@Nullable Executor executor, @NonNull Shell.GetShellCallback callback)
      Get the main shell instance asynchronously via a callback.

      If getCachedShell() returns null, the default Shell.Builder will be used to construct a new Shell in a background thread. The cached/created shell instance is returned to the callback executed by provided executor.

      Parameters:
      executor - the executor used to handle the result callback event. If null is passed, the callback can run on any thread.
      callback - invoked when a shell is acquired.
    • getCachedShell

      @Nullable public static Shell getCachedShell()
      Get the cached main shell.
      Returns:
      a Shell instance. null can be returned either when no main shell has been cached, or the cached shell is no longer active.
    • isAppGrantedRoot

      @Nullable public static Boolean isAppGrantedRoot()
      Whether the application has access to root.

      This method returns null when it is currently unable to determine whether root access has been granted to the application. A non-null value meant that the root permission grant state has been accurately determined and finalized. The application must have at least 1 root shell created to have this method return true. This method will not block the calling thread; results will be returned immediately.

      Returns:
      whether the application has access to root, or null when undetermined.
    • cmd

      @NonNull public static Shell.Job cmd(@NonNull String... commands)
      Create a pending Shell.Job of the main shell with commands.

      This method can be treated as functionally equivalent to Shell.getShell().newJob().add(commands).to(new ArrayList<>()), but the internal implementation is specialized for this use case and does not run this exact code. The developer can manually override output destination(s) with either Shell.Job.to(List) or Shell.Job.to(List, List).

      The main shell will NOT be requested until the developer invokes either Shell.Job.exec(), Shell.Job.enqueue(), or Job.submit(...). This makes it possible to construct Shell.Jobs before the program has created any root shell.

      Returns:
      a job that the developer can execute or submit later.
      See Also:
    • cmd

      @NonNull public static Shell.Job cmd(@NonNull InputStream in)
      Create a pending Shell.Job of the main shell with an InputStream.

      This method can be treated as functionally equivalent to Shell.getShell().newJob().add(in).to(new ArrayList<>()), but the internal implementation is specialized for this use case and does not run this exact code. The developer can manually override output destination(s) with either Shell.Job.to(List) or Shell.Job.to(List, List).

      The main shell will NOT be requested until the developer invokes either Shell.Job.exec(), Shell.Job.enqueue(), or Job.submit(...). This makes it possible to construct Shell.Jobs before the program has created any root shell.

      See Also:
    • isAlive

      public abstract boolean isAlive()
      Return whether the shell is still alive.
      Returns:
      true if the shell is still alive.
    • execTask

      public abstract void execTask(@NonNull Shell.Task task) throws IOException
      Execute a low-level Shell.Task using the shell. USE THIS METHOD WITH CAUTION!

      This method exposes raw STDIN/STDOUT/STDERR directly to the developer. This is meant for implementing low-level operations. The shell may stall if the buffer of STDOUT/STDERR is full. It is recommended to use additional threads to consume STDOUT/STDERR in parallel.

      STDOUT/STDERR is cleared before executing the task. No output from any previous tasks should be left over. It is the developer's responsibility to make sure all operations are done; the shell should be in idle and waiting for further input when the task returns.

      Parameters:
      task - the desired task.
      Throws:
      IOException - I/O errors when doing operations with STDIN/STDOUT/STDERR
    • submitTask

      public abstract void submitTask(@NonNull Shell.Task task)
      Submits a low-level Shell.Task for execution in a queue of the shell.
      Parameters:
      task - the desired task.
      See Also:
    • newJob

      @NonNull public abstract Shell.Job newJob()
      Construct a new Shell.Job that uses the shell for execution.

      Unlike cmd(String...) and cmd(InputStream), NO output will be collected if the developer did not set the output destination with Shell.Job.to(List) or Shell.Job.to(List, List).

      Returns:
      a job that the developer can execute or submit later.
    • getStatus

      public abstract int getStatus()
      Get the status of the shell.
      Returns:
      the status of the shell. Value is either UNKNOWN, NON_ROOT_SHELL, or ROOT_SHELL
    • isRoot

      public boolean isRoot()
      Return whether the shell has root access.
      Returns:
      true if the shell has root access.
    • waitAndClose

      public abstract boolean waitAndClose(long timeout, @NonNull TimeUnit unit) throws IOException, InterruptedException
      Wait for any current/pending tasks to finish before closing this shell and release any system resources associated with the shell.

      Blocks until all current/pending tasks have completed execution, or the timeout occurs, or the current thread is interrupted, whichever happens first.

      Parameters:
      timeout - the maximum time to wait
      unit - the time unit of the timeout argument
      Returns:
      true if this shell is terminated and false if the timeout elapsed before termination, in which the shell can still to be used afterwards.
      Throws:
      IOException - if an I/O error occurs.
      InterruptedException - if interrupted while waiting.
    • waitAndClose

      public void waitAndClose() throws IOException
      Wait indefinitely for any current/pending tasks to finish before closing this shell and release any system resources associated with the shell.
      Throws:
      IOException - if an I/O error occurs.