You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Switch to libsu
This commit is contained in:
@@ -27,6 +27,7 @@ public class Const {
|
||||
|
||||
// Paths
|
||||
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
|
||||
public static final String BUSYBOX_PATH = "/sbin/.core/busybox";
|
||||
public static final String TMP_FOLDER_PATH = "/dev/tmp";
|
||||
public static final String MAGISK_LOG = "/cache/magisk.log";
|
||||
public static final File EXTERNAL_PATH = new File(Environment.getExternalStorageDirectory(), "MagiskManager");
|
||||
@@ -37,14 +38,6 @@ public class Const {
|
||||
public static final int SNET_VER = 7;
|
||||
public static final int MIN_MODULE_VER = 1400;
|
||||
|
||||
public static String BUSYBOX_PATH() {
|
||||
if (Utils.itemExist("/sbin/.core/busybox/busybox")) {
|
||||
return "/sbin/.core/busybox";
|
||||
} else {
|
||||
return "/dev/magisk/bin";
|
||||
}
|
||||
}
|
||||
|
||||
public static String MAGISK_PATH() {
|
||||
if (Utils.itemExist("/sbin/.core/img")) {
|
||||
return "/sbin/.core/img";
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Modified by topjohnwu, based on Chainfire's libsuperuser
|
||||
*/
|
||||
|
||||
public class Shell {
|
||||
|
||||
// -2 = not initialized; -1 = no shell; 0 = non root shell; 1 = root shell
|
||||
public static int status = -2;
|
||||
|
||||
private final Process process;
|
||||
private final OutputStream STDIN;
|
||||
private final InputStream STDOUT;
|
||||
private final InputStream STDERR;
|
||||
|
||||
private static void testRootShell(Shell shell) throws IOException {
|
||||
shell.STDIN.write(("id\n").getBytes("UTF-8"));
|
||||
shell.STDIN.flush();
|
||||
String s = new BufferedReader(new InputStreamReader(shell.STDOUT)).readLine();
|
||||
if (TextUtils.isEmpty(s) || !s.contains("uid=0")) {
|
||||
shell.STDIN.close();
|
||||
shell.STDIN.close();
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
public Shell(String command) throws IOException {
|
||||
process = Runtime.getRuntime().exec(command);
|
||||
STDIN = process.getOutputStream();
|
||||
STDOUT = process.getInputStream();
|
||||
STDERR = process.getErrorStream();
|
||||
}
|
||||
|
||||
public static Shell getShell() {
|
||||
MagiskManager mm = MagiskManager.get();
|
||||
boolean needNewShell = mm.shell == null;
|
||||
|
||||
if (!needNewShell) {
|
||||
try {
|
||||
mm.shell.process.exitValue();
|
||||
// The process is dead
|
||||
needNewShell = true;
|
||||
} catch (IllegalThreadStateException ignored) {
|
||||
// This should be the expected result
|
||||
}
|
||||
}
|
||||
|
||||
if (needNewShell) {
|
||||
status = 1;
|
||||
try {
|
||||
mm.shell = new Shell("su --mount-master");
|
||||
testRootShell(mm.shell);
|
||||
} catch (IOException e) {
|
||||
// Mount master not implemented
|
||||
try {
|
||||
mm.shell = new Shell("su");
|
||||
testRootShell(mm.shell);
|
||||
} catch (IOException e1) {
|
||||
// No root exists
|
||||
status = 0;
|
||||
try {
|
||||
mm.shell = new Shell("sh");
|
||||
} catch (IOException e2) {
|
||||
status = -1;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rootAccess()) {
|
||||
// Load utility shell scripts
|
||||
try (InputStream in = mm.getAssets().open(Const.UTIL_FUNCTIONS)) {
|
||||
mm.shell.loadInputStream(in);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Root shell initialization
|
||||
mm.shell.run_raw(false, false,
|
||||
"export PATH=" + Const.BUSYBOX_PATH() + ":$PATH",
|
||||
"mount_partitions",
|
||||
"run_migrations");
|
||||
}
|
||||
}
|
||||
|
||||
return mm.shell;
|
||||
}
|
||||
|
||||
public static boolean rootAccess() {
|
||||
if (status == -2) getShell();
|
||||
return status > 0;
|
||||
}
|
||||
|
||||
public void run(Collection<String> output, Collection<String> error, String... commands) {
|
||||
StreamGobbler out, err;
|
||||
synchronized (process) {
|
||||
try {
|
||||
out = new StreamGobbler(STDOUT, output);
|
||||
err = new StreamGobbler(STDERR, error);
|
||||
out.start();
|
||||
err.start();
|
||||
run_raw(output != null, error != null, commands);
|
||||
STDIN.write("echo \'-shell-done-\'\necho \'-shell-done-\' >&2\n".getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
try {
|
||||
out.join();
|
||||
err.join();
|
||||
} catch (InterruptedException ignored) {}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run_raw(boolean stdout, boolean stderr, String... commands) {
|
||||
String suffix = "\n";
|
||||
if (!stderr) suffix = " 2>/dev/null" + suffix;
|
||||
if (!stdout) suffix = " >/dev/null" + suffix;
|
||||
synchronized (process) {
|
||||
try {
|
||||
for (String command : commands) {
|
||||
Logger.shell(true, command);
|
||||
STDIN.write((command + suffix).getBytes("UTF-8"));
|
||||
STDIN.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadInputStream(InputStream in) {
|
||||
synchronized (process) {
|
||||
try {
|
||||
Utils.inToOut(in, STDIN);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> sh(String... commands) {
|
||||
List<String> res = new ArrayList<>();
|
||||
sh(res, commands);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void sh(Collection<String> output, String... commands) {
|
||||
Shell shell = getShell();
|
||||
if (shell == null)
|
||||
return;
|
||||
shell.run(output, null, commands);
|
||||
}
|
||||
|
||||
public static void sh_raw(String... commands) {
|
||||
Shell shell = getShell();
|
||||
if (shell == null)
|
||||
return;
|
||||
shell.run_raw(false, false, commands);
|
||||
}
|
||||
|
||||
public static List<String> su(String... commands) {
|
||||
if (!rootAccess()) return sh();
|
||||
return sh(commands);
|
||||
}
|
||||
|
||||
public static void su(Collection<String> output, String... commands) {
|
||||
if (!rootAccess()) return;
|
||||
sh(output, commands);
|
||||
}
|
||||
|
||||
public static void su_raw(String... commands) {
|
||||
if (!rootAccess()) return;
|
||||
sh_raw(commands);
|
||||
}
|
||||
|
||||
public static abstract class AbstractList<E> extends java.util.AbstractList<E> {
|
||||
|
||||
@Override
|
||||
public abstract boolean add(E e);
|
||||
|
||||
@Override
|
||||
public E get(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
||||
import com.topjohnwu.magisk.receivers.RebootReceiver;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Modified by topjohnwu, based on Chainfire's libsuperuser
|
||||
*/
|
||||
|
||||
public class StreamGobbler extends Thread {
|
||||
|
||||
private BufferedReader reader;
|
||||
private Collection<String> writer;
|
||||
|
||||
/**
|
||||
* <p>StreamGobbler constructor</p>
|
||||
*
|
||||
* <p>We use this class because sh 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 in InputStream to read from
|
||||
* @param out {@literal List<String>} to write to, or null
|
||||
*/
|
||||
public StreamGobbler(InputStream in, Collection<String> out) {
|
||||
try {
|
||||
while (in.available() != 0) {
|
||||
in.skip(in.available());
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
reader = new BufferedReader(new InputStreamReader(in));
|
||||
writer = out == null ? null : Collections.synchronizedCollection(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// keep reading the InputStream until it ends (or an error occurs)
|
||||
try {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (TextUtils.equals(line, "-shell-done-"))
|
||||
return;
|
||||
if (writer != null) writer.add(line);
|
||||
Logger.shell(false, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.SplashActivity;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
Reference in New Issue
Block a user