Coder Social home page Coder Social logo

libsuperuser's Introduction

libsuperuser

ci

Example code for "How-To SU"

For some outdated background details, see:

http://su.chainfire.eu/

Even though its outdated with regards to usage of this library, if you're unfamiliar with writing code for root usage, it is not a bad idea to read it.

License

Copyright © 2012-2019 Jorrit Chainfire Jongma

This code is released under the Apache License version 2.0.

Deprecated

This library is not under active development right now, as I've mostly moved away from the Android world. While I believe it still works great, if it breaks due to changes on new Android versions or root solutions, fixes may be slow to appear.

If you're writing a new app, you might consider using TopJohnWu's libsu instead. Barring some edge-cases (that I personally seem to be the biggest user of) the capabilities should be similar, but it's likely to be better maintained.

v1.1.0 update

It is now 2019, 7 years since the initial release of libsuperuser, and I have finally gotten around to releasing v1.1.0, and writing an updated how-to. See, I don't need reminding every 6 months.

This update brings support for commands returning an InputStream for STDOUT, as well as adding per-line and buffered STDERR support to various methods.

As Shell.Interactive can be a bit tricky to use and understand callback and threading wise, especially when used from a background thread, the Shell.Threaded subclass has been added. This class maintains its own dedicated background thread, upon which all the callbacks are executed.

Shell.Interactive (and Shell.Threaded) have gained synchronous methods, that may be easier to handle than the asynchronous ones, when used from a background thread. Obviously one cannot use them from the main UI thread, as this would block the UI.

Last but not least, Shell.Pool has been added, which maintains a pool of Shell.Threaded instances for your app to use; created, cached, and closed on-demand. For new users, Shell.Pool is the place to start.

If you're looking at the source of the library, Shell.java has become way too large and would look better broken up. This is intentionally not done to maintain better backward compatibility with old code, of which there is quite a bit.

Upgrading from v1.0.0 to v1.1.0

No functionality has been removed, but some of the method signatures have subtly changed, and a lot of methods have been deprecated (though they will not be removed). The compiler will certainly tell you about these. Some interface have been renamed, and some methods were added to existing interfaces. All Exception based classes have moved to inner classes of Shell.

Shell.run(...), and all Shell.SH.xxx and Shell.SU.xxx methods automatically redirect to their Shell.Pool.xxx counterparts. This is a free speed-up for code using these methods. The redirection can be turned off by calling Shell.setRedirectDeprecated(false) from something like Application::onCreate().

While most code should run the same without issue, you should definitely double check, especially for complicated scripts or commands that set specific environment variables.

Shell.Interactive should work exactly as it always has, but since some threading-related code has changed internally, it is always wise to check if everything still works as expected.

There is no need to migrate existing Shell.Interactive code to Shell.Threaded, unless you want to use the functionality provided by Shell.Pool. Be sure to read about the usage difference between them below.

Last but not least, minSdkVersion was updated from 4 to 5, so we're losing compatibility with Android 1.6 Donut users, sorry.

Example project

The example project is very old, and does not follow current best practises. While PooledActivity has been added demonstrating some calls using Shell.Threaded and Shell.Pool, they aren't particularly good. The old code demonstrating both legacy and interactive modes remains present. Use the mode button at the bottom to switch between activities.

Basics

This page is not intended as a full reference, just to get you started off. There are many methods and classes in the library not explained here. For more advanced usages, consult the source code - over 1/3rd of the lines belong to comments.

Some of the below may seem out-of-order, you might want to read this entire section twice.

Blocking, threads, and ShellOnMainThreadException

Running subprocesses is expensive and timings cannot be predicted. For something like running "su" even more so, as it can launch a dialog waiting for user interaction. Many methods in this library may be blocking (taking unpredictable time to return). When you attempt to call any of these methods from the main UI thread, the library will throw a Shell.ShellOnMainThreadException at you, if your app is compiled in debug mode. (Note that this behavior can be disabled through the Debug.setSanityChecksEnabled(false) call).

Methods that may throw this exception include any of the run(...), waitFor...(), and close...() methods, with the exception of closeWhenIdle().

The Shell.Builder, Shell.Interactive and Shell.Threaded classes provide addCommand(...) methods, which run asynchronously and provide completion callbacks. addCommand(...) can safely be called from the main UI thread.

Shell.Interactive (and its Shell.Threaded subclass) is a class wrapping a running instance of a shell (such as "sh" or "su"), providing methods to run commands in that shell and return the output of each individual command and its exit code. As opening a shell itself can be very expensive (especially so with "su"), it is preferred to use few interactive shells to run many commands rather than executing a single shell for each individual command.

