Magisk/app/src/main/java/com/topjohnwu/magisk/utils/Shell.java

163 lines
4.5 KiB
Java
Raw Normal View History

package com.topjohnwu.magisk.utils;
2017-07-15 17:20:39 +00:00
import android.content.Context;
2017-07-15 17:20:39 +00:00
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Modified by topjohnwu, based on Chainfire's libsuperuser
*/
public class Shell {
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted
2016-08-27 11:02:41 +00:00
public static int rootStatus;
2017-07-15 17:20:39 +00:00
private final Process rootShell;
private final DataOutputStream rootSTDIN;
private final DataInputStream rootSTDOUT;
2017-07-15 19:32:29 +00:00
private boolean isValid;
2017-07-15 17:20:39 +00:00
private Shell() {
Process process;
try {
2017-07-15 17:20:39 +00:00
process = Runtime.getRuntime().exec("su");
} catch (IOException e) {
// No root
rootStatus = 0;
2017-07-15 17:20:39 +00:00
rootShell = null;
rootSTDIN = null;
rootSTDOUT = null;
2017-07-15 19:32:29 +00:00
isValid = false;
return;
}
2017-07-15 17:20:39 +00:00
rootStatus = 1;
2017-07-15 19:32:29 +00:00
isValid = true;
2017-07-15 17:20:39 +00:00
rootShell = process;
2016-08-27 11:02:41 +00:00
rootSTDIN = new DataOutputStream(rootShell.getOutputStream());
2017-07-15 17:20:39 +00:00
rootSTDOUT = new DataInputStream(rootShell.getInputStream());
2016-11-08 21:17:50 +00:00
2017-07-15 19:32:29 +00:00
su_raw("umask 022");
2016-08-28 22:35:07 +00:00
List<String> ret = su("echo -BOC-", "id");
2016-10-05 16:36:50 +00:00
2017-07-15 17:20:39 +00:00
if (ret.isEmpty()) {
2016-08-25 10:08:07 +00:00
// Something wrong with root, not allowed?
rootStatus = -1;
return;
}
for (String line : ret) {
if (line.contains("uid=")) {
// id command is working, let's see if we are actually root
2017-07-15 17:20:39 +00:00
rootStatus = line.contains("uid=0") ? 1 : -1;
return;
} else if (!line.contains("-BOC-")) {
rootStatus = -1;
return;
}
}
}
2017-07-15 17:20:39 +00:00
public static Shell getRootShell() {
return new Shell();
}
public static Shell getRootShell(Context context) {
return Utils.getMagiskManager(context).rootShell;
}
2016-08-25 10:08:07 +00:00
public static boolean rootAccess() {
2017-07-15 17:20:39 +00:00
return rootStatus > 0;
2016-08-25 10:08:07 +00:00
}
public static List<String> sh(String... commands) {
List<String> res = Collections.synchronizedList(new ArrayList<String>());
try {
Process process = Runtime.getRuntime().exec("sh");
DataOutputStream STDIN = new DataOutputStream(process.getOutputStream());
StreamGobbler STDOUT = new StreamGobbler(process.getInputStream(), res);
STDOUT.start();
try {
for (String write : commands) {
STDIN.write((write + "\n").getBytes("UTF-8"));
STDIN.flush();
2016-09-30 02:41:40 +00:00
Logger.shell(false, write);
}
STDIN.write("exit\n".getBytes("UTF-8"));
STDIN.flush();
} catch (IOException e) {
if (!e.getMessage().contains("EPIPE")) {
throw e;
}
}
process.waitFor();
try {
STDIN.close();
} catch (IOException e) {
// might be closed already
}
STDOUT.join();
process.destroy();
} catch (IOException | InterruptedException e) {
// shell probably not found
res = null;
}
return res;
}
2017-07-15 17:20:39 +00:00
public List<String> su(String... commands) {
2017-07-15 19:32:29 +00:00
if (!isValid) return null;
2017-07-15 17:20:39 +00:00
List<String> res = new ArrayList<>();
su(res, commands);
return res;
}
2017-07-15 19:32:29 +00:00
public void su_raw(String... commands) {
if (!isValid) return;
2017-07-15 17:20:39 +00:00
synchronized (rootShell) {
try {
for (String command : commands) {
rootSTDIN.write((command + "\n").getBytes("UTF-8"));
rootSTDIN.flush();
}
2017-07-15 19:32:29 +00:00
} catch (IOException e) {
2017-07-15 17:20:39 +00:00
e.printStackTrace();
rootShell.destroy();
2017-07-15 19:32:29 +00:00
isValid = false;
}
}
}
2017-07-15 19:32:29 +00:00
public void su(List<String> output, String... commands) {
if (!isValid) return;
try {
rootShell.exitValue();
isValid = false;
return; // The process is dead, return
} catch (IllegalThreadStateException ignored) {
// This should be the expected result
}
synchronized (rootShell) {
StreamGobbler STDOUT = new StreamGobbler(rootSTDOUT, output, true);
STDOUT.start();
su_raw(commands);
su_raw("echo \'-root-done-\'");
try { STDOUT.join(); } catch (InterruptedException ignored) {}
}
}
}