Refactor shell (again)

This commit is contained in:
topjohnwu 2017-10-15 23:02:44 +08:00
parent 13bf1b27b4
commit 6f457c0c59
20 changed files with 198 additions and 254 deletions

View File

@ -48,7 +48,7 @@ public class FlashActivity extends Activity {
@OnClick(R.id.reboot)
public void reboot() {
getShell().su_raw("reboot");
Shell.su_raw("reboot");
}
@Override
@ -91,7 +91,7 @@ public class FlashActivity extends Activity {
String boot = intent.getStringExtra(SET_BOOT);
if (getMagiskManager().remoteMagiskVersionCode < 1370) {
// Use legacy installation method
getShell().su_raw(
Shell.su_raw(
"echo \"BOOTIMAGE=" + boot + "\" > /dev/.magisk",
"echo \"KEEPFORCEENCRYPT=" + keepEnc + "\" >> /dev/.magisk",
"echo \"KEEPVERITY=" + keepVerity + "\" >> /dev/.magisk"

View File

@ -254,7 +254,7 @@ public class MagiskFragment extends Fragment
magiskStatusIcon.setImageResource(image);
magiskStatusIcon.setColorFilter(color);
switch (Shell.rootStatus) {
switch (Shell.status) {
case 0:
color = colorBad;
image = R.drawable.ic_cancel;

View File

@ -117,11 +117,11 @@ public class MagiskLogFragment extends Fragment {
switch (mode) {
case 0:
StringBuildingList logList = new StringBuildingList();
getShell().su(logList, "cat " + MAGISK_LOG);
Shell.su(logList, "cat " + MAGISK_LOG);
return logList.toString();
case 1:
getShell().su_raw("echo -n > " + MAGISK_LOG);
Shell.su_raw("echo -n > " + MAGISK_LOG);
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
return "";
@ -142,7 +142,7 @@ public class MagiskLogFragment extends Fragment {
try (FileWriter out = new FileWriter(targetFile)) {
FileWritingList fileWritingList = new FileWritingList(out);
getShell().su(fileWritingList, "cat " + MAGISK_LOG);
Shell.su(fileWritingList, "cat " + MAGISK_LOG);
} catch (IOException e) {
e.printStackTrace();
return false;

View File

@ -208,7 +208,7 @@ public class MagiskManager extends Application {
// Root actions
if (Shell.rootAccess()) {
if (hasNetwork && !Utils.itemExist(shell, BUSYBOXPATH + "/busybox")) {
if (hasNetwork && !Utils.itemExist(BUSYBOXPATH + "/busybox")) {
try {
// Force synchronous, make sure we have busybox to use
new DownloadBusybox(this).exec().get();
@ -223,7 +223,7 @@ public class MagiskManager extends Application {
e.printStackTrace();
}
shell.su_raw(
Shell.su_raw(
"export PATH=" + BUSYBOXPATH + ":$PATH",
"mount_partitions",
"BOOTIMAGE=",
@ -231,11 +231,11 @@ public class MagiskManager extends Application {
"migrate_boot_backup"
);
List<String> res = shell.su("echo \"$BOOTIMAGE\"");
List<String> res = Shell.su("echo \"$BOOTIMAGE\"");
if (Utils.isValidShellResponse(res)) {
bootBlock = res.get(0);
} else {
blockList = shell.su("find /dev/block -type b | grep -vE 'dm|ram|loop'");
blockList = Shell.su("find /dev/block -type b | grep -vE 'dm|ram|loop'");
}
}
@ -244,8 +244,8 @@ public class MagiskManager extends Application {
.putBoolean("dark_theme", isDarkTheme)
.putBoolean("magiskhide", magiskHide)
.putBoolean("notification", updateNotification)
.putBoolean("hosts", Utils.itemExist(shell, MAGISK_HOST_FILE))
.putBoolean("disable", Utils.itemExist(shell, MAGISK_DISABLE_FILE))
.putBoolean("hosts", Utils.itemExist(MAGISK_HOST_FILE))
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
.putBoolean("su_reauth", suReauth)
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
.putString("su_auto_response", String.valueOf(suResponseType))
@ -284,15 +284,15 @@ public class MagiskManager extends Application {
public void getMagiskInfo() {
List<String> ret;
Shell.getShell(this);
ret = shell.sh("su -v");
Shell.registerShell(this);
ret = Shell.sh("su -v");
if (Utils.isValidShellResponse(ret)) {
suVersion = ret.get(0);
isSuClient = suVersion.toUpperCase().contains("MAGISK");
}
ret = shell.sh("magisk -v");
ret = Shell.sh("magisk -v");
if (!Utils.isValidShellResponse(ret)) {
ret = shell.sh("getprop magisk.version");
ret = Shell.sh("getprop magisk.version");
if (Utils.isValidShellResponse(ret)) {
try {
magiskVersionString = ret.get(0);
@ -301,21 +301,21 @@ public class MagiskManager extends Application {
}
} else {
magiskVersionString = ret.get(0).split(":")[0];
ret = shell.sh("magisk -V");
ret = Shell.sh("magisk -V");
try {
magiskVersionCode = Integer.parseInt(ret.get(0));
} catch (NumberFormatException ignored) {}
}
ret = shell.sh("getprop " + DISABLE_INDICATION_PROP);
ret = Shell.sh("getprop " + DISABLE_INDICATION_PROP);
try {
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {
disabled = false;
}
if (magiskVersionCode > 1435) {
ret = shell.su("resetprop -p " + MAGISKHIDE_PROP);
ret = Shell.su("resetprop -p " + MAGISKHIDE_PROP);
} else {
ret = shell.sh("getprop " + MAGISKHIDE_PROP);
ret = Shell.sh("getprop " + MAGISKHIDE_PROP);
}
try {
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0;

View File

@ -195,28 +195,28 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
case "disable":
enabled = prefs.getBoolean("disable", false);
if (enabled) {
Utils.createFile(getShell(), MagiskManager.MAGISK_DISABLE_FILE);
Utils.createFile(MagiskManager.MAGISK_DISABLE_FILE);
} else {
Utils.removeItem(getShell(), MagiskManager.MAGISK_DISABLE_FILE);
Utils.removeItem(MagiskManager.MAGISK_DISABLE_FILE);
}
Toast.makeText(getActivity(), R.string.settings_reboot_toast, Toast.LENGTH_LONG).show();
break;
case "magiskhide":
enabled = prefs.getBoolean("magiskhide", false);
if (enabled) {
Utils.enableMagiskHide(getShell());
Utils.enableMagiskHide();
} else {
Utils.disableMagiskHide(getShell());
Utils.disableMagiskHide();
}
break;
case "hosts":
enabled = prefs.getBoolean("hosts", false);
if (enabled) {
getShell().su_raw(
Shell.su_raw(
"cp -af /system/etc/hosts " + MagiskManager.MAGISK_HOST_FILE,
"mount -o bind " + MagiskManager.MAGISK_HOST_FILE + " /system/etc/hosts");
} else {
getShell().su_raw(
Shell.su_raw(
"umount -l /system/etc/hosts",
"rm -f " + MagiskManager.MAGISK_HOST_FILE);
}
@ -243,10 +243,6 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
setSummary();
}
private Shell getShell() {
return Shell.getShell(getActivity());
}
private void setSummary() {
updateChannel.setSummary(getResources()
.getStringArray(R.array.update_channel)[mm.updateChannel]);

View File

@ -16,7 +16,6 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
@ -47,7 +46,6 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
private PackageManager pm;
private ApplicationFilter filter;
private Topic magiskHideDone;
private Shell shell;
public ApplicationAdapter(Context context) {
mOriginalList = mList = Collections.emptyList();
@ -55,7 +53,6 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
filter = new ApplicationFilter();
pm = context.getPackageManager();
magiskHideDone = Utils.getMagiskManager(context).magiskHideDone;
shell = Shell.getShell(context);
new LoadApps().exec();
}
@ -89,10 +86,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
holder.checkBox.setChecked(mHideList.contains(info.packageName));
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
if (isChecked) {
Utils.addMagiskHide(shell, info.packageName);
Utils.addMagiskHide(info.packageName);
mHideList.add(info.packageName);
} else {
Utils.rmMagiskHide(shell, info.packageName);
Utils.rmMagiskHide(info.packageName);
mHideList.remove(info.packageName);
}
});
@ -163,7 +160,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
}
Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
mHideList = Utils.listMagiskHide(shell);
mHideList = Utils.listMagiskHide();
return null;
}

View File

@ -38,7 +38,6 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Context context = holder.itemView.getContext();
Shell rootShell = Shell.getShell(context);
final Module module = mList.get(position);
String version = module.getVersion();
@ -56,10 +55,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
int snack;
if (isChecked) {
module.removeDisableFile(rootShell);
module.removeDisableFile();
snack = R.string.disable_file_removed;
} else {
module.createDisableFile(rootShell);
module.createDisableFile();
snack = R.string.disable_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();
@ -69,10 +68,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
boolean removed = module.willBeRemoved();
int snack;
if (removed) {
module.deleteRemoveFile(rootShell);
module.deleteRemoveFile();
snack = R.string.remove_file_deleted;
} else {
module.createRemoveFile(rootShell);
module.createRemoveFile();
snack = R.string.remove_file_created;
}
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show();

View File

@ -4,6 +4,7 @@ import android.support.v4.app.FragmentActivity;
import com.topjohnwu.jarsigner.ByteArrayStream;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.WebService;
import java.io.BufferedOutputStream;
@ -34,7 +35,7 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
protected void onPreExecute() {
MagiskManager mm = getMagiskManager();
if (mm.snet_version != CheckSafetyNet.SNET_VER) {
getShell().sh("rm -rf " + dexPath.getParent());
Shell.sh("rm -rf " + dexPath.getParent());
}
mm.snet_version = CheckSafetyNet.SNET_VER;
mm.prefs.edit().putInt("snet_version", CheckSafetyNet.SNET_VER).apply();

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.os.Build;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
@ -28,7 +29,7 @@ public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
Context context = getMagiskManager();
Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox");
Utils.removeItem(context.getApplicationInfo().dataDir + "/busybox");
try {
FileOutputStream out = new FileOutputStream(busybox);
HttpURLConnection conn = WebService.request(
@ -50,7 +51,7 @@ public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
e.printStackTrace();
}
if (busybox.exists()) {
getShell().su(
Shell.su(
"rm -rf " + MagiskManager.BUSYBOXPATH,
"mkdir -p " + MagiskManager.BUSYBOXPATH,
"cp " + busybox + " " + MagiskManager.BUSYBOXPATH,

View File

@ -7,6 +7,7 @@ import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.AdaptiveList;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;
@ -35,7 +36,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
private boolean unzipAndCheck() throws Exception {
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true);
List<String> ret = Utils.readFile(getShell(), new File(mCachedFile.getParentFile(), "updater-script").getPath());
List<String> ret = Utils.readFile(new File(mCachedFile.getParentFile(), "updater-script").getPath());
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
}
@ -77,7 +78,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
}
if (!unzipAndCheck()) return 0;
mList.add("- Installing " + Utils.getNameFromUri(mm, mUri));
getShell().su(mList,
Shell.su(mList,
"cd " + mCachedFile.getParent(),
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile +
" && echo 'Success!' || echo 'Failed!'"
@ -95,7 +96,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
protected void onPostExecute(Integer result) {
MagiskManager mm = getMagiskManager();
if (mm == null) return;
getShell().su_raw(
Shell.su_raw(
"rm -rf " + mCachedFile.getParent(),
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
);

View File

@ -9,6 +9,7 @@ import com.topjohnwu.jarsigner.JarMap;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;
@ -78,7 +79,7 @@ public class HideManager extends ParallelTask<Void, Void, Boolean> {
}
// Install the application
List<String> ret = getShell().su("pm install " + unhideAPK + ">/dev/null && echo true || echo false");
List<String> ret = Shell.su("pm install " + unhideAPK + ">/dev/null && echo true || echo false");
unhideAPK.delete();
if (!Utils.isValidShellResponse(ret) || !Boolean.parseBoolean(ret.get(0)))
return false;
@ -98,7 +99,7 @@ public class HideManager extends ParallelTask<Void, Void, Boolean> {
}
// Hide myself!
getShell().su_raw("pm hide " + mm.getPackageName());
Shell.su_raw("pm hide " + mm.getPackageName());
return true;
}

View File

@ -76,7 +76,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
if (mm == null) return false;
File install = new File(Utils.getEncContext(mm).getFilesDir().getParent(), "install");
getShell().sh_raw("rm -rf " + install);
Shell.sh_raw("rm -rf " + install);
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
String arch;
@ -157,13 +157,16 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
Shell shell;
if (mode == PATCH_MODE && Shell.rootAccess()) {
// Force non-root shell
shell = Shell.getShell("sh");
shell = new Shell("sh");
} else {
shell = getShell();
shell = Shell.getShell();
}
if (shell == null)
return false;
// Patch boot image
shell.sh(mList,
shell.run(mList,
"cd " + install,
"KEEPFORCEENCRYPT=" + mKeepEnc + " KEEPVERITY=" + mKeepVerity + " sh " +
"update-binary indep boot_patch.sh " + boot +
@ -181,7 +184,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
dest.getParentFile().mkdirs();
switch (mm.bootFormat) {
case ".img":
getShell().sh_raw("cp -f " + patched_boot + " " + dest);
shell.run_raw(false, "cp -f " + patched_boot + " " + dest);
break;
case ".img.tar":
TarOutputStream tar = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
@ -204,14 +207,14 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
break;
case DIRECT_MODE:
// Direct flash boot image
getShell().su(mList, "flash_boot_image " + patched_boot + " " + mBootLocation);
Shell.su(mList, "flash_boot_image " + patched_boot + " " + mBootLocation);
break;
default:
return false;
}
// Finals
getShell().sh_raw(
shell.run_raw(false,
"cd " + install,
"mv bin/busybox busybox",
"rm -rf bin *.img update-binary",

View File

@ -19,8 +19,8 @@ public class LoadModules extends ParallelTask<Void, Void, Void> {
if (mm == null) return null;
mm.moduleMap = new ValueSortedMap<>();
for (String path : Utils.getModList(getShell(), MagiskManager.MAGISK_PATH)) {
Module module = new Module(getShell(), path);
for (String path : Utils.getModList(MagiskManager.MAGISK_PATH)) {
Module module = new Module(path);
mm.moduleMap.put(module.getId(), module);
}

View File

@ -5,7 +5,6 @@ import android.content.Context;
import android.os.AsyncTask;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.lang.ref.WeakReference;
@ -36,11 +35,6 @@ public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<P
return weakMagiskManager.get();
}
protected Shell getShell() {
MagiskManager magiskManager = getMagiskManager();
return magiskManager == null ? null : Shell.getShell(magiskManager);
}
@SuppressWarnings("unchecked")
public ParallelTask<Params, Progress, Result> exec(Params... params) {
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.widget.Toast;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import java.util.List;
@ -19,13 +20,13 @@ public class RestoreStockBoot extends ParallelTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... voids) {
List<String> ret = getShell().su("cat /init.magisk.rc | grep STOCKSHA1");
List<String> ret = Shell.su("cat /init.magisk.rc | grep STOCKSHA1");
if (!Utils.isValidShellResponse(ret))
return false;
String stock_boot = "/data/stock_boot_" + ret.get(0).substring(ret.get(0).indexOf('=') + 1) + ".img.gz";
if (!Utils.itemExist(getShell(), stock_boot))
if (!Utils.itemExist(stock_boot))
return false;
getShell().su_raw("flash_boot_image " + stock_boot + " " + mBoot);
Shell.su_raw("flash_boot_image " + stock_boot + " " + mBoot);
return true;
}

View File

@ -10,7 +10,6 @@ import android.view.WindowManager;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Topic;
public class Activity extends AppCompatActivity {
@ -58,10 +57,6 @@ public class Activity extends AppCompatActivity {
return (MagiskManager) super.getApplicationContext();
}
public Shell getShell() {
return Shell.getShell(this);
}
protected void setFloating() {
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
if (isTablet) {

View File

@ -3,7 +3,6 @@ package com.topjohnwu.magisk.components;
import android.content.Intent;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
@ -15,10 +14,6 @@ public class Fragment extends android.support.v4.app.Fragment {
return Utils.getMagiskManager(getActivity());
}
public Shell getShell() {
return Shell.getShell(getActivity());
}
@Override
public void onResume() {
super.onResume();

View File

@ -1,6 +1,5 @@
package com.topjohnwu.magisk.container;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
public class Module extends BaseModule {
@ -8,10 +7,10 @@ public class Module extends BaseModule {
private String mRemoveFile, mDisableFile, mUpdateFile;
private boolean mEnable, mRemove, mUpdated;
public Module(Shell shell, String path) {
public Module(String path) {
try {
parseProps(Utils.readFile(shell, path + "/module.prop"));
parseProps(Utils.readFile(path + "/module.prop"));
} catch (NumberFormatException ignored) {}
mRemoveFile = path + "/remove";
@ -27,33 +26,33 @@ public class Module extends BaseModule {
setName(getId());
}
mEnable = !Utils.itemExist(shell, mDisableFile);
mRemove = Utils.itemExist(shell, mRemoveFile);
mUpdated = Utils.itemExist(shell, mUpdateFile);
mEnable = !Utils.itemExist(mDisableFile);
mRemove = Utils.itemExist(mRemoveFile);
mUpdated = Utils.itemExist(mUpdateFile);
}
public void createDisableFile(Shell shell) {
public void createDisableFile() {
mEnable = false;
Utils.createFile(shell, mDisableFile);
Utils.createFile(mDisableFile);
}
public void removeDisableFile(Shell shell) {
public void removeDisableFile() {
mEnable = true;
Utils.removeItem(shell, mDisableFile);
Utils.removeItem(mDisableFile);
}
public boolean isEnabled() {
return mEnable;
}
public void createRemoveFile(Shell shell) {
public void createRemoveFile() {
mRemove = true;
Utils.createFile(shell, mRemoveFile);
Utils.createFile(mRemoveFile);
}
public void deleteRemoveFile(Shell shell) {
public void deleteRemoveFile() {
mRemove = false;
Utils.removeItem(shell, mRemoveFile);
Utils.removeItem(mRemoveFile);
}
public boolean willBeRemoved() {

View File

@ -6,11 +6,11 @@ import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -21,116 +21,103 @@ import java.util.List;
public class Shell {
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted
public static int rootStatus;
private static WeakReference<MagiskManager> weakMm;
private final Process shellProcess;
private final DataOutputStream STDIN;
private final DataInputStream STDOUT;
// -1 = no shell; 0 = non root shell; 1 = root shell
public static int status;
private boolean isValid;
private final Process process;
private final OutputStream STDIN;
private final InputStream STDOUT;
private void testRootShell(DataOutputStream in, DataInputStream out) throws IOException {
in.write(("id\n").getBytes("UTF-8"));
in.flush();
String s = new BufferedReader(new InputStreamReader(out)).readLine();
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")) {
in.close();
out.close();
shell.STDIN.close();
shell.STDIN.close();
throw new IOException();
}
}
private Shell() {
rootStatus = 1;
Process process = null;
DataOutputStream in = null;
DataInputStream out = null;
try {
// Try getting global namespace
process = Runtime.getRuntime().exec("su --mount-master");
in = new DataOutputStream(process.getOutputStream());
out = new DataInputStream(process.getInputStream());
testRootShell(in, out);
} catch (IOException e) {
// Feature not implemented, normal root shell
try {
process = Runtime.getRuntime().exec("su");
in = new DataOutputStream(process.getOutputStream());
out = new DataInputStream(process.getInputStream());
testRootShell(in, out);
} catch (IOException e1) {
rootStatus = 0;
}
}
if (!rootAccess()) {
// Try to gain non-root sh
try {
process = Runtime.getRuntime().exec("sh");
in = new DataOutputStream(process.getOutputStream());
out = new DataInputStream(process.getInputStream());
} catch (IOException e) {
// Nothing works....
shellProcess = null;
STDIN = null;
STDOUT = null;
isValid = false;
return;
}
}
isValid = true;
shellProcess = process;
STDIN = in;
STDOUT = out;
sh_raw("umask 022");
public Shell(String command) throws IOException {
process = Runtime.getRuntime().exec(command);
STDIN = process.getOutputStream();
STDOUT = process.getInputStream();
}
private Shell(String command) {
Process process;
DataOutputStream in;
DataInputStream out;
try {
process = Runtime.getRuntime().exec(command);
in = new DataOutputStream(process.getOutputStream());
out = new DataInputStream(process.getInputStream());
} catch (IOException e) {
// Nothing works....
shellProcess = null;
STDIN = null;
STDOUT = null;
isValid = false;
return;
}
isValid = true;
shellProcess = process;
STDIN = in;
STDOUT = out;
public static void registerShell(Context context) {
weakMm = new WeakReference<>(Utils.getMagiskManager(context));
}
public static Shell getShell() {
return new Shell();
}
MagiskManager mm = weakMm.get();
boolean needNewShell = mm.shell == null;
public static Shell getShell(String command) {
return new Shell(command);
}
public static Shell getShell(Context context) {
MagiskManager magiskManager = Utils.getMagiskManager(context);
if (magiskManager.shell == null || !magiskManager.shell.isValid) {
// Get new shell if needed
magiskManager.shell = getShell();
if (!needNewShell) {
try {
mm.shell.process.exitValue();
// The process is dead
needNewShell = true;
} catch (IllegalThreadStateException ignored) {
// This should be the expected result
}
}
return magiskManager.shell;
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;
}
}
}
}
return mm.shell;
}
public static boolean rootAccess() {
return rootStatus > 0;
return status > 0;
}
public void run(Collection<String> output, String... commands) {
synchronized (process) {
StreamGobbler out = new StreamGobbler(STDOUT, output);
out.start();
run_raw(true, commands);
run_raw(true, "echo \'-shell-done-\'");
try { out.join(); } catch (InterruptedException ignored) {}
}
}
public void run_raw(boolean stdout, String... commands) {
synchronized (process) {
try {
for (String command : commands) {
Logger.shell(command);
STDIN.write((command + (stdout ? "\n" : " >/dev/null\n")).getBytes("UTF-8"));
STDIN.flush();
}
} catch (IOException e) {
e.printStackTrace();
process.destroy();
}
}
}
public void loadInputStream(InputStream in) {
@ -146,67 +133,41 @@ public class Shell {
}
}
public List<String> sh(String... commands) {
public static List<String> sh(String... commands) {
List<String> res = new ArrayList<>();
if (!isValid) return res;
sh(res, commands);
return res;
}
public void sh_raw(String... commands) {
sh_raw(false, commands);
public static void sh(Collection<String> output, String... commands) {
Shell shell = getShell();
if (shell == null)
return;
shell.run(output, commands);
}
public void sh_raw(boolean stdout, String... commands) {
if (!isValid) return;
synchronized (shellProcess) {
try {
for (String command : commands) {
Logger.shell(command);
STDIN.write((command + (stdout ? "\n" : " >/dev/null\n")).getBytes("UTF-8"));
STDIN.flush();
}
} catch (IOException e) {
e.printStackTrace();
shellProcess.destroy();
isValid = false;
}
}
public static void sh_raw(String... commands) {
Shell shell = getShell();
if (shell == null)
return;
shell.run_raw(false, commands);
}
public void sh(Collection<String> output, String... commands) {
if (!isValid) return;
try {
shellProcess.exitValue();
isValid = false;
return; // The process is dead, return
} catch (IllegalThreadStateException ignored) {
// This should be the expected result
}
synchronized (shellProcess) {
StreamGobbler out = new StreamGobbler(STDOUT, output);
out.start();
sh_raw(true, commands);
sh_raw(true, "echo \'-shell-done-\'");
try { out.join(); } catch (InterruptedException ignored) {}
}
}
public List<String> su(String... commands) {
public static List<String> su(String... commands) {
if (!rootAccess()) return sh();
return sh(commands);
}
public void su_raw(String... commands) {
if (!rootAccess()) return;
sh_raw(commands);
}
public void su(Collection<String> output, String... 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

View File

@ -62,31 +62,31 @@ public class Utils {
private static final int MAGISK_UPDATE_NOTIFICATION_ID = 1;
private static final int APK_UPDATE_NOTIFICATION_ID = 2;
public static boolean itemExist(Shell shell, String path) {
public static boolean itemExist(String path) {
String command = "[ -e " + path + " ] && echo true || echo false";
List<String> ret = shell.su(command);
List<String> ret = Shell.su(command);
return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0));
}
public static void createFile(Shell shell, String path) {
public static void createFile(String path) {
String folder = path.substring(0, path.lastIndexOf('/'));
String command = "mkdir -p " + folder + " 2>/dev/null; touch " + path + " 2>/dev/null;";
shell.su_raw(command);
Shell.su_raw(command);
}
public static void removeItem(Shell shell, String path) {
public static void removeItem(String path) {
String command = "rm -rf " + path + " 2>/dev/null";
shell.su_raw(command);
Shell.su_raw(command);
}
public static List<String> getModList(Shell shell, String path) {
public static List<String> getModList(String path) {
String command = "ls -d " + path + "/* | grep -v lost+found";
return shell.su(command);
return Shell.su(command);
}
public static List<String> readFile(Shell shell, String path) {
public static List<String> readFile(String path) {
String command = "cat " + path + " | sed '$a\\ ' | sed '$d'";
return shell.su(command);
return Shell.su(command);
}
public static void dlAndReceive(Context context, DownloadReceiver receiver, String link, String filename) {
@ -225,24 +225,24 @@ public class Utils {
notificationManager.notify(APK_UPDATE_NOTIFICATION_ID, builder.build());
}
public static void enableMagiskHide(Shell shell) {
shell.su_raw("magiskhide --enable");
public static void enableMagiskHide() {
Shell.su_raw("magiskhide --enable");
}
public static void disableMagiskHide(Shell shell) {
shell.su_raw("magiskhide --disable");
public static void disableMagiskHide() {
Shell.su_raw("magiskhide --disable");
}
public static List<String> listMagiskHide(Shell shell) {
return shell.su("magiskhide --ls");
public static List<String> listMagiskHide() {
return Shell.su("magiskhide --ls");
}
public static void addMagiskHide(Shell shell, String pkg) {
shell.su_raw("magiskhide --add " + pkg);
public static void addMagiskHide(String pkg) {
Shell.su_raw("magiskhide --add " + pkg);
}
public static void rmMagiskHide(Shell shell, String pkg) {
shell.su_raw("magiskhide --rm " + pkg);
public static void rmMagiskHide(String pkg) {
Shell.su_raw("magiskhide --rm " + pkg);
}
public static String getLocaleString(Context context, Locale locale, @StringRes int id) {
@ -331,7 +331,7 @@ public class Utils {
if (Shell.rootAccess()) {
options.add(mm.getString(R.string.direct_install));
}
List<String> res = Shell.getShell(mm).su("echo $SLOT");
List<String> res = Shell.su("echo $SLOT");
if (isValidShellResponse(res)) {
options.add(mm.getString(R.string.install_second_slot));
}
@ -409,14 +409,14 @@ public class Utils {
if (slot[1] == 'a') slot[1] = 'b';
else slot[1] = 'a';
// Then find the boot image again
List<String> ret = Shell.getShell(mm).su(
List<String> ret = Shell.su(
"BOOTIMAGE=",
"SLOT=" + String.valueOf(slot),
"find_boot_image",
"echo \"$BOOTIMAGE\""
);
boot = isValidShellResponse(ret) ? ret.get(ret.size() - 1) : null;
Shell.getShell(mm).su_raw("mount_partitions");
Shell.su_raw("mount_partitions");
if (boot == null)
return;
receiver = new DownloadReceiver() {
@ -497,12 +497,12 @@ public class Utils {
}
in.close();
out.close();
Shell.getShell(mm).su(
Shell.su(
"cat " + uninstaller + " > /cache/" + UNINSTALLER,
"cat " + utils + " > /data/magisk/" + UTIL_FUNCTIONS
);
mm.toast(R.string.uninstall_toast, Toast.LENGTH_LONG);
Shell.getShell(mm).su_raw(
Shell.su_raw(
"sleep 5",
"pm uninstall " + mm.getApplicationInfo().packageName
);