Shell.Interactive (and its Shell.Threaded subclass) uses two background threads to continuously gobble the input from STDOUT and STDERR. This is an (unfortunate) requirement to prevent the underlying shell from possibly deadlocking if it produces large amounts of output.

When an instance of Shell.Interactive is created, it determines if the calling thread has an Android Looper attached, if it does, it creates an Android Handler, to which all callbacks (such as the interfaces passed to addCommand(...)) are passed. The callbacks are then executed on the original calling thread. If a Looper is not available, callbacks are usually executed on the gobbler threads (which increases the risk of deadlocks, and should be avoided), but may also be executed on the calling thread (which can cause deadlocks in your own threading code).

(Didn't make sense? Don't worry about it, and just follow the advice and examples below)

Shell.Interactive vs Shell.Threaded

Shell.Interactive's threading/callback model can be fine when it's used from the main UI thread. As the main UI thread most certainly has a Looper, there is no problem creating a Handler, and the callbacks are run directly on the main UI thread. While this does allow you to directly manipulate UI elements from the callbacks, it also causes jank if your callbacks take too long to execute.

However, when Shell.Interactive is used from a background thread, unless you manually create and manage a special secondary thread for it (a HandlerThread), callbacks run on the gobbler threads, which is potentially bad.

The Shell.Threaded subclass specifically creates and manages this secondary HandlerThread for you, and guarantees all callbacks are executed on that thread. This prevents most deadlock situations from happening, and is consistent in its behavior across the board.

The drawback there is that you cannot directly manipulate UI elements from the callbacks passed to addCommand(...) (or any other methods), but that is probably not what you end up wanting to do in any real-world app anyway. When the need arises, you can use something like Activity::runOnUiThread(...) to call code that adjusts the UI.

Additionally, Shell.Threaded is easier to setup and supports pooling via Shell.Pool (explained further below). The choice which to use should be easy at this point, unless you have some very specific needs.

If you are porting from Shell.Interactive to Shell.Threaded, please note that the behavior of the close() method is different between the two. In Shell.Interactive it redirects to closeImmediately(), which waits for all commands to complete and then closes the shell. In Shell.Threaded it returns the shell to the pool if it is part of one, and otherwise redirects to closeWhenIdle(), which schedules the actual close when all commands have completed, but returns immediately. This discrepancy is unfortunate but required to maintain both good backwards compatibility and support pooling with try-with-resources.

Common methods

Examples follow further below, which make use of pooling. But before pooling can be explained, the common methods you will use with different classes need a quick walk-through.

Common methods: addCommand(...)

The Shell.Builder (used to manually construct Shell.Interactive and Shell.Threaded instances), Shell.Interactive and Shell.Threaded classes provide addCommand(...) methods. These run asynchronously and are safe to call from the main UI thread: they return before the commands complete, and an optionally provided callback is executed when the command does complete:

  • addCommand(Object commands)

  • addCommand(Object commands, int code, OnResult onResultListener)

commands accepts a String, a List<String>, or a String[].

onResultListener is one of:

  • OnCommandResultListener2, which buffers STDOUT and STDERR and returns them to the callback all in one go

  • OnCommandLineListener, which is unbuffered and is called once for each line read from STDOUT or STDERR

  • OnCommandInputStreamListener, which is called with an InputStream you can use to read raw data from the shell. You should continue reading the InputStream until -1 is returned (not 0 as is sometimes done), or further commands on this shell will not execute. You can call InputStream::close() to do this for you. Additionally, if the shell is closed during reading, then (and only then) an IOException will be thrown.

All of these provide an onCommandResult method that is called with the code you passed in, and the exit code of the (last) of the commands passed in. Note that the exit code will be < 0 if an error occurs, such as the shell being closed.

The addCommand(...) calls will not be further explained in this document, consult the example project (InteractiveActivity.java) and the library source for further details.

Common methods: run(...)

The Shell.Interactive, Shell.Threaded, and Shell.PoolWrapper classes provide run(...) methods. These run synchronously and are not safe to call from the main UI thread: they return when the command is completed:

  • int run(Object commands)

  • int run(Object commands, List<String> STDOUT, List<String> STDERR, boolean clear)

  • int run(Object commands, OnSyncCommandLineListener onSyncCommandLineListener)

  • int run(Object commands, OnSyncCommandInputStreamListener onSyncCommandInputStreamListener)

As before, commands accepts a String, a List<String>, or a String[].

It should be obvious that these are simply the synchronous counterparts of the asynchronous addCommand(...) methods.

