Update to libsu 1.0.0

This commit is contained in:
topjohnwu 2018-01-25 18:43:30 +08:00
parent 00d655f346
commit 40082d4571
19 changed files with 97 additions and 127 deletions

View File

@ -55,7 +55,7 @@ repositories {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':crypto')
implementation 'com.github.topjohnwu:libsu:0.1.0'
implementation 'com.github.topjohnwu:libsu:1.0.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'

View File

@ -17,8 +17,8 @@ import com.topjohnwu.magisk.asyncs.FlashZip;
import com.topjohnwu.magisk.asyncs.InstallMagisk;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.superuser.CallbackList;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellCallbackVector;
import java.io.File;
import java.io.FileWriter;
@ -49,7 +49,7 @@ public class FlashActivity extends Activity {
@OnClick(R.id.reboot)
void reboot() {
Shell.su_raw("/system/bin/reboot");
Shell.Async.su("/system/bin/reboot");
}
@OnClick(R.id.save_logs)
@ -96,9 +96,9 @@ public class FlashActivity extends Activity {
reboot.setVisibility(View.GONE);
logs = new ArrayList<>();
ShellCallbackVector console = new ShellCallbackVector() {
CallbackList console = new CallbackList<String>(new ArrayList<>()) {
@Override
public void onShellOutput(String s) {
public void onAddElement(String s) {
logs.add(s);
flashLogs.setText(TextUtils.join("\n", this));
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);

View File

@ -22,8 +22,8 @@ import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.utils.Const;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.CallbackList;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.ShellCallback;
import java.io.File;
import java.io.FileWriter;
@ -114,12 +114,18 @@ public class MagiskLogFragment extends Fragment {
mode = (int) params[0];
switch (mode) {
case 0:
StringBuildingList logList = new StringBuildingList();
Shell.su(logList, "cat " + Const.MAGISK_LOG + " | tail -n 5000");
return logList.getCharSequence();
StringBuilder builder = new StringBuilder();
CallbackList<String> logs = new CallbackList<String>() {
@Override
public void onAddElement(String s) {
builder.append(s).append('\n');
}
};
Shell.Sync.su(logs, "cat " + Const.MAGISK_LOG + " | tail -n 5000");
return builder;
case 1:
Shell.su_raw("echo -n > " + Const.MAGISK_LOG);
Shell.Async.su("echo -n > " + Const.MAGISK_LOG);
SnackbarMaker.make(txtLog, R.string.logs_cleared, Snackbar.LENGTH_SHORT).show();
return "";
@ -139,8 +145,16 @@ public class MagiskLogFragment extends Fragment {
}
try (FileWriter out = new FileWriter(targetFile)) {
FileWritingList fileWritingList = new FileWritingList(out);
Shell.su(fileWritingList, "cat " + Const.MAGISK_LOG);
CallbackList<String> list = new CallbackList<String>() {
@Override
public void onAddElement(String s) {
try {
out.write(s);
out.write("\n");
} catch (IOException ignored) {}
}
};
Shell.Sync.su(list, "cat " + Const.MAGISK_LOG);
} catch (IOException e) {
e.printStackTrace();
return false;
@ -188,39 +202,4 @@ public class MagiskLogFragment extends Fragment {
exec(2);
}
}
private static class StringBuildingList extends ShellCallback {
StringBuilder builder;
StringBuildingList() {
builder = new StringBuilder();
}
public CharSequence getCharSequence() {
return builder;
}
@Override
public void onShellOutput(String s) {
builder.append(s).append("\n");
}
}
private static class FileWritingList extends ShellCallback {
private FileWriter writer;
FileWritingList(FileWriter out) {
writer = out;
}
@Override
public void onShellOutput(String s) {
try {
writer.write(s + "\n");
} catch (IOException ignored) {}
}
}
}

View File

@ -1,6 +1,5 @@
package com.topjohnwu.magisk;
import android.app.Application;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@ -8,6 +7,7 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.widget.Toast;
import com.topjohnwu.magisk.container.Module;
@ -17,8 +17,6 @@ import com.topjohnwu.magisk.utils.Const;
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;
@ -27,7 +25,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
public class MagiskManager extends Application implements ShellContainer {
public class MagiskManager extends Shell.ContainerApp {
// Global weak reference to self
private static WeakReference<MagiskManager> weakSelf;
@ -82,7 +80,6 @@ public class MagiskManager extends Application implements ShellContainer {
public SharedPreferences prefs;
public SuDatabaseHelper suDB;
public RepoDatabaseHelper repoDB;
public Shell shell;
public Runnable permissionGrantCallback = null;
private static Handler mHandler = new Handler();
@ -90,16 +87,16 @@ public class MagiskManager extends Application implements ShellContainer {
public MagiskManager() {
weakSelf = new WeakReference<>(this);
Shell.setFlags(Shell.FLAG_MOUNT_MASTER);
Shell.setGlobalContainer(this);
Shell.setInitializer(new ShellInitializer() {
Shell.setInitializer(new Shell.Initializer() {
@Override
public void onRootShellInit(Shell shell) {
public void onRootShellInit(@NonNull Shell shell) {
try (InputStream in = MagiskManager.get().getAssets().open(Const.UTIL_FUNCTIONS)) {
shell.loadInputStream(in);
shell.loadInputStream(null, null, in);
} catch (IOException e) {
e.printStackTrace();
}
shell.run_raw("export PATH=" + Const.BUSYBOX_PATH + ":$PATH",
shell.run(null, null,
"export PATH=" + Const.BUSYBOX_PATH + ":$PATH",
"mount_partitions",
"run_migrations");
}
@ -129,16 +126,6 @@ public class MagiskManager extends Application implements ShellContainer {
loadConfig();
}
@Override
public Shell getShell() {
return shell;
}
@Override
public void setShell(Shell shell) {
this.shell = shell;
}
public static MagiskManager get() {
return weakSelf.get();
}
@ -202,9 +189,9 @@ public class MagiskManager extends Application implements ShellContainer {
public void loadMagiskInfo() {
List<String> ret;
ret = Shell.sh("magisk -v");
ret = Shell.Sync.sh("magisk -v");
if (!Utils.isValidShellResponse(ret)) {
ret = Shell.sh("getprop magisk.version");
ret = Shell.Sync.sh("getprop magisk.version");
if (Utils.isValidShellResponse(ret)) {
try {
magiskVersionString = ret.get(0);
@ -213,15 +200,15 @@ public class MagiskManager extends Application implements ShellContainer {
}
} else {
magiskVersionString = ret.get(0).split(":")[0];
ret = Shell.sh("magisk -V");
ret = Shell.Sync.sh("magisk -V");
try {
magiskVersionCode = Integer.parseInt(ret.get(0));
} catch (NumberFormatException ignored) {}
}
if (magiskVersionCode > 1435) {
ret = Shell.su("resetprop -p " + Const.MAGISKHIDE_PROP);
ret = Shell.Sync.su("resetprop -p " + Const.MAGISKHIDE_PROP);
} else {
ret = Shell.sh("getprop " + Const.MAGISKHIDE_PROP);
ret = Shell.Sync.sh("getprop " + Const.MAGISKHIDE_PROP);
}
try {
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0;
@ -229,7 +216,7 @@ public class MagiskManager extends Application implements ShellContainer {
magiskHide = true;
}
ret = Shell.su("echo \"$BOOTIMAGE\"");
ret = Shell.Sync.su("echo \"$BOOTIMAGE\"");
if (Utils.isValidShellResponse(ret))
bootBlock = ret.get(0);
@ -241,11 +228,11 @@ public class MagiskManager extends Application implements ShellContainer {
public void getDefaultInstallFlags() {
List<String> ret;
ret = Shell.su("echo \"$DTBOIMAGE\"");
ret = Shell.Sync.su("echo \"$DTBOIMAGE\"");
if (Utils.isValidShellResponse(ret))
keepVerity = true;
ret = Shell.su(
ret = Shell.Sync.su(
"getvar KEEPVERITY",
"echo $KEEPVERITY");
try {
@ -253,11 +240,11 @@ public class MagiskManager extends Application implements ShellContainer {
keepVerity = Boolean.parseBoolean(ret.get(0));
} catch (NumberFormatException ignored) {}
ret = Shell.sh("getprop ro.crypto.state");
ret = Shell.Sync.sh("getprop ro.crypto.state");
if (Utils.isValidShellResponse(ret) && ret.get(0).equals("encrypted"))
keepEnc = true;
ret = Shell.su(
ret = Shell.Sync.su(
"getvar KEEPFORCEENCRYPT",
"echo $KEEPFORCEENCRYPT");
try {

View File

@ -113,16 +113,16 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.reboot:
Shell.su_raw("/system/bin/reboot");
Shell.Async.su("/system/bin/reboot");
return true;
case R.id.reboot_recovery:
Shell.su_raw("/system/bin/reboot recovery");
Shell.Async.su("/system/bin/reboot recovery");
return true;
case R.id.reboot_bootloader:
Shell.su_raw("/system/bin/reboot bootloader");
Shell.Async.su("/system/bin/reboot bootloader");
return true;
case R.id.reboot_download:
Shell.su_raw("/system/bin/reboot download");
Shell.Async.su("/system/bin/reboot download");
return true;
default:
return false;

View File

@ -231,18 +231,18 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
break;
case Const.Key.MAGISKHIDE:
if (prefs.getBoolean(key, false)) {
Shell.su_raw("magiskhide --enable");
Shell.Async.su("magiskhide --enable");
} else {
Shell.su_raw("magiskhide --disable");
Shell.Async.su("magiskhide --disable");
}
break;
case Const.Key.HOSTS:
if (prefs.getBoolean(key, false)) {
Shell.su_raw(
Shell.Async.su(
"cp -af /system/etc/hosts " + Const.MAGISK_HOST_FILE(),
"mount -o bind " + Const.MAGISK_HOST_FILE() + " /system/etc/hosts");
} else {
Shell.su_raw(
Shell.Async.su(
"umount -l /system/etc/hosts",
"rm -f " + Const.MAGISK_HOST_FILE());
}

View File

@ -81,10 +81,10 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
holder.checkBox.setChecked(mHideList.contains(info.packageName));
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
if (isChecked) {
Shell.su_raw("magiskhide --add " + info.packageName);
Shell.Async.su("magiskhide --add " + info.packageName);
mHideList.add(info.packageName);
} else {
Shell.su_raw("magiskhide --rm " + info.packageName);
Shell.Async.su("magiskhide --rm " + info.packageName);
mHideList.remove(info.packageName);
}
});
@ -155,7 +155,7 @@ public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.
}
Collections.sort(mOriginalList, (a, b) -> a.loadLabel(pm).toString().toLowerCase()
.compareTo(b.loadLabel(pm).toString().toLowerCase()));
mHideList = Shell.su("magiskhide --ls");
mHideList = Shell.Sync.su("magiskhide --ls");
return null;
}

View File

@ -32,7 +32,7 @@ public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
}
private void dlSnet() throws IOException {
Shell.sh("rm -rf " + dexPath.getParent());
Shell.Sync.sh("rm -rf " + dexPath.getParent());
HttpURLConnection conn = WebService.request(Const.Url.SNET_URL, null);
dexPath.getParentFile().mkdir();
try (

View File

@ -85,7 +85,7 @@ public class FlashZip extends ParallelTask<Void, Void, Integer> {
@Override
protected void onPostExecute(Integer result) {
FlashActivity activity = (FlashActivity) getActivity();
Shell.su_raw(
Shell.Async.su(
"rm -rf " + mCachedFile.getParent(),
"rm -rf " + Const.TMP_FOLDER_PATH
);

View File

@ -131,7 +131,7 @@ public class HideManager extends ParallelTask<Void, Void, Boolean> {
// Install the application
List<String> ret = Shell.su(Utils.fmt("pm install %s >/dev/null && echo true || echo false", repack));
List<String> ret = Shell.Sync.su(Utils.fmt("pm install %s >/dev/null && echo true || echo false", repack));
repack.delete();
if (!Utils.isValidShellResponse(ret) || !Boolean.parseBoolean(ret.get(0)))
return false;

View File

@ -70,7 +70,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
mm.createDeviceProtectedStorageContext() :
mm).getFilesDir().getParent()
, "install");
Shell.sh_raw("rm -rf " + install);
Shell.Async.sh("rm -rf " + install);
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
String arch;
@ -102,7 +102,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
console.add("! Cannot unzip zip");
throw e;
}
Shell.sh("chmod 755 " + install + "/*");
Shell.Sync.sh("chmod 755 " + install + "/*");
File boot = new File(install, "boot.img");
boolean highCompression = false;
@ -154,7 +154,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
}
}
if (boot.createNewFile()) {
Shell.su("cat " + mBootLocation + " > " + boot);
Shell.Sync.su("cat " + mBootLocation + " > " + boot);
} else {
console.add("! Dump boot image failed");
return false;
@ -178,7 +178,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
// Force non-root shell
Shell shell;
if (Shell.rootAccess())
shell = Shell.newShell("sh");
shell = Shell.newInstance("sh");
else
shell = Shell.getShell();
@ -192,7 +192,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
if (TextUtils.equals(console.get(console.size() - 1), "Failed!"))
return false;
shell.run("mv -f new-boot.img ../",
shell.run(null, null, "mv -f new-boot.img ../",
"mv bin/busybox busybox",
"rm -rf bin *.img update-binary",
"cd /");
@ -211,7 +211,7 @@ public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
) {
SignBoot.doSignature("/boot", in, out, keyIn, certIn);
}
shell.run_raw("mv -f " + signed + " " + patched_boot);
shell.run(null, null, "mv -f " + signed + " " + patched_boot);
}
switch (mode) {

View File

@ -12,7 +12,7 @@ public class LoadModules extends ParallelTask<Void, Void, Void> {
private List<String> getModList() {
String command = "ls -d " + Const.MAGISK_PATH() + "/* | grep -v lost+found";
return Shell.su(command);
return Shell.Sync.su(command);
}
@Override

View File

@ -18,13 +18,13 @@ public class RestoreImages extends ParallelTask<Void, Void, Boolean> {
if (Utils.isValidShellResponse(ret)) {
sha1 = ret.get(0);
} else {
ret = Shell.su("cat /init.magisk.rc | grep STOCKSHA1");
ret = Shell.Sync.su("cat /init.magisk.rc | grep STOCKSHA1");
if (!Utils.isValidShellResponse(ret))
return false;
sha1 = ret.get(0).substring(ret.get(0).indexOf('=') + 1);
}
ret = Shell.su("restore_imgs " + sha1 + " && echo true || echo false");
ret = Shell.Sync.su("restore_imgs " + sha1 + " && echo true || echo false");
return Utils.isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(ret.size() - 1));
}

View File

@ -42,7 +42,7 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
private SQLiteDatabase mDb;
private static void unmntDB() {
Shell.su(Utils.fmt("umount -l /data/user*/*/%s/*/*.db", MagiskManager.get().getPackageName()));
Shell.Sync.su(Utils.fmt("umount -l /data/user*/*/%s/*/*.db", MagiskManager.get().getPackageName()));
}
private static Context initDB(boolean verify) {
@ -100,22 +100,22 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
if (!verified) {
context.deleteDatabase(DB_NAME);
db.getParentFile().mkdirs();
Shell.su(Utils.fmt("magisk --clone-attr %s %s; chmod 600 %s; ln %s %s",
Shell.Sync.su(Utils.fmt("magisk --clone-attr %s %s; chmod 600 %s; ln %s %s",
context.getFilesDir(), OLD_GLOBAL_DB, OLD_GLOBAL_DB, OLD_GLOBAL_DB, db));
verified = TextUtils.equals(Utils.checkInode(OLD_GLOBAL_DB), Utils.checkInode(db));
}
} else if (ce.magiskVersionCode >= 1464) {
// New global su db
Shell.su(Utils.fmt("mkdir %s 2>/dev/null; chmod 700 %s", GLOBAL_DB.getParent(), GLOBAL_DB.getParent()));
Shell.Sync.su(Utils.fmt("mkdir %s 2>/dev/null; chmod 700 %s", GLOBAL_DB.getParent(), GLOBAL_DB.getParent()));
if (!Utils.itemExist(GLOBAL_DB)) {
context.openOrCreateDatabase(DB_NAME, 0, null).close();
Shell.su(Utils.fmt("cp -af %s %s; rm -f %s*", db, GLOBAL_DB, db));
Shell.Sync.su(Utils.fmt("cp -af %s %s; rm -f %s*", db, GLOBAL_DB, db));
}
verified = TextUtils.equals(Utils.checkInode(GLOBAL_DB), Utils.checkInode(db));
if (!verified) {
context.deleteDatabase(DB_NAME);
Utils.javaCreateFile(db);
Shell.su(Utils.fmt(
Shell.Sync.su(Utils.fmt(
"chown 0.0 %s; chmod 666 %s; chcon u:object_r:su_file:s0 %s;" +
"mount -o bind %s %s",
GLOBAL_DB, GLOBAL_DB, GLOBAL_DB, GLOBAL_DB, db));
@ -131,7 +131,7 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
} catch(Exception e) {
// Try to catch runtime exceptions and remove all db for retry
unmntDB();
Shell.su(Utils.fmt("rm -rf /data/user*/*/magisk.db /data/adb/magisk.db /data/user*/*/%s/databases",
Shell.Sync.su(Utils.fmt("rm -rf /data/user*/*/magisk.db /data/adb/magisk.db /data/user*/*/%s/databases",
MagiskManager.get().getPackageName()));
e.printStackTrace();
return new SuDatabaseHelper(initDB(false));

View File

@ -25,7 +25,7 @@ public class PackageReceiver extends BroadcastReceiver {
break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
mm.suDB.deletePolicy(pkg);
Shell.su_raw("magiskhide --rm " + pkg);
Shell.Async.su("magiskhide --rm " + pkg);
break;
}
}

View File

@ -9,6 +9,6 @@ import com.topjohnwu.superuser.Shell;
public class RebootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Shell.su_raw("/system/bin/reboot");
Shell.Async.su("/system/bin/reboot");
}
}

View File

@ -26,6 +26,7 @@ public class Const {
public static final String SU_KEYSTORE_KEY = "su_key";
// Paths
private static String MAGISK_PATH = null;
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";
@ -38,14 +39,17 @@ public class Const {
public static final int SNET_VER = 7;
public static final int MIN_MODULE_VER = 1400;
public static String MAGISK_PATH() {
if (Utils.itemExist("/sbin/.core/img")) {
return "/sbin/.core/img";
} else if (Utils.itemExist("/dev/magisk/img")) {
return "/dev/magisk/img";
} else {
return "/magisk";
public synchronized static String MAGISK_PATH() {
if (MAGISK_PATH == null) {
if (Utils.itemExist("/sbin/.core/img")) {
MAGISK_PATH = "/sbin/.core/img";
} else if (Utils.itemExist("/dev/magisk/img")) {
MAGISK_PATH = "/dev/magisk/img";
} else {
MAGISK_PATH = "/magisk";
}
}
return MAGISK_PATH;
}
public static String MAGISK_HOST_FILE() {

View File

@ -111,7 +111,7 @@ public class ShowUI {
if (Shell.rootAccess()) {
options.add(mm.getString(R.string.direct_install));
}
List<String> res = Shell.su("echo $SLOT");
List<String> res = Shell.Sync.su("echo $SLOT");
if (Utils.isValidShellResponse(res)) {
options.add(mm.getString(R.string.install_second_slot));
}
@ -185,13 +185,13 @@ public class ShowUI {
if (slot[1] == 'a') slot[1] = 'b';
else slot[1] = 'a';
// Then find the boot image again
List<String> ret = Shell.su(
List<String> ret = Shell.Sync.su(
"SLOT=" + String.valueOf(slot),
"find_boot_image",
"echo \"$BOOTIMAGE\""
);
boot = Utils.isValidShellResponse(ret) ? ret.get(ret.size() - 1) : null;
Shell.su_raw("mount_partitions");
Shell.Async.su("mount_partitions");
if (boot == null)
return;
receiver = new DownloadReceiver() {
@ -266,7 +266,7 @@ public class ShowUI {
return;
}
Shell.su(
Shell.Sync.su(
Utils.fmt("echo '%s' > /cache/%s", uninstaller.toString().replace("'", "'\\''"), Const.UNINSTALLER),
Utils.fmt("echo '%s' > %s/%s", utils.toString().replace("'", "'\\''"),
mm.magiskVersionCode >= 1464 ? "/data/adb/magisk" : "/data/magisk", Const.UTIL_FUNCTIONS)

View File

@ -47,12 +47,12 @@ public class Utils {
public static boolean isDownloading = false;
public static boolean itemExist(Object path) {
List<String> ret = Shell.su(fmt("[ -e %s ] && echo true || echo false", path));
List<String> ret = Shell.Sync.su(fmt("[ -e %s ] && echo true || echo false", path));
return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0));
}
public static void createFile(Object path) {
Shell.su_raw(fmt("mkdir -p `dirname '%s'` 2>/dev/null; touch '%s' 2>/dev/null", path, path));
Shell.Async.su(fmt("mkdir -p `dirname '%s'` 2>/dev/null; touch '%s' 2>/dev/null", path, path));
}
public static boolean javaCreateFile(File path) {
@ -67,20 +67,20 @@ public class Utils {
}
public static void removeItem(Object path) {
Shell.su_raw(fmt("rm -rf %s 2>/dev/null", path));
Shell.Async.su(fmt("rm -rf %s 2>/dev/null", path));
}
public static List<String> readFile(Object path) {
return Shell.su(fmt("cat %s | sed '$a\\ ' | sed '$d'", path));
return Shell.Sync.su(fmt("cat %s | sed '$a\\ ' | sed '$d'", path));
}
public static String checkInode(Object path) {
List<String> ret = Shell.su(fmt("ls -i %s", path));
List<String> ret = Shell.Sync.su(fmt("ls -i %s", path));
return isValidShellResponse(ret) ? ret.get(0).trim().split("\\s+")[0] : path.toString();
}
public static void uninstallPkg(String pkg) {
Shell.su(fmt("umount -l /data/user*/*/%s/*/*.db 2>/dev/null; pm uninstall %s", pkg, pkg));
Shell.Sync.su(fmt("umount -l /data/user*/*/%s/*/*.db 2>/dev/null; pm uninstall %s", pkg, pkg));
}
public static void dlAndReceive(Context context, DownloadReceiver receiver, String link, String filename) {
@ -260,7 +260,7 @@ public class Utils {
public static void patchDTBO() {
MagiskManager mm = MagiskManager.get();
if (mm.magiskVersionCode >= 1446 && !mm.keepVerity) {
List<String> ret = Shell.su("patch_dtbo_image && echo true || echo false");
List<String> ret = Shell.Sync.su("patch_dtbo_image && echo true || echo false");
if (Utils.isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(ret.size() - 1))) {
ShowUI.dtboPatchedNotification();
}
@ -278,7 +278,7 @@ public class Utils {
Map<String, ?> prefs = MagiskManager.get().prefs.getAll();
prefs.remove("App Restrictions");
String json = gson.toJson(prefs, new TypeToken<Map<String, ?>>(){}.getType());
Shell.su(fmt("for usr in /data/user/*; do echo '%s' > ${usr}/%s; done", json, Const.MANAGER_CONFIGS));
Shell.Sync.su(fmt("for usr in /data/user/*; do echo '%s' > ${usr}/%s; done", json, Const.MANAGER_CONFIGS));
}
public static void loadPrefs() {