Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/topjohnwu/libsu
A complete solution for apps using root permissions
https://github.com/topjohnwu/libsu
Last synced: about 6 hours ago
JSON representation
A complete solution for apps using root permissions
- Host: GitHub
- URL: https://github.com/topjohnwu/libsu
- Owner: topjohnwu
- License: apache-2.0
- Created: 2018-01-19T22:16:33.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2024-06-28T04:48:17.000Z (6 months ago)
- Last Synced: 2024-12-05T01:04:57.116Z (7 days ago)
- Language: Java
- Homepage:
- Size: 23 MB
- Stars: 1,784
- Watchers: 87
- Forks: 358
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-hacking-lists - topjohnwu/libsu - A complete solution for apps using root permissions (Java)
README
# libsu
[![](https://jitpack.io/v/topjohnwu/libsu.svg)](https://jitpack.io/#topjohnwu/libsu)
An Android library providing a complete solution for apps using root permissions.
`libsu` comes with 2 main components: the `core` module handles the creation of the Unix (root) shell process and wraps it with high level, robust Java APIs; the `service` module handles the launching, binding, and management of root services over IPC, allowing you to run Java/Kotlin and C/C++ code (via JNI) with root permissions.
## [Changelog](./CHANGELOG.md)
## [Javadoc](https://topjohnwu.github.io/libsu/)
## Download
```groovy
android {
compileOptions {
// The library uses Java 8 features
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
def libsuVersion = '6.0.0'// The core module that provides APIs to a shell
implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"// Optional: APIs for creating root services. Depends on ":core"
implementation "com.github.topjohnwu.libsu:service:${libsuVersion}"// Optional: Provides remote file system support
implementation "com.github.topjohnwu.libsu:nio:${libsuVersion}"
}
```## Quick Tutorial
Please note that this is a quick demo going through the key features of `libsu`. Please read the full Javadoc and check out the example app (`:example`) in this project for more details.
### Configuration
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. Set default configurations before the main `Shell` instance is created:
```java
public class SplashActivity extends Activity {static {
// Set settings before the main shell can be created
Shell.enableVerboseLogging = BuildConfig.DEBUG;
Shell.setDefaultBuilder(Shell.Builder.create()
.setFlags(Shell.FLAG_MOUNT_MASTER)
.setInitializers(ShellInit.class)
.setTimeout(10));
}@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showSplashScreen();
// As an example, preload the main root shell in the splash screen
// so the app can use it afterwards without interrupting application
// flow (e.g. waiting for root permission prompt)
Shell.getShell(shell -> {
// The main shell is now constructed and cached
exitSplashScreen();
});
}
}```
### Shell Operations
`Shell` operations can be performed through static `Shell.cmd(...)` methods that directly use the main root shell:
```java
Shell.Result result;
// Execute commands synchronously
result = Shell.cmd("find /dev/block -iname boot").exec();
// Aside from commands, you can also load scripts from InputStream.
// This is NOT like executing a script like "sh script.sh", but rather
// more similar to sourcing the script (". script.sh").
result = Shell.cmd(getResources().openRawResource(R.raw.script)).exec();List out = result.getOut(); // stdout
int code = result.getCode(); // return code of the last command
boolean ok = result.isSuccess(); // return code == 0?// Async APIs
Shell.cmd("setenforce 0").submit(); // submit and don't care results
Shell.cmd("sleep 5", "echo hello").submit(result -> updateUI(result));
Future futureResult = Shell.cmd("sleep 5", "echo hello").enqueue();// Run commands and output to specific Lists
List mmaps = new ArrayList<>();
Shell.cmd("cat /proc/1/maps").to(mmaps).exec();
List stdout = new ArrayList<>();
List stderr = new ArrayList<>();
Shell.cmd("echo hello", "echo hello >&2").to(stdout, stderr).exec();// Receive output in real-time
List callbackList = new CallbackList() {
@Override
public void onAddElement(String s) { updateUI(s); }
};
Shell.cmd("for i in $(seq 5); do echo $i; sleep 1; done")
.to(callbackList)
.submit(result -> updateUI(result));
```### Initialization
Optionally, a similar concept to `.bashrc`, initialize shells with custom `Shell.Initializer`:
```java
public class ExampleInitializer extends Shell.Initializer {
@Override
public boolean onInit(Context context, Shell shell) {
InputStream bashrc = context.getResources().openRawResource(R.raw.bashrc);
// Here we use Shell instance APIs instead of Shell.cmd(...) static methods
shell.newJob()
.add(bashrc) /* Load a script */
.add("export ENV_VAR=VALUE") /* Run some commands */
.exec();
return true; // Return false to indicate initialization failed
}
}
Shell.Builder builder = /* Create a shell builder */ ;
builder.setInitializers(ExampleInitializer.class);
```### Root Services
If interacting with a root shell is too limited for your needs, you can also implement a root service to run complex code. A root service is similar to [Bound Services](https://developer.android.com/guide/components/bound-services) but running in a root process. `libsu` uses Android's native IPC mechanism, binder, for communication between your root service and the main application process. In addition to running Java/Kotlin code, loading native libraries with JNI is also supported (`android:extractNativeLibs=false` **is** allowed). For more details, please read the full Javadoc of `RootService` and check out the example app for more details. Add `com.github.topjohnwu.libsu:service` as a dependency to access `RootService`:
```java
public class RootConnection implements ServiceConnection { ... }
public class ExampleService extends RootService {
@Override
public IBinder onBind(Intent intent) {
// return IBinder from Messenger or AIDL stub implementation
}
}
RootConnection connection = new RootConnection();
Intent intent = new Intent(context, ExampleService.class);
RootService.bind(intent, connection);
```##### Debugging Root Services
If the application process creating the root service has a debugger attached, the root service will automatically enable debugging mode and wait for the debugger to attach. In Android Studio, go to **"Run > Attach Debugger to Android Process"**, tick the **"Show all processes"** box, and you should be able to manually attach to the remote root process. Currently, only the **"Java only"** debugger is supported.
### I/O
Add `com.github.topjohnwu.libsu:nio` as a dependency to access remote file system APIs:
```java
// Create the file system service in the root process
// For example, create and send the service back to the client in a RootService
public class ExampleService extends RootService {
@Override
public IBinder onBind(Intent intent) {
return FileSystemManager.getService();
}
}// In the client process
IBinder binder = /* From the root service connection */;
FileSystemManager remoteFS;
try {
remoteFS = FileSystemManager.getRemote(binder);
} catch (RemoteException e) {
// Handle errors
}
ExtendedFile bootBlock = remoteFS.getFile("/dev/block/by-name/boot");
if (bootBlock.exists()) {
ExtendedFile bootBackup = remoteFS.getFile("/data/boot.img");
try (InputStream in = bootBlock.newInputStream();
OutputStream out = bootBackup.newOutputStream()) {
// Do I/O stuffs...
} catch (IOException e) {
// Handle errors
}
}
```## License
This project is licensed under the Apache License, Version 2.0. Please refer to `LICENSE` for the full text.