Instead of calling a callback interface with the exit code, it is returned directly, and instead of returning a negative exit code on error, Shell.ShellDiedException is thrown.

Pooling

The Shell.Pool class provides shell pooling. It will create new shell instances on-demand, and keep a set number of them around for reuse later (4 by default for "su" instances, 1 for non-"su" instances).

Shell.Pool.SH and Shell.Pool.SU are pre-created instances of Shell.PoolWrapper for "sh" and "su", providing get() and the earlier mentions run(...) methods for the pool.

The get() method can be used to retrieve a Shell.Threaded instance from the pool, which you should later return to the pool by calling it's close() method.

The run(...) methods, instead of operating on a specific Shell.Threaded instance you manage, retrieve an instance from the pool, proxies the call to that instance's run(...) method, and then immediately returns the instance to the pool.

Sound complex? Maybe, but it all comes together so you can sprinkle Shell.Pool.SU.run(...) calls throughout as many threads as you wish (barring of course the main UI thread), running simultaneously or not, with instances being created, reused, and closed automatically. All of this without you ever having to worry about managing the instances, and only having to catch a single Shell.ShellDiedException.

Examples

It is assumed all the code following is run from a background thread, such as Thread, AsyncTask, or (Job)IntentService.

Running some basic commands:

try {
    List<String> STDOUT = new ArrayList<String>();
    List<String> STDERR = new ArrayList<String>();
    int exitCode;

    exitCode = Shell.Pool.SU.run("echo nobody will ever see this");
    // we have only an exit code

    exitCode = Shell.Pool.SU.run("ls -l /", STDOUT, STDERR, true);
    // exit code, and STDOUT/STDERR output

    exitCode = Shell.Pool.SU.run("cat /init.rc", new Shell.OnSyncCommandInputStreamListener() {
        @Override
        public void onInputStream(InputStream inputStream) {
            try {
                byte[] buf = new byte[16384];
                int r;
                while ((r = inputStream.read(buf)) >= 0) {
                    // do something with buf

                    // if we decide to abort before r == -1, call inputStream.close()
                }
            } catch (IOException e) {
                // shell died during read
            }
        }

        @Override
        public void onSTDERR(String line) {
            // hey, some output on STDERR!
        }
    });

    Shell.Pool.SU.run("logcat -d", new Shell.OnSyncCommandLineListener() {
        @Override
        public void onSTDOUT(String line) {
            // hey, some output on STDOUT!
        }

        @Override
        public void onSTDERR(String line) {
            // hey, some output on STDERR!
        }
    });

} catch (Shell.ShellDiedException e) {
    // su isn't present, access was denied, or the shell terminated while 'run'ing
}

When running multiple commands in quick succession, it is slightly cheaper to get() an instance and close() it when done, and using the returned instance. But keep in mind if there is a longer period between your calls, and another thread wants to call su, the shell you have not close()'d yet cannot be reused by that thread:

try {

    // get an instance from the pool
    Shell.Threaded shell = Shell.Pool.SU.get();
    try {

        // this is very useful
        for (int i = 0; i < 100; i++) {
            shell.run("echo nobody will ever see this");
        }

    } finally {
        // return the instance to the pool
        shell.close();
    }

} catch (Shell.ShellDiedException e) {
    // su isn't present, access was denied, or the shell terminated while 'run'ing
}

If you're targeting API >= 19 and Java 1.8, you can use try-with-resources with Shell.Threaded::ac(), which casts the instance to a Shell.ThreadedAutoCloseable:

try {

    // get an instance from the pool, automatically returning it at the end of the try block
    try (Shell.ThreadedAutoCloseable shell = Shell.Pool.SU.get().ac()) {

        // this is very useful
        for (int i = 0; i < 100; i++) {
            shell.run("echo nobody will ever see this");
        }

    }

} catch (Shell.ShellDiedException e) {
    // su isn't present, access was denied, or the shell terminated while 'run'ing
}

libRootJava

For more advanced usages of root, such as running Java/Kotlin code as root directly, please see my libRootJava library.

Annotations

Nullity and thread annotations have recently been added.

Please note that all methods that may be problematic on the UI thread have been marked as @WorkerThread. Some of these methods can be called from the UI thread without issue in specific conditions. If so, those conditions should be noted in the method's javadoc.

Gradle

Root build.gradle:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Module build.gradle:

dependencies {
    implementation 'eu.chainfire:libsuperuser:1.1.1'
}

libsuperuser's People

Contributors

afollestad avatar cernekee avatar chainfire avatar felixonmars avatar friederbluemle avatar mygod avatar pylersm avatar spocky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libsuperuser's Issues

Paths to external app cache folder

