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

View File

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

View File

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

View File

@ -208,7 +208,7 @@ public class MagiskManager extends Application {
// Root actions // Root actions
if (Shell.rootAccess()) { if (Shell.rootAccess()) {
if (hasNetwork && !Utils.itemExist(shell, BUSYBOXPATH + "/busybox")) { if (hasNetwork && !Utils.itemExist(BUSYBOXPATH + "/busybox")) {
try { try {
// Force synchronous, make sure we have busybox to use // Force synchronous, make sure we have busybox to use
new DownloadBusybox(this).exec().get(); new DownloadBusybox(this).exec().get();
@ -223,7 +223,7 @@ public class MagiskManager extends Application {
e.printStackTrace(); e.printStackTrace();
} }
shell.su_raw( Shell.su_raw(
"export PATH=" + BUSYBOXPATH + ":$PATH", "export PATH=" + BUSYBOXPATH + ":$PATH",
"mount_partitions", "mount_partitions",
"BOOTIMAGE=", "BOOTIMAGE=",
@ -231,11 +231,11 @@ public class MagiskManager extends Application {
"migrate_boot_backup" "migrate_boot_backup"
); );
List<String> res = shell.su("echo \"$BOOTIMAGE\""); List<String> res = Shell.su("echo \"$BOOTIMAGE\"");
if (Utils.isValidShellResponse(res)) { if (Utils.isValidShellResponse(res)) {
bootBlock = res.get(0); bootBlock = res.get(0);
} else { } 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("dark_theme", isDarkTheme)
.putBoolean("magiskhide", magiskHide) .putBoolean("magiskhide", magiskHide)
.putBoolean("notification", updateNotification) .putBoolean("notification", updateNotification)
.putBoolean("hosts", Utils.itemExist(shell, MAGISK_HOST_FILE)) .putBoolean("hosts", Utils.itemExist(MAGISK_HOST_FILE))
.putBoolean("disable", Utils.itemExist(shell, MAGISK_DISABLE_FILE)) .putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
.putBoolean("su_reauth", suReauth) .putBoolean("su_reauth", suReauth)
.putString("su_request_timeout", String.valueOf(suRequestTimeout)) .putString("su_request_timeout", String.valueOf(suRequestTimeout))
.putString("su_auto_response", String.valueOf(suResponseType)) .putString("su_auto_response", String.valueOf(suResponseType))
@ -284,15 +284,15 @@ public class MagiskManager extends Application {
public void getMagiskInfo() { public void getMagiskInfo() {
List<String> ret; List<String> ret;
Shell.getShell(this); Shell.registerShell(this);
ret = shell.sh("su -v"); ret = Shell.sh("su -v");
if (Utils.isValidShellResponse(ret)) { if (Utils.isValidShellResponse(ret)) {
suVersion = ret.get(0); suVersion = ret.get(0);
isSuClient = suVersion.toUpperCase().contains("MAGISK"); isSuClient = suVersion.toUpperCase().contains("MAGISK");
} }
ret = shell.sh("magisk -v"); ret = Shell.sh("magisk -v");
if (!Utils.isValidShellResponse(ret)) { if (!Utils.isValidShellResponse(ret)) {
ret = shell.sh("getprop magisk.version"); ret = Shell.sh("getprop magisk.version");
if (Utils.isValidShellResponse(ret)) { if (Utils.isValidShellResponse(ret)) {
try { try {
magiskVersionString = ret.get(0); magiskVersionString = ret.get(0);
@ -301,21 +301,21 @@ public class MagiskManager extends Application {
} }
} else { } else {
magiskVersionString = ret.get(0).split(":")[0]; magiskVersionString = ret.get(0).split(":")[0];
ret = shell.sh("magisk -V"); ret = Shell.sh("magisk -V");
try { try {
magiskVersionCode = Integer.parseInt(ret.get(0)); magiskVersionCode = Integer.parseInt(ret.get(0));
} catch (NumberFormatException ignored) {} } catch (NumberFormatException ignored) {}
} }
ret = shell.sh("getprop " + DISABLE_INDICATION_PROP); ret = Shell.sh("getprop " + DISABLE_INDICATION_PROP);
try { try {
disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0; disabled = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
disabled = false; disabled = false;
} }
if (magiskVersionCode > 1435) { if (magiskVersionCode > 1435) {
ret = shell.su("resetprop -p " + MAGISKHIDE_PROP); ret = Shell.su("resetprop -p " + MAGISKHIDE_PROP);
} else { } else {
ret = shell.sh("getprop " + MAGISKHIDE_PROP); ret = Shell.sh("getprop " + MAGISKHIDE_PROP);
} }
try { try {
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0; 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": case "disable":
enabled = prefs.getBoolean("disable", false); enabled = prefs.getBoolean("disable", false);
if (enabled) { if (enabled) {
Utils.createFile(getShell(), MagiskManager.MAGISK_DISABLE_FILE); Utils.createFile(MagiskManager.MAGISK_DISABLE_FILE);
} else { } 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(); Toast.makeText(getActivity(), R.string.settings_reboot_toast, Toast.LENGTH_LONG).show();
break; break;
case "magiskhide": case "magiskhide":
enabled = prefs.getBoolean("magiskhide", false); enabled = prefs.getBoolean("magiskhide", false);
if (enabled) { if (enabled) {
Utils.enableMagiskHide(getShell()); Utils.enableMagiskHide();
} else { } else {
Utils.disableMagiskHide(getShell()); Utils.disableMagiskHide();
} }
break; break;
case "hosts": case "hosts":
enabled = prefs.getBoolean("hosts", false); enabled = prefs.getBoolean("hosts", false);
if (enabled) { if (enabled) {
getShell().su_raw( Shell.su_raw(
"cp -af /system/etc/hosts " + MagiskManager.MAGISK_HOST_FILE, "cp -af /system/etc/hosts " + MagiskManager.MAGISK_HOST_FILE,
"mount -o bind " + MagiskManager.MAGISK_HOST_FILE + " /system/etc/hosts"); "mount -o bind " + MagiskManager.MAGISK_HOST_FILE + " /system/etc/hosts");
} else { } else {
getShell().su_raw( Shell.su_raw(
"umount -l /system/etc/hosts", "umount -l /system/etc/hosts",
"rm -f " + MagiskManager.MAGISK_HOST_FILE); "rm -f " + MagiskManager.MAGISK_HOST_FILE);
} }
@ -243,10 +243,6 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
setSummary(); setSummary();
} }
private Shell getShell() {
return Shell.getShell(getActivity());
}
private void setSummary() { private void setSummary() {
updateChannel.setSummary(getResources() updateChannel.setSummary(getResources()
.getStringArray(R.array.update_channel)[mm.updateChannel]); .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.R;
import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
@ -47,7 +46,6 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
private PackageManager pm; private PackageManager pm;
private ApplicationFilter filter; private ApplicationFilter filter;
private Topic magiskHideDone; private Topic magiskHideDone;
private Shell shell;
public ApplicationAdapter(Context context) { public ApplicationAdapter(Context context) {
mOriginalList = mList = Collections.emptyList(); mOriginalList = mList = Collections.emptyList();
@ -55,7 +53,6 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
filter = new ApplicationFilter(); filter = new ApplicationFilter();
pm = context.getPackageManager(); pm = context.getPackageManager();
magiskHideDone = Utils.getMagiskManager(context).magiskHideDone; magiskHideDone = Utils.getMagiskManager(context).magiskHideDone;
shell = Shell.getShell(context);
new LoadApps().exec(); new LoadApps().exec();
} }
@ -89,10 +86,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
holder.checkBox.setChecked(mHideList.contains(info.packageName)); holder.checkBox.setChecked(mHideList.contains(info.packageName));
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> { holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
if (isChecked) { if (isChecked) {
Utils.addMagiskHide(shell, info.packageName); Utils.addMagiskHide(info.packageName);
mHideList.add(info.packageName); mHideList.add(info.packageName);
} else { } else {
Utils.rmMagiskHide(shell, info.packageName); Utils.rmMagiskHide(info.packageName);
mHideList.remove(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() Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
.compareTo(b.loadLabel(pm).toString().toLowerCase())); .compareTo(b.loadLabel(pm).toString().toLowerCase()));
mHideList = Utils.listMagiskHide(shell); mHideList = Utils.listMagiskHide();
return null; return null;
} }

View File

@ -38,7 +38,6 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
@Override @Override
public void onBindViewHolder(final ViewHolder holder, int position) { public void onBindViewHolder(final ViewHolder holder, int position) {
Context context = holder.itemView.getContext(); Context context = holder.itemView.getContext();
Shell rootShell = Shell.getShell(context);
final Module module = mList.get(position); final Module module = mList.get(position);
String version = module.getVersion(); String version = module.getVersion();
@ -56,10 +55,10 @@ public class ModulesAdapter extends RecyclerView.Adapter<ModulesAdapter.ViewHold
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> { holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
int snack; int snack;
if (isChecked) { if (isChecked) {
module.removeDisableFile(rootShell); module.removeDisableFile();
snack = R.string.disable_file_removed; snack = R.string.disable_file_removed;
} else { } else {
module.createDisableFile(rootShell); module.createDisableFile();
snack = R.string.disable_file_created; snack = R.string.disable_file_created;
} }
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show(); 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(); boolean removed = module.willBeRemoved();
int snack; int snack;
if (removed) { if (removed) {
module.deleteRemoveFile(rootShell); module.deleteRemoveFile();
snack = R.string.remove_file_deleted; snack = R.string.remove_file_deleted;
} else { } else {
module.createRemoveFile(rootShell); module.createRemoveFile();
snack = R.string.remove_file_created; snack = R.string.remove_file_created;
} }
SnackbarMaker.make(holder.itemView, snack, Snackbar.LENGTH_SHORT).show(); 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.jarsigner.ByteArrayStream;
import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.WebService; import com.topjohnwu.magisk.utils.WebService;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
@ -34,7 +35,7 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
protected void onPreExecute() { protected void onPreExecute() {
MagiskManager mm = getMagiskManager(); MagiskManager mm = getMagiskManager();
if (mm.snet_version != CheckSafetyNet.SNET_VER) { 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.snet_version = CheckSafetyNet.SNET_VER;
mm.prefs.edit().putInt("snet_version", CheckSafetyNet.SNET_VER).apply(); 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 android.os.Build;
import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService; import com.topjohnwu.magisk.utils.WebService;
@ -28,7 +29,7 @@ public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
@Override @Override
protected Void doInBackground(Void... voids) { protected Void doInBackground(Void... voids) {
Context context = getMagiskManager(); Context context = getMagiskManager();
Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox"); Utils.removeItem(context.getApplicationInfo().dataDir + "/busybox");
try { try {
FileOutputStream out = new FileOutputStream(busybox); FileOutputStream out = new FileOutputStream(busybox);
HttpURLConnection conn = WebService.request( HttpURLConnection conn = WebService.request(
@ -50,7 +51,7 @@ public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
e.printStackTrace(); e.printStackTrace();
} }
if (busybox.exists()) { if (busybox.exists()) {
getShell().su( Shell.su(
"rm -rf " + MagiskManager.BUSYBOXPATH, "rm -rf " + MagiskManager.BUSYBOXPATH,
"mkdir -p " + MagiskManager.BUSYBOXPATH, "mkdir -p " + MagiskManager.BUSYBOXPATH,
"cp " + busybox + " " + 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.MagiskManager;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.AdaptiveList; import com.topjohnwu.magisk.container.AdaptiveList;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils; import com.topjohnwu.magisk.utils.ZipUtils;
@ -35,7 +36,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
private boolean unzipAndCheck() throws Exception { private boolean unzipAndCheck() throws Exception {
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true); 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"); 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; if (!unzipAndCheck()) return 0;
mList.add("- Installing " + Utils.getNameFromUri(mm, mUri)); mList.add("- Installing " + Utils.getNameFromUri(mm, mUri));
getShell().su(mList, Shell.su(mList,
"cd " + mCachedFile.getParent(), "cd " + mCachedFile.getParent(),
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile + "BOOTMODE=true sh update-binary dummy 1 " + mCachedFile +
" && echo 'Success!' || echo 'Failed!'" " && echo 'Success!' || echo 'Failed!'"
@ -95,7 +96,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
protected void onPostExecute(Integer result) { protected void onPostExecute(Integer result) {
MagiskManager mm = getMagiskManager(); MagiskManager mm = getMagiskManager();
if (mm == null) return; if (mm == null) return;
getShell().su_raw( Shell.su_raw(
"rm -rf " + mCachedFile.getParent(), "rm -rf " + mCachedFile.getParent(),
"rm -rf " + MagiskManager.TMP_FOLDER_PATH "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.MagiskManager;
import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.container.Policy; import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils; import com.topjohnwu.magisk.utils.ZipUtils;
@ -78,7 +79,7 @@ public class HideManager extends ParallelTask<Void, Void, Boolean> {
} }
// Install the application // 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(); unhideAPK.delete();
if (!Utils.isValidShellResponse(ret) || !Boolean.parseBoolean(ret.get(0))) if (!Utils.isValidShellResponse(ret) || !Boolean.parseBoolean(ret.get(0)))
return false; return false;
@ -98,7 +99,7 @@ public class HideManager extends ParallelTask<Void, Void, Boolean> {
} }
// Hide myself! // Hide myself!
getShell().su_raw("pm hide " + mm.getPackageName()); Shell.su_raw("pm hide " + mm.getPackageName());
return true; return true;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,11 +6,11 @@ import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.MagiskManager;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -21,116 +21,103 @@ import java.util.List;
public class Shell { public class Shell {
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted private static WeakReference<MagiskManager> weakMm;
public static int rootStatus;
private final Process shellProcess; // -1 = no shell; 0 = non root shell; 1 = root shell
private final DataOutputStream STDIN; public static int status;
private final DataInputStream STDOUT;
private boolean isValid; private final Process process;
private final OutputStream STDIN;
private final InputStream STDOUT;
private void testRootShell(DataOutputStream in, DataInputStream out) throws IOException { private static void testRootShell(Shell shell) throws IOException {
in.write(("id\n").getBytes("UTF-8")); shell.STDIN.write(("id\n").getBytes("UTF-8"));
in.flush(); shell.STDIN.flush();
String s = new BufferedReader(new InputStreamReader(out)).readLine(); String s = new BufferedReader(new InputStreamReader(shell.STDOUT)).readLine();
if (TextUtils.isEmpty(s) || !s.contains("uid=0")) { if (TextUtils.isEmpty(s) || !s.contains("uid=0")) {
in.close(); shell.STDIN.close();
out.close(); shell.STDIN.close();
throw new IOException(); throw new IOException();
} }
} }
private Shell() { public Shell(String command) throws IOException {
rootStatus = 1; process = Runtime.getRuntime().exec(command);
Process process = null; STDIN = process.getOutputStream();
DataOutputStream in = null; STDOUT = process.getInputStream();
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");
} }
private Shell(String command) { public static void registerShell(Context context) {
Process process; weakMm = new WeakReference<>(Utils.getMagiskManager(context));
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 Shell getShell() { public static Shell getShell() {
return new Shell(); MagiskManager mm = weakMm.get();
} boolean needNewShell = mm.shell == null;
public static Shell getShell(String command) { if (!needNewShell) {
return new Shell(command); try {
} mm.shell.process.exitValue();
// The process is dead
public static Shell getShell(Context context) { needNewShell = true;
MagiskManager magiskManager = Utils.getMagiskManager(context); } catch (IllegalThreadStateException ignored) {
if (magiskManager.shell == null || !magiskManager.shell.isValid) { // This should be the expected result
// Get new shell if needed }
magiskManager.shell = getShell();
} }
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() { 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) { 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<>(); List<String> res = new ArrayList<>();
if (!isValid) return res;
sh(res, commands); sh(res, commands);
return res; return res;
} }
public void sh_raw(String... commands) { public static void sh(Collection<String> output, String... commands) {
sh_raw(false, commands); Shell shell = getShell();
if (shell == null)
return;
shell.run(output, commands);
} }
public void sh_raw(boolean stdout, String... commands) { public static void sh_raw(String... commands) {
if (!isValid) return; Shell shell = getShell();
synchronized (shellProcess) { if (shell == null)
try { return;
for (String command : commands) { shell.run_raw(false, 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 void sh(Collection<String> output, String... commands) { public static List<String> su(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) {
if (!rootAccess()) return sh(); if (!rootAccess()) return sh();
return sh(commands); return sh(commands);
} }
public void su_raw(String... commands) { public static void su(Collection<String> output, String... commands) {
if (!rootAccess()) return;
sh_raw(commands);
}
public void su(Collection<String> output, String... commands) {
if (!rootAccess()) return; if (!rootAccess()) return;
sh(output, commands); 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> { public static abstract class AbstractList<E> extends java.util.AbstractList<E> {
@Override @Override

View File

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