diff --git a/build.gradle b/build.gradle index dea42343f..7bf99f878 100644 --- a/build.gradle +++ b/build.gradle @@ -55,6 +55,7 @@ repositories { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':crypto') + implementation 'com.github.topjohnwu:libsu:0.1.0' implementation 'com.android.support:recyclerview-v7:27.0.2' implementation 'com.android.support:cardview-v7:27.0.2' implementation 'com.android.support:design:27.0.2' diff --git a/src/main/java/com/topjohnwu/magisk/FlashActivity.java b/src/main/java/com/topjohnwu/magisk/FlashActivity.java index e5f5c30cd..e2e29bee1 100644 --- a/src/main/java/com/topjohnwu/magisk/FlashActivity.java +++ b/src/main/java/com/topjohnwu/magisk/FlashActivity.java @@ -16,9 +16,9 @@ import android.widget.Toast; import com.topjohnwu.magisk.asyncs.FlashZip; import com.topjohnwu.magisk.asyncs.InstallMagisk; import com.topjohnwu.magisk.components.Activity; -import com.topjohnwu.magisk.container.CallbackList; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellCallbackVector; import java.io.File; import java.io.FileWriter; @@ -96,10 +96,10 @@ public class FlashActivity extends Activity { reboot.setVisibility(View.GONE); logs = new ArrayList<>(); - List console = new CallbackList() { + ShellCallbackVector console = new ShellCallbackVector() { @Override - public synchronized void onAddElement(String e) { - logs.add(e); + public void onShellOutput(String s) { + logs.add(s); flashLogs.setText(TextUtils.join("\n", this)); sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10); } diff --git a/src/main/java/com/topjohnwu/magisk/MagiskFragment.java b/src/main/java/com/topjohnwu/magisk/MagiskFragment.java index 6aeb048ae..567637b26 100644 --- a/src/main/java/com/topjohnwu/magisk/MagiskFragment.java +++ b/src/main/java/com/topjohnwu/magisk/MagiskFragment.java @@ -22,10 +22,10 @@ import com.topjohnwu.magisk.asyncs.CheckUpdates; import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.components.ExpandableView; import com.topjohnwu.magisk.components.Fragment; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.ShowUI; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; import butterknife.BindColor; import butterknife.BindView; diff --git a/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java b/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java index 3aecbf007..45da4b331 100644 --- a/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java +++ b/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java @@ -21,8 +21,9 @@ import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.components.Fragment; import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellCallback; import java.io.File; import java.io.FileWriter; @@ -188,7 +189,7 @@ public class MagiskLogFragment extends Fragment { } } - private static class StringBuildingList extends Shell.AbstractList { + private static class StringBuildingList extends ShellCallback { StringBuilder builder; @@ -196,18 +197,17 @@ public class MagiskLogFragment extends Fragment { builder = new StringBuilder(); } - @Override - public boolean add(String s) { - builder.append(s).append("\n"); - return true; - } - public CharSequence getCharSequence() { return builder; } + + @Override + public void onShellOutput(String s) { + builder.append(s).append("\n"); + } } - private static class FileWritingList extends Shell.AbstractList { + private static class FileWritingList extends ShellCallback { private FileWriter writer; @@ -216,11 +216,10 @@ public class MagiskLogFragment extends Fragment { } @Override - public boolean add(String s) { + public void onShellOutput(String s) { try { writer.write(s + "\n"); } catch (IOException ignored) {} - return true; } } diff --git a/src/main/java/com/topjohnwu/magisk/MagiskManager.java b/src/main/java/com/topjohnwu/magisk/MagiskManager.java index c8fdf9165..140163ba2 100644 --- a/src/main/java/com/topjohnwu/magisk/MagiskManager.java +++ b/src/main/java/com/topjohnwu/magisk/MagiskManager.java @@ -14,16 +14,20 @@ import com.topjohnwu.magisk.container.Module; import com.topjohnwu.magisk.database.RepoDatabaseHelper; import com.topjohnwu.magisk.database.SuDatabaseHelper; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; +import com.topjohnwu.superuser.ShellContainer; +import com.topjohnwu.superuser.ShellInitializer; +import java.io.IOException; +import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.List; import java.util.Locale; import java.util.Map; -public class MagiskManager extends Application { +public class MagiskManager extends Application implements ShellContainer { // Global weak reference to self private static WeakReference weakSelf; @@ -85,6 +89,21 @@ public class MagiskManager extends Application { public MagiskManager() { weakSelf = new WeakReference<>(this); + Shell.setFlags(Shell.FLAG_MOUNT_MASTER); + Shell.setGlobalContainer(this); + Shell.setInitializer(new ShellInitializer() { + @Override + public void onRootShellInit(Shell shell) { + try (InputStream in = MagiskManager.get().getAssets().open(Const.UTIL_FUNCTIONS)) { + shell.loadInputStream(in); + } catch (IOException e) { + e.printStackTrace(); + } + shell.run_raw("export PATH=" + Const.BUSYBOX_PATH + ":$PATH", + "mount_partitions", + "run_migrations"); + } + }); } @Override @@ -110,6 +129,16 @@ public class MagiskManager extends Application { loadConfig(); } + @Override + public Shell getShell() { + return shell; + } + + @Override + public void setShell(Shell shell) { + this.shell = shell; + } + public static MagiskManager get() { return weakSelf.get(); } diff --git a/src/main/java/com/topjohnwu/magisk/MainActivity.java b/src/main/java/com/topjohnwu/magisk/MainActivity.java index 414460723..769b51c89 100644 --- a/src/main/java/com/topjohnwu/magisk/MainActivity.java +++ b/src/main/java/com/topjohnwu/magisk/MainActivity.java @@ -19,9 +19,9 @@ import android.view.View; import com.topjohnwu.magisk.asyncs.MarkDownWindow; import com.topjohnwu.magisk.components.Activity; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 542f7b3f2..d98c6a9e6 100644 --- a/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -20,9 +20,9 @@ import com.topjohnwu.magisk.asyncs.LoadModules; import com.topjohnwu.magisk.components.Fragment; import com.topjohnwu.magisk.container.Module; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index f714a9522..b00a180cf 100644 --- a/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -23,9 +23,9 @@ import com.topjohnwu.magisk.asyncs.HideManager; import com.topjohnwu.magisk.components.Activity; import com.topjohnwu.magisk.utils.Const; import com.topjohnwu.magisk.utils.FingerprintHelper; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; import java.util.Locale; diff --git a/src/main/java/com/topjohnwu/magisk/SplashActivity.java b/src/main/java/com/topjohnwu/magisk/SplashActivity.java index 50d56a5e0..4981ea297 100644 --- a/src/main/java/com/topjohnwu/magisk/SplashActivity.java +++ b/src/main/java/com/topjohnwu/magisk/SplashActivity.java @@ -17,8 +17,8 @@ import com.topjohnwu.magisk.asyncs.UpdateRepos; import com.topjohnwu.magisk.components.Activity; import com.topjohnwu.magisk.services.UpdateCheckService; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; public class SplashActivity extends Activity { diff --git a/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java b/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java index e3d375ca8..851f029cd 100644 --- a/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java +++ b/src/main/java/com/topjohnwu/magisk/adapters/ApplicationAdapter.java @@ -18,9 +18,9 @@ import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Topic; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java b/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java index ac4a605fc..9ce3614f6 100644 --- a/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java +++ b/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java @@ -14,7 +14,7 @@ import android.widget.TextView; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.container.Module; -import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.superuser.Shell; import java.util.List; diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java b/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java index 70c9f39d4..503247f54 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java @@ -4,9 +4,9 @@ import android.app.Activity; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebService; +import com.topjohnwu.superuser.Shell; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java b/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java index ac1395ee9..3926bddb1 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java @@ -8,9 +8,9 @@ import android.view.View; import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.ZipUtils; +import com.topjohnwu.superuser.Shell; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java b/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java index 7570cc13b..0d8e0fc4b 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java @@ -8,9 +8,9 @@ import com.topjohnwu.crypto.JarMap; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.ZipUtils; +import com.topjohnwu.superuser.Shell; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java b/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java index 55e47bb3f..29d89d1ac 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java @@ -12,9 +12,9 @@ import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.container.TarEntry; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.ZipUtils; +import com.topjohnwu.superuser.Shell; import org.kamranzafar.jtar.TarInputStream; import org.kamranzafar.jtar.TarOutputStream; @@ -178,7 +178,7 @@ public class InstallMagisk extends ParallelTask { // Force non-root shell Shell shell; if (Shell.rootAccess()) - shell = new Shell("sh"); + shell = Shell.newShell("sh"); else shell = Shell.getShell(); @@ -192,8 +192,7 @@ public class InstallMagisk extends ParallelTask { if (TextUtils.equals(console.get(console.size() - 1), "Failed!")) return false; - shell.run(null, null, - "mv -f new-boot.img ../", + shell.run("mv -f new-boot.img ../", "mv bin/busybox busybox", "rm -rf bin *.img update-binary", "cd /"); @@ -212,7 +211,7 @@ public class InstallMagisk extends ParallelTask { ) { SignBoot.doSignature("/boot", in, out, keyIn, certIn); } - shell.run_raw(false, false, "mv -f " + signed + " " + patched_boot); + shell.run_raw("mv -f " + signed + " " + patched_boot); } switch (mode) { diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java b/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java index 4efeef542..88819c0ae 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java @@ -4,7 +4,7 @@ import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.container.Module; import com.topjohnwu.magisk.container.ValueSortedMap; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.superuser.Shell; import java.util.List; diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java b/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java index c4196ea80..1eeb5dd60 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/ProcessRepoZip.java @@ -13,10 +13,10 @@ import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.WebService; import com.topjohnwu.magisk.utils.ZipUtils; +import com.topjohnwu.superuser.Shell; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/RestoreImages.java b/src/main/java/com/topjohnwu/magisk/asyncs/RestoreImages.java index 9df543660..f1761b1c3 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/RestoreImages.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/RestoreImages.java @@ -4,8 +4,8 @@ import android.widget.Toast; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; import java.util.List; diff --git a/src/main/java/com/topjohnwu/magisk/container/CallbackList.java b/src/main/java/com/topjohnwu/magisk/container/CallbackList.java deleted file mode 100644 index 0ee88e1d4..000000000 --- a/src/main/java/com/topjohnwu/magisk/container/CallbackList.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.topjohnwu.magisk.container; - -import android.os.Handler; - -import java.util.ArrayList; - -public abstract class CallbackList extends ArrayList { - - private Handler handler; - - protected CallbackList() { - handler = new Handler(); - } - - public abstract void onAddElement(E e); - - public synchronized boolean add(E e) { - boolean ret = super.add(e); - handler.post(() -> onAddElement(e)); - return ret; - } -} diff --git a/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java b/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java index fadbd56b2..c89453aed 100644 --- a/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java +++ b/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java @@ -15,8 +15,8 @@ import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.container.Policy; import com.topjohnwu.magisk.container.SuLogEntry; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; import java.io.File; import java.text.DateFormat; diff --git a/src/main/java/com/topjohnwu/magisk/receivers/PackageReceiver.java b/src/main/java/com/topjohnwu/magisk/receivers/PackageReceiver.java index 52bc9f932..dde1c29ae 100644 --- a/src/main/java/com/topjohnwu/magisk/receivers/PackageReceiver.java +++ b/src/main/java/com/topjohnwu/magisk/receivers/PackageReceiver.java @@ -6,8 +6,8 @@ import android.content.Intent; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; public class PackageReceiver extends BroadcastReceiver { @Override diff --git a/src/main/java/com/topjohnwu/magisk/receivers/RebootReceiver.java b/src/main/java/com/topjohnwu/magisk/receivers/RebootReceiver.java index f8032b273..dbd25895f 100644 --- a/src/main/java/com/topjohnwu/magisk/receivers/RebootReceiver.java +++ b/src/main/java/com/topjohnwu/magisk/receivers/RebootReceiver.java @@ -4,7 +4,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.superuser.Shell; public class RebootReceiver extends BroadcastReceiver { @Override diff --git a/src/main/java/com/topjohnwu/magisk/services/OnBootIntentService.java b/src/main/java/com/topjohnwu/magisk/services/OnBootIntentService.java index e5750cc9e..3e8b2039b 100644 --- a/src/main/java/com/topjohnwu/magisk/services/OnBootIntentService.java +++ b/src/main/java/com/topjohnwu/magisk/services/OnBootIntentService.java @@ -8,8 +8,8 @@ import android.support.v4.app.NotificationCompat; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.utils.Const; -import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.superuser.Shell; public class OnBootIntentService extends IntentService { diff --git a/src/main/java/com/topjohnwu/magisk/utils/Const.java b/src/main/java/com/topjohnwu/magisk/utils/Const.java index 0290fde98..63a559a6a 100644 --- a/src/main/java/com/topjohnwu/magisk/utils/Const.java +++ b/src/main/java/com/topjohnwu/magisk/utils/Const.java @@ -27,6 +27,7 @@ public class Const { // Paths public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk"; + public static final String BUSYBOX_PATH = "/sbin/.core/busybox"; public static final String TMP_FOLDER_PATH = "/dev/tmp"; public static final String MAGISK_LOG = "/cache/magisk.log"; public static final File EXTERNAL_PATH = new File(Environment.getExternalStorageDirectory(), "MagiskManager"); @@ -37,14 +38,6 @@ public class Const { public static final int SNET_VER = 7; public static final int MIN_MODULE_VER = 1400; - public static String BUSYBOX_PATH() { - if (Utils.itemExist("/sbin/.core/busybox/busybox")) { - return "/sbin/.core/busybox"; - } else { - return "/dev/magisk/bin"; - } - } - public static String MAGISK_PATH() { if (Utils.itemExist("/sbin/.core/img")) { return "/sbin/.core/img"; diff --git a/src/main/java/com/topjohnwu/magisk/utils/Shell.java b/src/main/java/com/topjohnwu/magisk/utils/Shell.java deleted file mode 100644 index 34e43a610..000000000 --- a/src/main/java/com/topjohnwu/magisk/utils/Shell.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.topjohnwu.magisk.utils; - -import android.text.TextUtils; - -import com.topjohnwu.magisk.MagiskManager; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * Modified by topjohnwu, based on Chainfire's libsuperuser - */ - -public class Shell { - - // -2 = not initialized; -1 = no shell; 0 = non root shell; 1 = root shell - public static int status = -2; - - private final Process process; - private final OutputStream STDIN; - private final InputStream STDOUT; - private final InputStream STDERR; - - private static void testRootShell(Shell shell) throws IOException { - shell.STDIN.write(("id\n").getBytes("UTF-8")); - shell.STDIN.flush(); - String s = new BufferedReader(new InputStreamReader(shell.STDOUT)).readLine(); - if (TextUtils.isEmpty(s) || !s.contains("uid=0")) { - shell.STDIN.close(); - shell.STDIN.close(); - throw new IOException(); - } - } - - public Shell(String command) throws IOException { - process = Runtime.getRuntime().exec(command); - STDIN = process.getOutputStream(); - STDOUT = process.getInputStream(); - STDERR = process.getErrorStream(); - } - - public static Shell getShell() { - MagiskManager mm = MagiskManager.get(); - boolean needNewShell = mm.shell == null; - - if (!needNewShell) { - try { - mm.shell.process.exitValue(); - // The process is dead - needNewShell = true; - } catch (IllegalThreadStateException ignored) { - // This should be the expected result - } - } - - if (needNewShell) { - status = 1; - try { - mm.shell = new Shell("su --mount-master"); - testRootShell(mm.shell); - } catch (IOException e) { - // Mount master not implemented - try { - mm.shell = new Shell("su"); - testRootShell(mm.shell); - } catch (IOException e1) { - // No root exists - status = 0; - try { - mm.shell = new Shell("sh"); - } catch (IOException e2) { - status = -1; - return null; - } - } - } - if (rootAccess()) { - // Load utility shell scripts - try (InputStream in = mm.getAssets().open(Const.UTIL_FUNCTIONS)) { - mm.shell.loadInputStream(in); - } catch (IOException e) { - e.printStackTrace(); - } - - // Root shell initialization - mm.shell.run_raw(false, false, - "export PATH=" + Const.BUSYBOX_PATH() + ":$PATH", - "mount_partitions", - "run_migrations"); - } - } - - return mm.shell; - } - - public static boolean rootAccess() { - if (status == -2) getShell(); - return status > 0; - } - - public void run(Collection output, Collection error, String... commands) { - StreamGobbler out, err; - synchronized (process) { - try { - out = new StreamGobbler(STDOUT, output); - err = new StreamGobbler(STDERR, error); - out.start(); - err.start(); - run_raw(output != null, error != null, commands); - STDIN.write("echo \'-shell-done-\'\necho \'-shell-done-\' >&2\n".getBytes("UTF-8")); - STDIN.flush(); - try { - out.join(); - err.join(); - } catch (InterruptedException ignored) {} - } catch (IOException e) { - e.printStackTrace(); - process.destroy(); - } - } - } - - public void run_raw(boolean stdout, boolean stderr, String... commands) { - String suffix = "\n"; - if (!stderr) suffix = " 2>/dev/null" + suffix; - if (!stdout) suffix = " >/dev/null" + suffix; - synchronized (process) { - try { - for (String command : commands) { - Logger.shell(true, command); - STDIN.write((command + suffix).getBytes("UTF-8")); - STDIN.flush(); - } - } catch (IOException e) { - e.printStackTrace(); - process.destroy(); - } - } - } - - public void loadInputStream(InputStream in) { - synchronized (process) { - try { - Utils.inToOut(in, STDIN); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - public static List sh(String... commands) { - List res = new ArrayList<>(); - sh(res, commands); - return res; - } - - public static void sh(Collection output, String... commands) { - Shell shell = getShell(); - if (shell == null) - return; - shell.run(output, null, commands); - } - - public static void sh_raw(String... commands) { - Shell shell = getShell(); - if (shell == null) - return; - shell.run_raw(false, false, commands); - } - - public static List su(String... commands) { - if (!rootAccess()) return sh(); - return sh(commands); - } - - public static void su(Collection 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 extends java.util.AbstractList { - - @Override - public abstract boolean add(E e); - - @Override - public E get(int i) { - return null; - } - - @Override - public int size() { - return 0; - } - } -} diff --git a/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java b/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java index 28d7d579e..910e848d3 100644 --- a/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java +++ b/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java @@ -22,6 +22,7 @@ import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.receivers.ManagerUpdate; import com.topjohnwu.magisk.receivers.RebootReceiver; +import com.topjohnwu.superuser.Shell; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java b/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java deleted file mode 100644 index 503de5cde..000000000 --- a/src/main/java/com/topjohnwu/magisk/utils/StreamGobbler.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.topjohnwu.magisk.utils; - -import android.text.TextUtils; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Collection; -import java.util.Collections; - -/** - * Modified by topjohnwu, based on Chainfire's libsuperuser - */ - -public class StreamGobbler extends Thread { - - private BufferedReader reader; - private Collection writer; - - /** - *

StreamGobbler constructor

- * - *

We use this class because sh STDOUT and STDERR should be read as quickly as - * possible to prevent a deadlock from occurring, or Process.waitFor() never - * returning (as the buffer is full, pausing the native process)

- * - * @param in InputStream to read from - * @param out {@literal List} to write to, or null - */ - public StreamGobbler(InputStream in, Collection out) { - try { - while (in.available() != 0) { - in.skip(in.available()); - } - } catch (IOException ignored) {} - reader = new BufferedReader(new InputStreamReader(in)); - writer = out == null ? null : Collections.synchronizedCollection(out); - } - - @Override - public void run() { - // keep reading the InputStream until it ends (or an error occurs) - try { - String line; - while ((line = reader.readLine()) != null) { - if (TextUtils.equals(line, "-shell-done-")) - return; - if (writer != null) writer.add(line); - Logger.shell(false, line); - } - } catch (IOException e) { - // reader probably closed, expected exit condition - } - - // make sure our stream is closed and resources will be freed - try { - reader.close(); - } catch (IOException e) { - // read already closed - } - } -} diff --git a/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/src/main/java/com/topjohnwu/magisk/utils/Utils.java index 1525bd68b..10bf16b28 100644 --- a/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -29,6 +29,7 @@ import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.SplashActivity; import com.topjohnwu.magisk.components.SnackbarMaker; import com.topjohnwu.magisk.receivers.DownloadReceiver; +import com.topjohnwu.superuser.Shell; import java.io.File; import java.io.IOException;