How do I get to the path of Context.getExternalCacheDir() using this shell? In the lib I was currently using (org.sufficientlysecure.rootcommands), I could just do (in Kotlin): context.externalCacheDir.absolutePath.replace("/storage/emulated/0","\$EXTERNAL_STORAGE") and it worked, with this lib it doesn't. Is there any difference? How could I accomplish the same thing across all device models?

Shell.SU.Run does not return

I am using libsuperuser, by importing the following:

import eu.chainfire.libsuperuser.Application;
import eu.chainfire.libsuperuser.Shell;

In the class I got the following method:

    private List<String> suRun(String format, Object... args) {
        String binDir = mAppContext.getFilesDir() + "/bin/";
        String command = binDir + String.format(format, args);
        return Shell.SU.run(command);
    }

and in another method, I call it as follows:

    List<String> result = suRun("cs close %s", getVolumePath());

the command does run, yet it doesn't seem to return, here's the relevant logcat output:

D/libsuperuser( 9783): [libsuperuser][C][SU%] START
D/libsuperuser( 9783): [libsuperuser][C][SU+] /data/data/me.opsec.darkmatter/files/bin/cs close /extSdCard/volume.dat
D/libsuperuser( 9783): [libsuperuser][O][SU*] failed: No such file or directory
D/libsuperuser( 9783): [libsuperuser][O][SU*] failed: No such file or directory
D/libsuperuser( 9783): [libsuperuser][O][SU*] failed: No such file or directory
D/libsuperuser( 9783): [libsuperuser][O][SU*] failed: No such file or directory
D/libsuperuser( 9783): [libsuperuser][O][SU*] failed: Invalid argument

as far as I understand, I should expect a [SU%] END in the logcat, but I never get it.
it seems to me that process.waitFor() in Shell.java never returns.

Can't read output from STDERR

I have a use case when all output is written to STDERR. I modified the libsuperuser_example project to reproduce:

suResult = Shell.run("su", new String[] {
    "id",
    "ls -l / >/dev/stderr"
}, null, true);

Now the output from ls is no longer included in "suResult".

While debugging I've seen that the StreamGobbler STDERR is initialized but for some reason never reaches run() !?!?!

how to su

#63
Updating to 1.0.0.201607041850 caused blocking issues

run() does not return null on failure

Shell.SU.run("echo foo > bar"); always returns an empty list instead of null, even if I decline the SuperSU request.
I'd like to present the user the most exact error message possible, so I'd like to know if the issue is because there was no su access or if the command failed.

Currently, I have to do a Shell.SU.available() check before issuing my command.

Device: Nexus 5x on Marshmallow.

ls -pl doesn't work nor ls -Al

I want to know which of the files are directory. So I am using the ls -pl command. But it returns me 0 results. When I tried it with Terminal Emulator app or Adb, I do get the results? Any way to achieve this? My main idea is to know if the file is directory or not?

`

                                     String [] commands = new String[1];

                    commands[0] = "ls -pl " + path; // path --> /storage/emulated

                    List<String> suResult = Shell.SU.run(commands);

                    StringBuilder sb = new StringBuilder();

                    for (String line : suResult) {

                        sb.append(line).append((char)10);

                    }
                    Logger.log("TAG","List=="+sb);`    

ADB results:
`

                   root@bacon:/ # ls -pl /storage/emulated

total 24

drwxrwx--x 71 root sdcard_rw 4096 2016-07-18 23:33 0/

drwxrwx--x 2 root sdcard_rw 4096 2016-05-12 16:18 legacy/

drwxrwx--x 3 root sdcard_rw 4096 2016-07-15 17:15 obb/ `

Is it possible to send CTRL-C?

I'm trying to execute screenrecord and it seems that the only way to stop it is to send CTRL-C or simply wait for 3 min limit time. The worst part is while screenrecord is active, I cannot execute other commands until screenrecord process stops.

Is it possible to send CTRL-C to Shell.SU.run()? Or perhaps multiple threads of ADB Shell so I can use 1 for screenrecord and another for killing the process of screenrecord. You know, like when you have 2 windows on your Terminal.

Thank you.

Shell session could not terminate or stop

I looked into the code, but could not find the functionality of terminate or stop a shell session whether it is a interactive shell or not.
This feature is important for executing some commands like "tcpdump -p -vv -s 0 -w /sdcard/network_traffic.pcap" or "ps".

Keep shell open but kill a command

The situation:

I am writing a file manager and I am using FileObserver to watch for any changes in the current directory. While browsing directories with no read access I am running inotifywait -m in a root shell.

