From d3f5f5ee59be4aa18bd957735146546d857d566d Mon Sep 17 00:00:00 2001 From: topjohnwu <topjohnwu@gmail.com> Date: Fri, 3 May 2019 03:36:39 -0400 Subject: [PATCH] Rewrite RootUtils in Kotlin --- .../topjohnwu/magisk/utils/DownloadApp.java | 2 +- .../com/topjohnwu/magisk/utils/PatchAPK.java | 6 +- .../com/topjohnwu/magisk/utils/RootUtils.java | 149 ---------------- .../com/topjohnwu/magisk/utils/RootUtils.kt | 164 ++++++++++++++++++ .../com/topjohnwu/magisk/utils/Utils.java | 27 +-- .../com/topjohnwu/magisk/utils/XAndroid.kt | 5 +- .../java/com/topjohnwu/magisk/utils/XList.kt | 14 ++ .../magisk/view/dialogs/EnvFixDialog.java | 6 +- 8 files changed, 195 insertions(+), 178 deletions(-) delete mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.java create mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java b/app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java index 39727e52d..e10d38420 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java @@ -89,7 +89,7 @@ public class DownloadApp { // Make it world readable apk.setReadable(true, false); if (Shell.su("pm install " + apk).exec().isSuccess()) - RootUtils.rmAndLaunch(app.getPackageName(), + RootUtils.Companion.rmAndLaunch(app.getPackageName(), new ComponentName(BuildConfig.APPLICATION_ID, ClassMap.get(SplashActivity.class).getName())); progress.dismiss(); diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java index 0d77c058a..95389302f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java @@ -3,6 +3,8 @@ package com.topjohnwu.magisk.utils; import android.content.ComponentName; import android.widget.Toast; +import androidx.core.app.NotificationCompat; + import com.topjohnwu.magisk.App; import com.topjohnwu.magisk.BuildConfig; import com.topjohnwu.magisk.ClassMap; @@ -27,8 +29,6 @@ import java.util.ArrayList; import java.util.List; import java.util.jar.JarEntry; -import androidx.core.app.NotificationCompat; - public class PatchAPK { public static final String LOWERALPHA = "abcdefghijklmnopqrstuvwxyz"; @@ -112,7 +112,7 @@ public class PatchAPK { Config.set(Config.Key.SU_MANAGER, pkg); Config.export(); - RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID, + RootUtils.Companion.rmAndLaunch(BuildConfig.APPLICATION_ID, new ComponentName(pkg, ClassMap.get(SplashActivity.class).getName())); return true; diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.java b/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.java deleted file mode 100644 index 216c2a3d0..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.topjohnwu.magisk.utils; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; - -import androidx.annotation.NonNull; - -import com.topjohnwu.magisk.Config; -import com.topjohnwu.magisk.Const; -import com.topjohnwu.magisk.R; -import com.topjohnwu.superuser.Shell; -import com.topjohnwu.superuser.ShellUtils; -import com.topjohnwu.superuser.io.SuFile; - -import java.io.InputStream; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.List; - -public class RootUtils extends Shell.Initializer { - - public static void rmAndLaunch(String rm, ComponentName component) { - Shell.su(Utils.fmt("(rm_launch %s %s)&", rm, component.flattenToString())).exec(); - } - - public static void reboot() { - Shell.su("/system/bin/reboot" + (Config.recovery ? " recovery" : "")).submit(); - } - - public static void startActivity(Intent intent) { - if (intent.getComponent() == null) - return; - List<String> args = new ArrayList<>(); - args.add("am"); - args.add("start"); - intentToCommand(intent, args); - Shell.su(Utils.argsToCommand(args)).exec(); - } - - public static void intentToCommand(Intent intent, List<String> args) { - if (intent.getAction() != null) { - args.add("-a"); - args.add(intent.getAction()); - } - if (intent.getComponent() != null) { - args.add("-n"); - args.add(intent.getComponent().flattenToString()); - } - if (intent.getData() != null) { - args.add("-d"); - args.add(intent.getDataString()); - } - if (intent.getCategories() != null) { - for (String cat : intent.getCategories()) { - args.add("-c"); - args.add(cat); - } - } - if (intent.getType() != null) { - args.add("-t"); - args.add(intent.getType()); - } - Bundle extras = intent.getExtras(); - if (extras != null) { - for (String key : extras.keySet()) { - Object val = extras.get(key); - if (val == null) - continue; - Object value = val; - String arg; - if (val instanceof String) arg = "--es"; - else if (val instanceof Boolean) arg = "--ez"; - else if (val instanceof Integer) arg = "--ei"; - else if (val instanceof Long) arg = "--el"; - else if (val instanceof Float) arg = "--ef"; - else if (val instanceof Uri) arg = "--eu"; - else if (val instanceof ComponentName) { - arg = "--ecn"; - value = ((ComponentName) val).flattenToString(); - } else if (val instanceof ArrayList) { - ArrayList arr = (ArrayList) val; - if (arr.size() <= 0) - /* Impossible to know the type due to type erasure */ - continue; - - if (arr.get(0) instanceof Integer) arg = "--eial"; - else if (arr.get(0) instanceof Long) arg = "--elal"; - else if (arr.get(0) instanceof Float) arg = "--efal"; - else if (arr.get(0) instanceof String) arg = "--esal"; - else continue; /* Unsupported */ - StringBuilder sb = new StringBuilder(); - for (Object o : arr) { - sb.append(o.toString().replace(",", "\\,")); - sb.append(','); - } - // Remove trailing comma - sb.deleteCharAt(sb.length() - 1); - value = sb; - } else if (val.getClass().isArray()) { - if (val instanceof int[]) arg = "--eia"; - else if (val instanceof long[]) arg = "--ela"; - else if (val instanceof float[]) arg = "--efa"; - else if (val instanceof String[]) arg = "--esa"; - else continue; /* Unsupported */ - StringBuilder sb = new StringBuilder(); - int len = Array.getLength(val); - for (int i = 0; i < len; ++i) { - sb.append(Array.get(val, i).toString().replace(",", "\\,")); - sb.append(','); - } - // Remove trailing comma - sb.deleteCharAt(sb.length() - 1); - value = sb; - } - else continue; /* Unsupported */ - - args.add(arg); - args.add(key); - args.add(value.toString()); - } - } - args.add("-f"); - args.add(String.valueOf(intent.getFlags())); - } - - @Override - public boolean onInit(Context context, @NonNull Shell shell) { - Shell.Job job = shell.newJob(); - if (shell.isRoot()) { - job.add(context.getResources().openRawResource(R.raw.util_functions)) - .add(context.getResources().openRawResource(R.raw.utils)); - Const.MAGISK_DISABLE_FILE = new SuFile("/cache/.disable_magisk"); - Config.loadMagiskInfo(); - } else { - InputStream nonroot = context.getResources().openRawResource(R.raw.nonroot_utils); - job.add(nonroot); - } - - job.add("mount_partitions", "get_flags", "run_migrations", "export BOOTMODE=true").exec(); - - Config.keepVerity = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPVERITY")); - Config.keepEnc = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPFORCEENCRYPT")); - Config.recovery = Boolean.parseBoolean(ShellUtils.fastCmd("echo $RECOVERYMODE")); - return true; - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt b/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt new file mode 100644 index 000000000..baa9ed7dd --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt @@ -0,0 +1,164 @@ +package com.topjohnwu.magisk.utils + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.net.Uri +import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.Const +import com.topjohnwu.magisk.R +import com.topjohnwu.superuser.Shell +import com.topjohnwu.superuser.ShellUtils +import com.topjohnwu.superuser.io.SuFile +import java.util.* +import java.lang.reflect.Array as RArray + +fun Intent.toCommand(args: MutableList<String>) { + if (action != null) { + args.add("-a") + args.add(action!!) + } + if (component != null) { + args.add("-n") + args.add(component!!.flattenToString()) + } + if (data != null) { + args.add("-d") + args.add(dataString!!) + } + if (categories != null) { + for (cat in categories) { + args.add("-c") + args.add(cat) + } + } + if (type != null) { + args.add("-t") + args.add(type!!) + } + val extras = extras + if (extras != null) { + for (key in extras.keySet()) { + val v = extras.get(key) ?: continue + var value: Any = v + val arg: String + if (v is String) + arg = "--es" + else if (v is Boolean) + arg = "--ez" + else if (v is Int) + arg = "--ei" + else if (v is Long) + arg = "--el" + else if (v is Float) + arg = "--ef" + else if (v is Uri) + arg = "--eu" + else if (v is ComponentName) { + arg = "--ecn" + value = v.flattenToString() + } else if (v is ArrayList<*>) { + if (v.size <= 0) + /* Impossible to know the type due to type erasure */ + continue + + arg = if (v[0] is Int) + "--eial" + else if (v[0] is Long) + "--elal" + else if (v[0] is Float) + "--efal" + else if (v[0] is String) + "--esal" + else + continue /* Unsupported */ + + val sb = StringBuilder() + for (o in v) { + sb.append(o.toString().replace(",", "\\,")) + sb.append(',') + } + // Remove trailing comma + sb.deleteCharAt(sb.length - 1) + value = sb + } else if (v.javaClass.isArray) { + arg = if (v is IntArray) + "--eia" + else if (v is LongArray) + "--ela" + else if (v is FloatArray) + "--efa" + else if (v is Array<*> && v.isArrayOf<String>()) + "--esa" + else + continue /* Unsupported */ + + val sb = StringBuilder() + val len = RArray.getLength(v) + for (i in 0 until len) { + sb.append(RArray.get(v, i)!!.toString().replace(",", "\\,")) + sb.append(',') + } + // Remove trailing comma + sb.deleteCharAt(sb.length - 1) + value = sb + } else + continue /* Unsupported */ + + args.add(arg) + args.add(key) + args.add(value.toString()) + } + } + args.add("-f") + args.add(flags.toString()) +} + +fun startActivity(intent: Intent) { + if (intent.component == null) + return + val args = ArrayList<String>() + args.add("am") + args.add("start") + intent.toCommand(args) + Shell.su(args.toShellCmd()).exec() +} + +class RootUtils : Shell.Initializer() { + + override fun onInit(context: Context?, shell: Shell): Boolean { + context ?: return false + + val job = shell.newJob() + if (shell.isRoot) { + job.add(context.rawResource(R.raw.util_functions)) + .add(context.rawResource(R.raw.utils)) + Const.MAGISK_DISABLE_FILE = SuFile("/cache/.disable_magisk") + Config.loadMagiskInfo() + } else { + job.add(context.rawResource(R.raw.nonroot_utils)) + } + + job.add("mount_partitions", + "get_flags", + "run_migrations", + "export BOOTMODE=true") + .exec() + + Config.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean() + Config.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean() + Config.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean() + return true + } + + companion object { + + fun rmAndLaunch(rm: String, component: ComponentName) { + Shell.su("(rm_launch $rm ${component.flattenToString()})").exec() + } + + fun reboot() { + Shell.su("/system/bin/reboot ${if (Config.recovery) "recovery" else ""}").submit() + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java index 1cbcb06d5..562fcadf0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -12,6 +12,12 @@ import android.net.Uri; import android.provider.OpenableColumns; import android.widget.Toast; +import androidx.work.Constraints; +import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.NetworkType; +import androidx.work.PeriodicWorkRequest; +import androidx.work.WorkManager; + import com.topjohnwu.magisk.App; import com.topjohnwu.magisk.BuildConfig; import com.topjohnwu.magisk.ClassMap; @@ -25,17 +31,10 @@ import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.internal.UiThreadHandler; import com.topjohnwu.superuser.io.SuFile; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; -import androidx.work.Constraints; -import androidx.work.ExistingPeriodicWorkPolicy; -import androidx.work.NetworkType; -import androidx.work.PeriodicWorkRequest; -import androidx.work.WorkManager; - public class Utils { public static void toast(CharSequence msg, int duration) { @@ -166,18 +165,4 @@ public class Utils { } } - public static String argsToCommand(List<String> args) { - StringBuilder sb = new StringBuilder(); - for (String s : args) { - if (s.contains(" ")) { - sb.append('"').append(s).append('"'); - } else { - sb.append(s); - } - sb.append(' '); - } - sb.deleteCharAt(sb.length() - 1); - return sb.toString(); - } - } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt b/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt index bf594c755..e722bd134 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/XAndroid.kt @@ -1,5 +1,6 @@ package com.topjohnwu.magisk.utils +import android.content.Context import android.content.pm.ApplicationInfo import android.content.pm.ComponentInfo import android.content.pm.PackageInfo @@ -47,4 +48,6 @@ fun PackageManager.receivers(packageName: String) = getPackageInfo(packageName, GET_RECEIVERS).receivers fun PackageManager.providers(packageName: String) = - getPackageInfo(packageName, GET_PROVIDERS).providers \ No newline at end of file + getPackageInfo(packageName, GET_PROVIDERS).providers + +fun Context.rawResource(id: Int) = resources.openRawResource(id) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt b/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt index 705ee9bb3..26b5009fa 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/XList.kt @@ -10,6 +10,20 @@ fun <T> MutableList<T>.update(newList: List<T>) { addAll(newList) } +fun List<String>.toShellCmd() : String { + val sb = StringBuilder() + for (s in this) { + if (s.contains(" ")) { + sb.append('"').append(s).append('"') + } else { + sb.append(s) + } + sb.append(' ') + } + sb.deleteCharAt(sb.length - 1) + return sb.toString() +} + fun <T1, T2> ObservableList<T1>.sendUpdatesTo( target: DiffObservableList<T2>, mapper: (List<T1>) -> List<T2> diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.java b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.java index 95e1364b6..aff566fb3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.java +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/EnvFixDialog.java @@ -4,6 +4,8 @@ import android.app.Activity; import android.app.ProgressDialog; import android.widget.Toast; +import androidx.annotation.NonNull; + import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.tasks.MagiskInstaller; import com.topjohnwu.magisk.utils.RootUtils; @@ -12,8 +14,6 @@ import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.internal.UiThreadHandler; import com.topjohnwu.superuser.io.SuFile; -import androidx.annotation.NonNull; - public class EnvFixDialog extends CustomAlertDialog { public EnvFixDialog(@NonNull Activity activity) { @@ -38,7 +38,7 @@ public class EnvFixDialog extends CustomAlertDialog { pd.dismiss(); Utils.toast(success ? R.string.reboot_delay_toast : R.string.setup_fail, Toast.LENGTH_LONG); if (success) - UiThreadHandler.handler.postDelayed(RootUtils::reboot, 5000); + UiThreadHandler.handler.postDelayed(RootUtils.Companion::reboot, 5000); } }.exec(); });