Merge shells
This commit is contained in:
parent
2ea046cd80
commit
6933bcf7bb
@ -35,7 +35,7 @@ public class FlashActivity extends Activity {
|
|||||||
|
|
||||||
@OnClick(R.id.reboot)
|
@OnClick(R.id.reboot)
|
||||||
public void reboot() {
|
public void reboot() {
|
||||||
Shell.getRootShell(this).su_raw("reboot");
|
Shell.getShell(this).su_raw("reboot");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,6 @@ import android.widget.Spinner;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
@ -105,25 +104,18 @@ public class MagiskFragment extends Fragment
|
|||||||
collapse();
|
collapse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.detect_bootimage)
|
|
||||||
public void toAutoDetect() {
|
|
||||||
if (magiskManager.bootBlock != null) {
|
|
||||||
spinner.setSelection(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.install_button)
|
@OnClick(R.id.install_button)
|
||||||
public void install() {
|
public void install() {
|
||||||
String bootImage = null;
|
String bootImage = null;
|
||||||
if (magiskManager.blockList != null) {
|
if (Shell.rootAccess()) {
|
||||||
int idx = spinner.getSelectedItemPosition();
|
|
||||||
if (magiskManager.bootBlock != null) {
|
if (magiskManager.bootBlock != null) {
|
||||||
bootImage = magiskManager.bootBlock;
|
bootImage = magiskManager.bootBlock;
|
||||||
} else {
|
} else {
|
||||||
|
int idx = spinner.getSelectedItemPosition();
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
bootImage = magiskManager.blockList.get(idx - 1);
|
bootImage = magiskManager.blockList.get(idx - 1);
|
||||||
} else {
|
} else {
|
||||||
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG);
|
SnackbarMaker.make(getActivity(), R.string.manual_boot_image, Snackbar.LENGTH_LONG).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,27 +127,32 @@ public class MagiskFragment extends Fragment
|
|||||||
.setMessage(getString(R.string.repo_install_msg, filename))
|
.setMessage(getString(R.string.repo_install_msg, filename))
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download,
|
.setPositiveButton(Shell.rootAccess() ? R.string.install : R.string.download,
|
||||||
(dialogInterface, i) -> Utils.dlAndReceive(
|
(d, i) ->
|
||||||
getActivity(),
|
Utils.dlAndReceive(
|
||||||
new DownloadReceiver() {
|
getActivity(),
|
||||||
private String boot = finalBootImage;
|
new DownloadReceiver() {
|
||||||
private boolean enc = keepEncChkbox.isChecked();
|
private String boot = finalBootImage;
|
||||||
private boolean verity = keepVerityChkbox.isChecked();
|
private boolean enc = keepEncChkbox.isChecked();
|
||||||
|
private boolean verity = keepVerityChkbox.isChecked();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDownloadDone(Uri uri, Context context) {
|
public void onDownloadDone(Uri uri, Context context) {
|
||||||
if (Shell.rootAccess()) {
|
if (Shell.rootAccess()) {
|
||||||
new SetInstallFlags(boot, enc, verity)
|
magiskManager.shell.su_raw(
|
||||||
.setCallBack(() -> startActivity(new Intent(context, FlashActivity.class).setData(uri)))
|
"rm -f /dev/.magisk",
|
||||||
.exec(context);
|
"echo \"BOOTIMAGE=" + boot + "\" >> /dev/.magisk",
|
||||||
} else {
|
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(enc) + "\" >> /dev/.magisk",
|
||||||
Utils.showUriSnack(getActivity(), uri);
|
"echo \"KEEPVERITY=" + String.valueOf(verity) + "\" >> /dev/.magisk"
|
||||||
}
|
);
|
||||||
}
|
startActivity(new Intent(context, FlashActivity.class).setData(uri));
|
||||||
},
|
} else {
|
||||||
magiskManager.magiskLink,
|
Utils.showUriSnack(getActivity(), uri);
|
||||||
Utils.getLegalFilename(filename)))
|
}
|
||||||
.setNeutralButton(R.string.release_notes, (dialog, which) -> {
|
}
|
||||||
|
},
|
||||||
|
magiskManager.magiskLink,
|
||||||
|
Utils.getLegalFilename(filename)))
|
||||||
|
.setNeutralButton(R.string.release_notes, (d, i) -> {
|
||||||
if (magiskManager.releaseNoteLink != null) {
|
if (magiskManager.releaseNoteLink != null) {
|
||||||
Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink));
|
Intent openReleaseNoteLink = new Intent(Intent.ACTION_VIEW, Uri.parse(magiskManager.releaseNoteLink));
|
||||||
openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
openReleaseNoteLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
@ -166,28 +163,6 @@ public class MagiskFragment extends Fragment
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SetInstallFlags extends ParallelTask<Context, Void, Void> {
|
|
||||||
|
|
||||||
private String boot;
|
|
||||||
private boolean enc, verity;
|
|
||||||
|
|
||||||
SetInstallFlags(String boot, boolean enc, boolean verity) {
|
|
||||||
this.boot = boot;
|
|
||||||
this.enc = enc;
|
|
||||||
this.verity = verity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Context... contexts) {
|
|
||||||
Shell.getRootShell(contexts[0]).su_raw("rm -f /dev/.magisk",
|
|
||||||
(boot != null) ? "echo \"BOOTIMAGE=" + boot + "\" >> /dev/.magisk" : "",
|
|
||||||
"echo \"KEEPFORCEENCRYPT=" + String.valueOf(enc) + "\" >> /dev/.magisk",
|
|
||||||
"echo \"KEEPVERITY=" + String.valueOf(verity) + "\" >> /dev/.magisk"
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.uninstall_button)
|
@OnClick(R.id.uninstall_button)
|
||||||
public void uninstall() {
|
public void uninstall() {
|
||||||
new AlertDialogBuilder(getActivity())
|
new AlertDialogBuilder(getActivity())
|
||||||
@ -225,7 +200,7 @@ public class MagiskFragment extends Fragment
|
|||||||
@Override
|
@Override
|
||||||
public void onFinish() {
|
public void onFinish() {
|
||||||
progress.setMessage(getString(R.string.reboot_countdown, 0));
|
progress.setMessage(getString(R.string.reboot_countdown, 0));
|
||||||
magiskManager.rootShell.su_raw(
|
magiskManager.shell.su_raw(
|
||||||
"mv -f " + uninstaller + " /cache/" + MagiskManager.UNINSTALLER,
|
"mv -f " + uninstaller + " /cache/" + MagiskManager.UNINSTALLER,
|
||||||
"mv -f " + utils + " /data/magisk/" + MagiskManager.UTIL_FUNCTIONS,
|
"mv -f " + utils + " /data/magisk/" + MagiskManager.UTIL_FUNCTIONS,
|
||||||
"reboot"
|
"reboot"
|
||||||
@ -314,8 +289,6 @@ public class MagiskFragment extends Fragment
|
|||||||
updateCheckUI();
|
updateCheckUI();
|
||||||
} else if (event == magiskManager.safetyNetDone) {
|
} else if (event == magiskManager.safetyNetDone) {
|
||||||
updateSafetyNetUI();
|
updateSafetyNetUI();
|
||||||
} else if (event == magiskManager.blockDetectionDone) {
|
|
||||||
updateInstallUI();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,11 +300,8 @@ public class MagiskFragment extends Fragment
|
|||||||
updateCheckUI();
|
updateCheckUI();
|
||||||
if (magiskManager.safetyNetDone.isTriggered)
|
if (magiskManager.safetyNetDone.isTriggered)
|
||||||
updateSafetyNetUI();
|
updateSafetyNetUI();
|
||||||
if (magiskManager.blockDetectionDone.isTriggered || !Shell.rootAccess())
|
|
||||||
updateInstallUI();
|
|
||||||
magiskManager.updateCheckDone.register(this);
|
magiskManager.updateCheckDone.register(this);
|
||||||
magiskManager.safetyNetDone.register(this);
|
magiskManager.safetyNetDone.register(this);
|
||||||
magiskManager.blockDetectionDone.register(this);
|
|
||||||
getActivity().setTitle(R.string.magisk);
|
getActivity().setTitle(R.string.magisk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +309,6 @@ public class MagiskFragment extends Fragment
|
|||||||
public void onStop() {
|
public void onStop() {
|
||||||
magiskManager.updateCheckDone.unRegister(this);
|
magiskManager.updateCheckDone.unRegister(this);
|
||||||
magiskManager.safetyNetDone.unRegister(this);
|
magiskManager.safetyNetDone.unRegister(this);
|
||||||
magiskManager.blockDetectionDone.unRegister(this);
|
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +320,8 @@ public class MagiskFragment extends Fragment
|
|||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
((MainActivity) getActivity()).checkHideSection();
|
((MainActivity) getActivity()).checkHideSection();
|
||||||
|
magiskManager.updateMagiskInfo();
|
||||||
|
|
||||||
final int ROOT = 0x1, NETWORK = 0x2, UPTODATE = 0x4;
|
final int ROOT = 0x1, NETWORK = 0x2, UPTODATE = 0x4;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
status |= Shell.rootAccess() ? ROOT : 0;
|
status |= Shell.rootAccess() ? ROOT : 0;
|
||||||
@ -362,14 +333,9 @@ public class MagiskFragment extends Fragment
|
|||||||
installOptionCard.setVisibility(Utils.checkBits(status, NETWORK, ROOT) ? View.VISIBLE : View.GONE);
|
installOptionCard.setVisibility(Utils.checkBits(status, NETWORK, ROOT) ? View.VISIBLE : View.GONE);
|
||||||
installButton.setVisibility(Utils.checkBits(status, NETWORK) ? View.VISIBLE : View.GONE);
|
installButton.setVisibility(Utils.checkBits(status, NETWORK) ? View.VISIBLE : View.GONE);
|
||||||
uninstallButton.setVisibility(Utils.checkBits(status, UPTODATE, ROOT) ? View.VISIBLE : View.GONE);
|
uninstallButton.setVisibility(Utils.checkBits(status, UPTODATE, ROOT) ? View.VISIBLE : View.GONE);
|
||||||
updateVersionUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateVersionUI() {
|
|
||||||
int image, color;
|
int image, color;
|
||||||
|
|
||||||
magiskManager.updateMagiskInfo();
|
|
||||||
|
|
||||||
if (magiskManager.magiskVersionCode < 0) {
|
if (magiskManager.magiskVersionCode < 0) {
|
||||||
color = colorBad;
|
color = colorBad;
|
||||||
image = R.drawable.ic_cancel;
|
image = R.drawable.ic_cancel;
|
||||||
@ -405,6 +371,25 @@ public class MagiskFragment extends Fragment
|
|||||||
|
|
||||||
rootStatusIcon.setImageResource(image);
|
rootStatusIcon.setImageResource(image);
|
||||||
rootStatusIcon.setColorFilter(color);
|
rootStatusIcon.setColorFilter(color);
|
||||||
|
|
||||||
|
if (!Shell.rootAccess()) {
|
||||||
|
installText.setText(R.string.download);
|
||||||
|
} else {
|
||||||
|
installText.setText(R.string.download_install);
|
||||||
|
|
||||||
|
List<String> items = new ArrayList<>();
|
||||||
|
if (magiskManager.bootBlock != null) {
|
||||||
|
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
|
||||||
|
spinner.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
items.add(getString(R.string.cannot_auto_detect));
|
||||||
|
items.addAll(magiskManager.blockList);
|
||||||
|
}
|
||||||
|
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
|
||||||
|
android.R.layout.simple_spinner_item, items);
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
spinner.setAdapter(adapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCheckUI() {
|
private void updateCheckUI() {
|
||||||
@ -428,28 +413,6 @@ public class MagiskFragment extends Fragment
|
|||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInstallUI() {
|
|
||||||
if (!Shell.rootAccess()) {
|
|
||||||
installText.setText(R.string.download);
|
|
||||||
} else {
|
|
||||||
installText.setText(R.string.download_install);
|
|
||||||
|
|
||||||
List<String> items = new ArrayList<>();
|
|
||||||
if (magiskManager.bootBlock != null) {
|
|
||||||
items.add(getString(R.string.auto_detect, magiskManager.bootBlock));
|
|
||||||
spinner.setEnabled(false);
|
|
||||||
} else {
|
|
||||||
items.add(getString(R.string.cannot_auto_detect));
|
|
||||||
items.addAll(magiskManager.blockList);
|
|
||||||
}
|
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
|
|
||||||
android.R.layout.simple_spinner_item, items);
|
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
||||||
spinner.setAdapter(adapter);
|
|
||||||
toAutoDetect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSafetyNetUI() {
|
private void updateSafetyNetUI() {
|
||||||
int image, color;
|
int image, color;
|
||||||
safetyNetProgress.setVisibility(View.GONE);
|
safetyNetProgress.setVisibility(View.GONE);
|
||||||
|
@ -142,7 +142,7 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
mode = (int) params[0];
|
mode = (int) params[0];
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 0:
|
case 0:
|
||||||
List<String> logList = Utils.readFile(magiskManager.rootShell, MAGISK_LOG);
|
List<String> logList = Utils.readFile(magiskManager.shell, MAGISK_LOG);
|
||||||
|
|
||||||
if (Utils.isValidShellResponse(logList)) {
|
if (Utils.isValidShellResponse(logList)) {
|
||||||
StringBuilder llog = new StringBuilder(15 * 10 * 1024);
|
StringBuilder llog = new StringBuilder(15 * 10 * 1024);
|
||||||
@ -154,7 +154,7 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
return "";
|
return "";
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
magiskManager.rootShell.su_raw("echo > " + MAGISK_LOG);
|
magiskManager.shell.su_raw("echo > " + 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 "";
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ public class MagiskLogFragment extends Fragment {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> in = Utils.readFile(magiskManager.rootShell, MAGISK_LOG);
|
List<String> in = Utils.readFile(magiskManager.shell, MAGISK_LOG);
|
||||||
|
|
||||||
if (Utils.isValidShellResponse(in)) {
|
if (Utils.isValidShellResponse(in)) {
|
||||||
try (FileWriter out = new FileWriter(targetFile)) {
|
try (FileWriter out = new FileWriter(targetFile)) {
|
||||||
|
@ -38,7 +38,6 @@ public class MagiskManager extends Application {
|
|||||||
public static final String NOTIFICATION_CHANNEL = "magisk_update_notice";
|
public static final String NOTIFICATION_CHANNEL = "magisk_update_notice";
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
public final CallbackEvent<Void> blockDetectionDone = new CallbackEvent<>();
|
|
||||||
public final CallbackEvent<Void> magiskHideDone = new CallbackEvent<>();
|
public final CallbackEvent<Void> magiskHideDone = new CallbackEvent<>();
|
||||||
public final CallbackEvent<Void> reloadMainActivity = new CallbackEvent<>();
|
public final CallbackEvent<Void> reloadMainActivity = new CallbackEvent<>();
|
||||||
public final CallbackEvent<Void> moduleLoadDone = new CallbackEvent<>();
|
public final CallbackEvent<Void> moduleLoadDone = new CallbackEvent<>();
|
||||||
@ -88,7 +87,7 @@ public class MagiskManager extends Application {
|
|||||||
// Global resources
|
// Global resources
|
||||||
public SharedPreferences prefs;
|
public SharedPreferences prefs;
|
||||||
public SuDatabaseHelper suDB;
|
public SuDatabaseHelper suDB;
|
||||||
public Shell rootShell;
|
public Shell shell;
|
||||||
|
|
||||||
private static Handler mHandler = new Handler();
|
private static Handler mHandler = new Handler();
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ public class MagiskManager extends Application {
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
new File(getApplicationInfo().dataDir).mkdirs(); /* Create the app data directory */
|
new File(getApplicationInfo().dataDir).mkdirs(); /* Create the app data directory */
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
rootShell = Shell.getRootShell();
|
shell = Shell.getShell();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toast(String msg, int duration) {
|
public void toast(String msg, int duration) {
|
||||||
@ -121,11 +120,12 @@ public class MagiskManager extends Application {
|
|||||||
updateNotification = prefs.getBoolean("notification", true);
|
updateNotification = prefs.getBoolean("notification", true);
|
||||||
initSU();
|
initSU();
|
||||||
updateMagiskInfo();
|
updateMagiskInfo();
|
||||||
|
updateBlockInfo();
|
||||||
// Initialize busybox
|
// Initialize busybox
|
||||||
File busybox = new File(getApplicationInfo().dataDir + "/busybox/busybox");
|
File busybox = new File(getApplicationInfo().dataDir + "/busybox/busybox");
|
||||||
if (!busybox.exists() || !TextUtils.equals(prefs.getString("busybox_version", ""), BUSYBOX_VERSION)) {
|
if (!busybox.exists() || !TextUtils.equals(prefs.getString("busybox_version", ""), BUSYBOX_VERSION)) {
|
||||||
busybox.getParentFile().mkdirs();
|
busybox.getParentFile().mkdirs();
|
||||||
rootShell.su_raw(
|
shell.su_raw(
|
||||||
"cp -f " + new File(getApplicationInfo().nativeLibraryDir, "libbusybox.so") + " " + busybox,
|
"cp -f " + new File(getApplicationInfo().nativeLibraryDir, "libbusybox.so") + " " + busybox,
|
||||||
"chmod -R 755 " + busybox.getParent(),
|
"chmod -R 755 " + busybox.getParent(),
|
||||||
busybox + " --install -s " + busybox.getParent()
|
busybox + " --install -s " + busybox.getParent()
|
||||||
@ -137,7 +137,7 @@ public class MagiskManager extends Application {
|
|||||||
.putBoolean("magiskhide", magiskHide)
|
.putBoolean("magiskhide", magiskHide)
|
||||||
.putBoolean("notification", updateNotification)
|
.putBoolean("notification", updateNotification)
|
||||||
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
||||||
.putBoolean("disable", Utils.itemExist(rootShell, MAGISK_DISABLE_FILE))
|
.putBoolean("disable", Utils.itemExist(shell, 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))
|
||||||
@ -148,7 +148,7 @@ public class MagiskManager extends Application {
|
|||||||
.putString("busybox_version", BUSYBOX_VERSION)
|
.putString("busybox_version", BUSYBOX_VERSION)
|
||||||
.apply();
|
.apply();
|
||||||
// Add busybox to PATH
|
// Add busybox to PATH
|
||||||
rootShell.su_raw("PATH=$PATH:" + busybox.getParent());
|
shell.su_raw("PATH=$PATH:" + busybox.getParent());
|
||||||
|
|
||||||
// Create notification channel on Android O
|
// Create notification channel on Android O
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@ -170,7 +170,7 @@ public class MagiskManager extends Application {
|
|||||||
public void initSU() {
|
public void initSU() {
|
||||||
initSUConfig();
|
initSUConfig();
|
||||||
|
|
||||||
List<String> ret = Shell.sh("su -v");
|
List<String> 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");
|
||||||
@ -184,9 +184,9 @@ public class MagiskManager extends Application {
|
|||||||
|
|
||||||
public void updateMagiskInfo() {
|
public void updateMagiskInfo() {
|
||||||
List<String> ret;
|
List<String> ret;
|
||||||
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);
|
||||||
@ -195,24 +195,39 @@ 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;
|
||||||
}
|
}
|
||||||
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;
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
magiskHide = true;
|
magiskHide = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBlockInfo() {
|
||||||
|
List<String> res = shell.su(
|
||||||
|
"for BLOCK in boot_a BOOT_A kern-a KERN-A android_boot ANDROID_BOOT kernel KERNEL boot BOOT lnx LNX; do",
|
||||||
|
"BOOTIMAGE=`ls /dev/block/by-name/$BLOCK || ls /dev/block/platform/*/by-name/$BLOCK || ls /dev/block/platform/*/*/by-name/$BLOCK` 2>/dev/null",
|
||||||
|
"[ ! -z \"$BOOTIMAGE\" ] && break",
|
||||||
|
"done",
|
||||||
|
"[ ! -z \"$BOOTIMAGE\" -a -L \"$BOOTIMAGE\" ] && BOOTIMAGE=`readlink $BOOTIMAGE`",
|
||||||
|
"echo \"$BOOTIMAGE\""
|
||||||
|
);
|
||||||
|
if (Utils.isValidShellResponse(res)) {
|
||||||
|
bootBlock = res.get(0);
|
||||||
|
} else {
|
||||||
|
blockList = shell.su("ls -d /dev/block/mmc* /dev/block/sd* 2>/dev/null");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -149,9 +149,9 @@ public class SettingsActivity extends Activity {
|
|||||||
case "disable":
|
case "disable":
|
||||||
enabled = prefs.getBoolean("disable", false);
|
enabled = prefs.getBoolean("disable", false);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Utils.createFile(magiskManager.rootShell, MagiskManager.MAGISK_DISABLE_FILE);
|
Utils.createFile(magiskManager.shell, MagiskManager.MAGISK_DISABLE_FILE);
|
||||||
} else {
|
} else {
|
||||||
Utils.removeItem(magiskManager.rootShell, MagiskManager.MAGISK_DISABLE_FILE);
|
Utils.removeItem(magiskManager.shell, 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;
|
||||||
@ -175,11 +175,11 @@ public class SettingsActivity extends Activity {
|
|||||||
case "hosts":
|
case "hosts":
|
||||||
enabled = prefs.getBoolean("hosts", false);
|
enabled = prefs.getBoolean("hosts", false);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
magiskManager.rootShell.su_raw(
|
magiskManager.shell.su_raw(
|
||||||
"cp -af /system/etc/hosts /magisk/.core/hosts",
|
"cp -af /system/etc/hosts /magisk/.core/hosts",
|
||||||
"mount -o bind /magisk/.core/hosts /system/etc/hosts");
|
"mount -o bind /magisk/.core/hosts /system/etc/hosts");
|
||||||
} else {
|
} else {
|
||||||
magiskManager.rootShell.su_raw(
|
magiskManager.shell.su_raw(
|
||||||
"umount -l /system/etc/hosts",
|
"umount -l /system/etc/hosts",
|
||||||
"rm -f /magisk/.core/hosts");
|
"rm -f /magisk/.core/hosts");
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import android.content.Intent;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.asyncs.GetBootBlocks;
|
|
||||||
import com.topjohnwu.magisk.asyncs.LoadApps;
|
import com.topjohnwu.magisk.asyncs.LoadApps;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
import com.topjohnwu.magisk.asyncs.LoadRepos;
|
||||||
@ -25,12 +24,13 @@ public class SplashActivity extends Activity{
|
|||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// Init the info and configs and root shell
|
// Init the info and configs and root sh
|
||||||
getApplicationContext().init();
|
getApplicationContext().init();
|
||||||
|
|
||||||
// Now fire all async tasks
|
// Now fire all async tasks
|
||||||
new GetBootBlocks(this).exec();
|
new LoadModules(this)
|
||||||
new LoadModules(this).setCallBack(() -> new LoadRepos(this).exec()).exec();
|
.setCallBack(() -> new LoadRepos(this).exec())
|
||||||
|
.exec();
|
||||||
new LoadApps(this).exec();
|
new LoadApps(this).exec();
|
||||||
|
|
||||||
if (Utils.checkNetworkStatus(this)) {
|
if (Utils.checkNetworkStatus(this)) {
|
||||||
|
@ -38,7 +38,7 @@ 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.getRootShell(context);
|
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();
|
||||||
|
@ -63,7 +63,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
|
|||||||
|
|
||||||
private boolean unzipAndCheck() throws Exception {
|
private boolean unzipAndCheck() throws Exception {
|
||||||
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
|
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android");
|
||||||
List<String> ret = Utils.readFile(magiskManager.rootShell, mCheckFile.getPath());
|
List<String> ret = Utils.readFile(magiskManager.shell, mCheckFile.getPath());
|
||||||
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
|
|||||||
copyToCache();
|
copyToCache();
|
||||||
if (!unzipAndCheck()) return 0;
|
if (!unzipAndCheck()) return 0;
|
||||||
mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
mList.add(magiskManager.getString(R.string.zip_install_progress_msg, mFilename));
|
||||||
magiskManager.rootShell.su(mList,
|
magiskManager.shell.su(mList,
|
||||||
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile +
|
"BOOTMODE=true sh " + mScriptFile + " dummy 1 " + mCachedFile +
|
||||||
" && echo 'Success!' || echo 'Failed!'"
|
" && echo 'Success!' || echo 'Failed!'"
|
||||||
);
|
);
|
||||||
@ -99,7 +99,7 @@ public class FlashZip extends ParallelTask<Void, String, Integer> {
|
|||||||
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Integer result) {
|
protected void onPostExecute(Integer result) {
|
||||||
magiskManager.rootShell.su_raw(
|
magiskManager.shell.su_raw(
|
||||||
"rm -rf " + mCachedFile.getParent() + "/*",
|
"rm -rf " + mCachedFile.getParent() + "/*",
|
||||||
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
"rm -rf " + MagiskManager.TMP_FOLDER_PATH
|
||||||
);
|
);
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.asyncs;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
public class GetBootBlocks extends ParallelTask<Void, Void, Void> {
|
|
||||||
|
|
||||||
public GetBootBlocks(Activity context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
magiskManager.blockList = magiskManager.rootShell.su(
|
|
||||||
"find /dev/block -type b -maxdepth 1 | grep -v -E \"loop|ram|dm-0\""
|
|
||||||
);
|
|
||||||
if (magiskManager.bootBlock == null) {
|
|
||||||
magiskManager.bootBlock = Utils.detectBootImage(magiskManager.rootShell);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void v) {
|
|
||||||
magiskManager.blockDetectionDone.trigger();
|
|
||||||
super.onPostExecute(v);
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,10 +21,10 @@ public class LoadModules extends ParallelTask<Void, Void, Void> {
|
|||||||
|
|
||||||
magiskManager.moduleMap = new ValueSortedMap<>();
|
magiskManager.moduleMap = new ValueSortedMap<>();
|
||||||
|
|
||||||
for (String path : Utils.getModList(magiskManager.rootShell, MagiskManager.MAGISK_PATH)) {
|
for (String path : Utils.getModList(magiskManager.shell, MagiskManager.MAGISK_PATH)) {
|
||||||
Logger.dev("LoadModules: Adding modules from " + path);
|
Logger.dev("LoadModules: Adding modules from " + path);
|
||||||
try {
|
try {
|
||||||
Module module = new Module(magiskManager.rootShell, path);
|
Module module = new Module(magiskManager.shell, path);
|
||||||
magiskManager.moduleMap.put(module.getId(), module);
|
magiskManager.moduleMap.put(module.getId(), module);
|
||||||
} catch (BaseModule.CacheModException ignored) {}
|
} catch (BaseModule.CacheModException ignored) {}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ public class MagiskHide extends ParallelTask<Object, Void, Void> {
|
|||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Object... params) {
|
protected Void doInBackground(Object... params) {
|
||||||
String command = (String) params[0];
|
String command = (String) params[0];
|
||||||
List<String> ret = magiskManager.rootShell.su("magiskhide --" + command);
|
List<String> ret = magiskManager.shell.su("magiskhide --" + command);
|
||||||
if (isList) {
|
if (isList) {
|
||||||
magiskManager.magiskHideList = ret;
|
magiskManager.magiskHideList = ret;
|
||||||
}
|
}
|
||||||
|
@ -37,13 +37,13 @@ public class Logger {
|
|||||||
dev(String.format(Locale.US, fmt, args));
|
dev(String.format(Locale.US, fmt, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void shell(boolean root, String line) {
|
public static void shell(String line) {
|
||||||
if (MagiskManager.shellLogging) {
|
if (MagiskManager.shellLogging) {
|
||||||
Log.d(DEBUG_TAG, (root ? "MANAGERSU: " : "MANAGERSH: ") + line);
|
Log.d(DEBUG_TAG, "SHELL: " + line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void shell(boolean root, String fmt, Object... args) {
|
public static void shell(String fmt, Object... args) {
|
||||||
shell(root, String.format(Locale.US, fmt, args));
|
shell(String.format(Locale.US, fmt, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,12 @@ package com.topjohnwu.magisk.utils;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,145 +19,133 @@ public class Shell {
|
|||||||
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted
|
// -1 = problematic/unknown issue; 0 = not rooted; 1 = properly rooted
|
||||||
public static int rootStatus;
|
public static int rootStatus;
|
||||||
|
|
||||||
private final Process rootShell;
|
private final Process shellProcess;
|
||||||
private final DataOutputStream rootSTDIN;
|
private final DataOutputStream STDIN;
|
||||||
private final DataInputStream rootSTDOUT;
|
private final DataInputStream STDOUT;
|
||||||
|
|
||||||
private boolean isValid;
|
private boolean isValid;
|
||||||
|
|
||||||
private Shell() {
|
private Shell() {
|
||||||
Process process;
|
rootStatus = 1;
|
||||||
|
Process process = null;
|
||||||
|
DataOutputStream in = null;
|
||||||
|
DataInputStream out = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
process = Runtime.getRuntime().exec("su");
|
process = Runtime.getRuntime().exec("su");
|
||||||
|
in = new DataOutputStream(process.getOutputStream());
|
||||||
|
out = new DataInputStream(process.getInputStream());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// No root
|
|
||||||
rootStatus = 0;
|
rootStatus = 0;
|
||||||
rootShell = null;
|
|
||||||
rootSTDIN = null;
|
|
||||||
rootSTDOUT = null;
|
|
||||||
isValid = false;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rootStatus = 1;
|
while (true) {
|
||||||
isValid = true;
|
if (rootAccess()) {
|
||||||
rootShell = process;
|
try {
|
||||||
rootSTDIN = new DataOutputStream(rootShell.getOutputStream());
|
in.write(("id\n").getBytes("UTF-8"));
|
||||||
rootSTDOUT = new DataInputStream(rootShell.getInputStream());
|
in.flush();
|
||||||
|
String s = new BufferedReader(new InputStreamReader(out)).readLine();
|
||||||
su_raw("umask 022");
|
if (s.isEmpty() || !s.contains("uid=0")) {
|
||||||
List<String> ret = su("echo -BOC-", "id");
|
in.close();
|
||||||
|
out.close();
|
||||||
if (ret.isEmpty()) {
|
process.destroy();
|
||||||
// Something wrong with root, not allowed?
|
throw new IOException();
|
||||||
rootStatus = -1;
|
}
|
||||||
return;
|
} catch (IOException e) {
|
||||||
}
|
rootStatus = -1;
|
||||||
|
continue;
|
||||||
for (String line : ret) {
|
}
|
||||||
if (line.contains("uid=")) {
|
break;
|
||||||
// id command is working, let's see if we are actually root
|
} else {
|
||||||
rootStatus = line.contains("uid=0") ? 1 : -1;
|
// Try to gain non-root sh
|
||||||
return;
|
try {
|
||||||
} else if (!line.contains("-BOC-")) {
|
process = Runtime.getRuntime().exec("sh");
|
||||||
rootStatus = -1;
|
in = new DataOutputStream(process.getOutputStream());
|
||||||
return;
|
out = new DataInputStream(process.getInputStream());
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Nothing works....
|
||||||
|
shellProcess = null;
|
||||||
|
STDIN = null;
|
||||||
|
STDOUT = null;
|
||||||
|
isValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isValid = true;
|
||||||
|
shellProcess = process;
|
||||||
|
STDIN = in;
|
||||||
|
STDOUT = out;
|
||||||
|
sh_raw("umask 022");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Shell getRootShell() {
|
public static Shell getShell() {
|
||||||
return new Shell();
|
return new Shell();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Shell getRootShell(Context context) {
|
public static Shell getShell(Context context) {
|
||||||
return Utils.getMagiskManager(context).rootShell;
|
return Utils.getMagiskManager(context).shell;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean rootAccess() {
|
public static boolean rootAccess() {
|
||||||
return rootStatus > 0;
|
return rootStatus > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> sh(String... commands) {
|
public 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();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> su(String... commands) {
|
|
||||||
if (!isValid) return null;
|
|
||||||
List<String> res = new ArrayList<>();
|
List<String> res = new ArrayList<>();
|
||||||
su(res, commands);
|
if (!isValid) return res;
|
||||||
|
sh(res, commands);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void su_raw(String... commands) {
|
public void sh_raw(String... commands) {
|
||||||
if (!isValid) return;
|
if (!isValid) return;
|
||||||
synchronized (rootShell) {
|
synchronized (shellProcess) {
|
||||||
try {
|
try {
|
||||||
for (String command : commands) {
|
for (String command : commands) {
|
||||||
rootSTDIN.write((command + "\n").getBytes("UTF-8"));
|
STDIN.write((command + "\n").getBytes("UTF-8"));
|
||||||
rootSTDIN.flush();
|
STDIN.flush();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
rootShell.destroy();
|
shellProcess.destroy();
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void su(List<String> output, String... commands) {
|
public void sh(List<String> output, String... commands) {
|
||||||
if (!isValid) return;
|
if (!isValid) return;
|
||||||
try {
|
try {
|
||||||
rootShell.exitValue();
|
shellProcess.exitValue();
|
||||||
isValid = false;
|
isValid = false;
|
||||||
return; // The process is dead, return
|
return; // The process is dead, return
|
||||||
} catch (IllegalThreadStateException ignored) {
|
} catch (IllegalThreadStateException ignored) {
|
||||||
// This should be the expected result
|
// This should be the expected result
|
||||||
}
|
}
|
||||||
synchronized (rootShell) {
|
synchronized (shellProcess) {
|
||||||
StreamGobbler STDOUT = new StreamGobbler(rootSTDOUT, output, true);
|
StreamGobbler out = new StreamGobbler(this.STDOUT, output);
|
||||||
STDOUT.start();
|
out.start();
|
||||||
su_raw(commands);
|
sh_raw(commands);
|
||||||
su_raw("echo \'-root-done-\'");
|
sh_raw("echo \'-shell-done-\'");
|
||||||
try { STDOUT.join(); } catch (InterruptedException ignored) {}
|
try { out.join(); } catch (InterruptedException ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public 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(List<String> output, String... commands) {
|
||||||
|
if (!rootAccess()) return;
|
||||||
|
sh(output, commands);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ public class StreamGobbler extends Thread {
|
|||||||
/**
|
/**
|
||||||
* <p>StreamGobbler constructor</p>
|
* <p>StreamGobbler constructor</p>
|
||||||
*
|
*
|
||||||
* <p>We use this class because shell STDOUT and STDERR should be read as quickly as
|
* <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
|
* possible to prevent a deadlock from occurring, or Process.waitFor() never
|
||||||
* returning (as the buffer is full, pausing the native process)</p>
|
* returning (as the buffer is full, pausing the native process)</p>
|
||||||
*
|
*
|
||||||
@ -38,21 +38,16 @@ public class StreamGobbler extends Thread {
|
|||||||
writer = outputList;
|
writer = outputList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamGobbler(InputStream inputStream, List<String> outputList, boolean root) {
|
|
||||||
this(inputStream, outputList);
|
|
||||||
isRoot = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// keep reading the InputStream until it ends (or an error occurs)
|
// keep reading the InputStream until it ends (or an error occurs)
|
||||||
try {
|
try {
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
if (TextUtils.equals(line, "-root-done-"))
|
if (TextUtils.equals(line, "-shell-done-"))
|
||||||
return;
|
return;
|
||||||
writer.add(line);
|
writer.add(line);
|
||||||
Logger.shell(isRoot, line);
|
Logger.shell(line);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// reader probably closed, expected exit condition
|
// reader probably closed, expected exit condition
|
||||||
|
Loading…
Reference in New Issue
Block a user