The process runs forever. When a user navigates to another directory I am calling shell.kill() and then adding a new command (inotifywait [OPTIONS] [FILE]) to listen to the new working directory.

The issue/request/question:

When running a command that never terminates (like logcat or inotifywait) is there a way to stop that command and run another command without requesting root access again (starting a new shell process)?

I don't want the SuperSU toast to popup every time I need to kill the process and add another command.

If it is of any help, here is my code: http://pastebin.com/kG9Cjd4D

Environment passing

Hi!

First of all, thank you for your work. I'm just learning right now your code, and during that i just noticed something:

public static List run(String shell, String[] commands, String[] environment, boolean wantSTDERR) {
[...]
// Combine passed environment with system environment
if (environment != null) {
newEnvironment.putAll(System.getenv());
[...]

So if there is no envrionment variable passed externally, then the other system environments will be skipped too. I might be wrong, but i thought i'll notice you about this.

Thanks!

Unable to cat ftrace buffer to a secondary user directory

I'm playing with the ftrace on the Nexus 6 with Lollipop. Everything works as expected except saving the trace buffer "/d/tracing/trace" to the secondary user storage directory using the "cat" command as follows. The number 10 indicates the secondary user who logged in and the storage path is gotten from the Environment. The file may be created but the content is not written so the size is zero.

cat /d/tracing/trace > /storage/emulated/10/Download/trace.log

On the other hand, if it is the primary user, the same command works as expected and the trace buffer is fully written to the primary user's directory.

cat /d/tracing/trace > /storage/emulated/0/Download/trace.log

I'm wondering if there is something missing here. Any idea?

PS: both uses SU.

How to start interactive mode and run operations of it on a background thread?

It seems the only way to start interactive mode is by using a listener.
When I try to avoid this, only when root permission is given, I get the listener being called, but if the root permission isn't given, the listener isn't called.

I've used the exact same function calls as on the sample, but it still behaves this way.

Is there a way to start interactive mode on the background thread?
Same goes about running commands using interactive mode on a background thread.

I could use rootSession.addCommand(String) , and then rootSession.waitForIdle() , but then I lose the output lines that were written...

Can't import

I get this:

image

Also, BTW, you can remove the "buildToolsVersion" part. It's not needed anymore, for a long time...

Shell.Interactive should not run availableTestCommands

When creating an interactive shell the Shell.availableTestCommands are run after the initial commands. This will only happen if the onCommandResultListener is not null.

TEST:

new Thread() {
  @Override
  public void run() {
      String[] commands = {
              "echo foo",
              "sleep 1",
              "echo bar",
              "sleep 1",
              "echo baz"
      };

      new Shell.Builder()
      .setShell("sh")
      .setOnSTDOUTLineListener(new Shell.OnCommandLineListener() {

        @Override
        public void onLine(String line) {
            android.util.Log.d("ShellTest", line);
        }

        @Override
        public void onCommandResult(int commandCode, int exitCode) {

        }
    })
    .addCommand(commands)
    .open(new Shell.OnCommandResultListener() {

        @Override
        public void onCommandResult(int commandCode, int exitCode, List<String> output) {
            android.util.Log.d("ShellTest", String.format("finished with exit code %d", exitCode));
        }
    });
  }
}.start();

LOG:

D/ShellTest(10309): foo
D/ShellTest(10309): bar
D/ShellTest(10309): baz
D/ShellTest(10309): -BOC-
D/ShellTest(10309): uid=10177(u0_a177) gid=10177(u0_a177) groups=1015(sdcard_rw),1028(sdcard_r),3003(inet),9997(everybody),50177(all_a177) context=u:r:untrusted_app:s0
D/ShellTest(10309): finished with exit code 0

If the interactive shell is opened with commands then the attempt to give time for the dialog to show will be useless.

Question: How to stream from a given inputStream into a root-command outputStream?

It seems that sometimes, it's needed to stream data from an InputStream into the outputStream of a root command.

Example can be found on this repository (which demonstrates how to install split-apks using root) :
https://github.com/Aefyr/SAI

If you look at itsRootedSAIPackageInstaller.java file, you can see it's calling this:

while (apkSource.nextApk())
     ensureCommandSucceeded(Root.exec(String.format("pm install-write -S %d %d \"%s\"", apkSource.getApkLength(), sessionId, apkSource.getApkName()), apkSource.openApkInputStream()));

And the code for its root class is as such:

    private static Result execInternal(String command, @Nullable InputStream inputPipe) {
        try {
            Process process = Runtime.getRuntime().exec(String.format("su -c %s", command));

            StringBuilder stdOutSb = new StringBuilder();
            StringBuilder stdErrSb = new StringBuilder();
            Thread stdOutD = writeStreamToStringBuilder(stdOutSb, process.getInputStream());
            Thread stdErrD = writeStreamToStringBuilder(stdErrSb, process.getErrorStream());

            if (inputPipe != null) {
                IOUtils.copyStream(inputPipe, process.getOutputStream());
                inputPipe.close();
                process.getOutputStream().close();
            }

            process.waitFor();
            stdOutD.join();
            stdErrD.join();

            return new Result(command, process.exitValue(), stdOutSb.toString().trim(), stdErrSb.toString().trim());
        } catch (Exception e) {
            Log.w(TAG, "Unable execute command: ");
            Log.w(TAG, e);
            return new Result(command, -1, "", "Java exception: " + Utils.throwableToString(e));
        }
    }

What is the equivalent for this on libsuperuser ?

Segmentation Fault on Nexus 10

Running the super user example (Shell.SU.available()) gives the following error and a tombstone file is created, however the app does not crash. Any specific reason why this can happen?

04-01 17:00:38.275: I/DEBUG(118): Build fingerprint: 'google/mantaray/manta:4.3/JWR66Y/776638:user/release-keys'
04-01 17:00:38.275: I/DEBUG(118): Revision: '9'
04-01 17:00:38.275: I/DEBUG(118): pid: 4548, tid: 4548, name: AsyncTask #2 >>> eu.chainfire.libsuperuser_example <<<
04-01 17:00:38.275: I/DEBUG(118): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 748e0390
04-01 17:00:38.285: W/NativeCrashListener(365): Couldn't find ProcessRecord for pid 4548

Gradle dependency error

Until before few days ago, I successfully compiled this application with same codes.
But since today, when I tried to build the application in android studio, I found a gradle error.

`Error:A problem occurred configuring project ':app'.

Could not resolve all dependencies for configuration ':app:_debugCompile'.
Could not resolve eu.chainfire:libsuperuser:1.0.0.+.
Required by:
android-msnlcollector:app:unspecified
> Could not resolve eu.chainfire:libsuperuser:1.0.0.201602232304.
> inconsistent module metadata found. Descriptor: eu.chainfire:libsuperuser:1.0.0.201602232303 Errors: bad version: expected='1.0.0.201602232304' found='1.0.0.201602232303'`

Gradle dependencies error

Hi, the compile has changed in the gradle? because i use your library for listing my process in background and the library gives me this error:

Error:(38, 13) Failed to resolve: eu.chainfire:libsuperuser:1.0.0.+

By the way, your library is great Chainfire!

Cheers!

Binary stdout

Currently all shell methods I know of look like

List Shell.SH.run(String command)

in that they return a list of lines (excluding \n) of standard output. Surely, this shouldn't work for binary output: What if there are no newline characters, what if there are, what if there are value-zero characters, what if the current String encoding is UTF-16?

How does one get byte[] output instead?

The Shell.SU.shell() method always returns su rather than context

When trying to use the Shell.SU.shell(int uid, String context) method to get a context, it will always return "su" rather than the actual shell string including the context. This is a result an issue with the Shell.SU.version(boolean internal) method.

Changing the shell to sh rather than the su command and passing su -v as a command allows this method to work properly (at least on the devices I've tested on).

See below for fixed method code:

public static String version(boolean internal) {
            List<String> ret = Shell.run(
                    "sh", 
                    new String[] {internal ? "su -V" : "su -v" }, 
                    null,
                    false
            );
            if (ret == null) return null;

            for (String line : ret) {
                if (!internal) {
                    if (line.contains(".")) return line;                    
                } else { 
                    try {
                        if (Integer.parseInt(line) > 0) return line;
                    } catch(NumberFormatException e) {                  
                    }
                }
            }
            return null;
        }

Gradle file is deprecated

android-library is a deprecated plugin, it's now com.android.library.

Also, the latest buildToolsVersion is 21.0.2 and the latest targetSdk is 21:)

Provide access to return codes when possible

It would be enormously useful to have access to the return codes of commands even if it is not guaranteed for non-zero return codes.
something like gobblers or a callback handler would be great.

Smaller library

I am working on app which has around 90 Kb APK file. I just tried to put some simple Shell.SH.run code added compile 'eu.chainfire:libsuperuser:1.0.0.+' to gradle file and final APK had above 550 Kb.

Since library is just code, not images or so, I wonder if is possible to shrink it.

Shell.SU.run() does not always return command result

Happening with: Nexus 4 running Android Marshmallow with SuperSu installed and properly working. Dont know if happens with other Android versions or other devices (but I guess so).

Steps to reproduce: Running sample command

Shell.SU.run("pm revoke io.plaidapp android.permission.INTERNET");

will result in a empty String array, while running the same command through ADB Shell terminal (from the PC) will result in the following sentence 'Operation not allowed: java.lang.SecurityException: Can't change android.permission.INTERNET. It is required by the application'

Suggestion: Either return null (because it throws java.lang.SecurityException) or return the whole message as a String

capture

How to add dependency to Gradle?

Just a tiny question for this great library please:

How do I add the dependency of this library to Android-Studio? What exactly should I do?

If the user clicks "deny", no callbacks are executed

I want to make a su call while setting a context. The synchronous interface in SU.run doesn't support contexts, so I am using the interactive shell. I have this code:

final boolean[] res = new boolean[1];
res[0] = false;

rootSession = new Shell.Builder().
    useSU().
    setWantSTDERR(true).
    setWatchdogTimeout(timeout).
    setMinimalLogging(false).
    open(new Shell.OnCommandResultListener() {
        @Override
        public void onCommandResult(int commandCode, int exitCode, List<String> output) {
            // Callback to report whether the shell was successfully started up

            if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) {
                Log.e(TAG, "Error opening root shell: exitCode " + exitCode);
            } else {
                rootSession.addCommand(command, 0, new Shell.OnCommandResultListener() {
                    public void onCommandResult(int commandCode, int exitCode, List<String> output) {
                        if (exitCode < 0) { 
                            Log.e(TAG, "Error executing command: exitCode " + exitCode);
                        } else {
                            res[0] = true;
                        }
                    }
                });
            }
        }
    });

rootSession.waitForIdle();
rootSession.close();
return res[0];

(The res[0] is a bit wacky, but I can't think of another way to force this into a synchronous function and return a value).

If the user presses "Deny" on the super user dialog, my callback is never executed. This is because the thread that runs it has no looper, and the code in "handleWatchdog" only calls the callbacks if a handler is defined:

https://github.com/Chainfire/libsuperuser/blob/master/libsuperuser/src/eu/chainfire/libsuperuser/Shell.java#L1242

I'm not sure if this is contrary to the documentation, which states that callbacks will be called from the threads, or not (the docs only refer to the gobbler threads).

In any case, I'm a bit at a loss as to how to use the Shell interface from my non-main thread. I can live with the above hack, but I have to catch the deny action somehow.

(I tried the rewrite the code above the use a looper, but currently running into problems where my app segfaults after calling Looper.quit()).

Gradle support / git tags

From your commits I guess you're still using Eclipse, but would you mind adding Gradle support? I'm already using it in my own branch (https://github.com/ramdroid/libsuperuser/blob/gradle/libsuperuser/build.gradle) but unfortunately I have to upload it to my own mvn-repo on github. So it would be nice if everyone could just pull the newest version from maven central instead ;)

I also would love if you'd support some kind of versioning to your library (e.g. in build.gradle + using git tags). In the current situation when including it in my projects I have no clue what state I'm using...

SuperSU ROM Building

Hi,
I've been trying to integrate SuperSU into an AOSP 4.4.4 ROM but am having a lot of difficulties.
I have everything properly configured in the make files to copy over the su, daemonsu and install-recovery.sh files but it seems that no matter what I do (chmoding and repacking system images, modiying the init script) that /system/etc/install-recovery.sh is always set with 0644 permissions and that even adding the "/system/xbin/daemonsu --auto-daemon &" command as a seperate init.rc service doesn't change it

I was wondering if you could clarify the process as it's extremely frustrating and I'm sure I'm not the only person having difficulties with this

Shell::run() doesn't return the result if the command contains "exit"

Writing "exit" to STDIN in Shell.java:152 fails if the command contains "exit", because the STDIN is already closed. This results in IOException, which is handled on Shell.java:178. This trashes the result, even though the command was successful.

I'm not sure what is the right way to fix this - sure, I can not use exit in the script, but I think the library should be able to handle it. Maybe nest in another try-catch block just around that exit line and ignore if it fails?

Unit Tests for improved test coverage

Hi there,

My name is Farid. I'm a developer with great interest in making open source contributions to popular projects.

My company - DevFactory - is sponsoring me to improve unit test coverage in open source projects.

I have analyzed libsuperuser and observed that there is room for improvement of coverage. The results indicate that the project currently has no unit test coverage.

If you are interested in having us work towards improving the project’s coverage to 80%, please let me know and we will add it to our pipeline. Our first step will be to create a pull request with a sample. Once you approve it, we'll follow up with one or two more pull requests. Our target is to increase code coverage to above 80 percent.

For an example of our work, please see these Pull Requests accepted by the community:

I'm looking forward to your confirmation.

Thank you,
Mohd Farid
Open Source Code Coverage Team
DevFactory

maven package missing

This seems to no longer be available on Maven Central. Adding compile 'eu.chainfire:libsuperuser:1.0.0+' results in a failed to find error. Manually searching Maven Central via the dialog in Android Studio or via search.maven.org does not find any package either.

Updating to 1.0.0.201607041850 caused blocking issues

I was on 1.0.0.201602271131 and previous versions and everything worked great. When it updated to 1.0.0.201607041850 I started getting complaints from users that things were taking forever to run (things that took root, basically just Shell.SU.available() and one Shell.SU.run(). When I put it back to 1.0.0.201602271131 it worked fine. I would be happy to provide whatever information that would be helpful.

cannot open project

ERROR: No toolchains found in the NDK toolchains folder for ABI with prefix: mipsel-linux-android

Android Studio 3.3.2

end/exit marker processing

If command that was executed in a shell doesn't print new line on the end, detecting command exit will not work properly.

Correct me if im wrong, this is my understandin of libsuperuser after quick look over the code....

libsuperuser marks end of command by echoing random string to stdout and stderror, and then checks for those lines during output parsing. When marker is found that means that command was finished.

STDIN.write(("echo " + command.marker + " $?\n").getBytes("UTF-8"));
STDIN.write(("echo " + command.marker + " >&2\n").getBytes("UTF-8"));

If last line on the actual command (command that user executed) is not new line (or doesnt end with new line (\n)), echos mentioned above will merge with last line of the actual output.
This is used to perform check if line is marker:

if (line.startsWith(command.marker))

which in this case will be false, because marker will actualy be on the end of the line, not a new line.

Am i correct, and can someone suggest a workaround.
Will something like this work?

STDIN.write(("echo \n" + command.marker + " $?\n").getBytes("UTF-8"));
STDIN.write(("echo \n" + command.marker + " >&2\n").getBytes("UTF-8"));

Just an example:
libsuperuser will never finish command from this program:

int main(int argc, char **argv)
{
    printf("no new line at the end");
    return 0;
}

Root lost after restarting Bluestacks 2

Hello,

I was trying to install SuperSU binaries on Bluestacks 2, because it has "su" execution exploit and some apps are not working correctly with "su" exploit. After installation, SuperSU is working perfectly until i restart Bluestacks, and the "su" execution is not working anymore. root is completely lost and i'm not able to root Bluestacks with any of root apps and SuperSU. I have tried to enable OTA survival before reproduce this, but it didn't help. SuperSU binary and recovery script are still there but it can't execute "su"!

I have tried to root Bluestacks with Kingroot, restart it and the root was permanent. root is working perfectly and it never go away.

Can you or someone try to find out what cause "su" execution not to work even it is still installed?

OnLineListener per command like OnCommandResultListener

It would be nice to have an OnLineListener per command like the OnCommandResultListener. This would enable to add commands with big outputs to the interactive shell without worrying that it will exhaust memory.

After having some problems with my own Shell implementation and with all the upcoming problems of Android 4.5, it would be nice to base all root apps on libsuperuser.
Thus, I am trying to port my own library root-commands (https://github.com/dschuermann/root-commands) to use libsuperuser for the actual shell access.

This requested feature is the only requirement left for my migration.

PING command takes longer to execute if there is an error than when running from ADB terminal.

Hello,

I am continuously sending PING commands to a host in order to check whether it is reachable.
The shell is initialized as per your example:

   rootSession = new Shell.Builder().
            useSU().
            setWantSTDERR(true).
            setWatchdogTimeout(5).
            setMinimalLogging(true).open();

However, if the host is unreachable there will be no callback at all (not even with WATCHDOG_EXIT) and sending any further commands will not produce responses as well, until I call rootSession.close() and then open() again.

The addCommand() method is used to send the command and everything is working as expected until the point where the host becomes unreachable.

I am testing the same command in the terminal over ADB and after 2 seconds it finishes with Exit Code 1 and a Destination Host Unreachable error (as expected):

root@hltexx:/ # ping -c 1 192.168.100.50
PING 192.168.100.50 (192.168.100.50) 56(84) bytes of data.
From 192.168.100.109: icmp_seq=1 Destination Host Unreachable

--- 192.168.100.50 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms

1|root@hltexx:/ #

Unfortunately I was not able to further debug this as I recently started using Android Studio and the debugger there is slower than evolution. :(

I will get back with more information when I import my project back in Eclipse.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.