diff --git a/app/src/main/java/com/topjohnwu/magisk/tasks/FlashZip.kt b/app/src/main/java/com/topjohnwu/magisk/tasks/FlashZip.kt index 0594dc2bb..0a42d1783 100644 --- a/app/src/main/java/com/topjohnwu/magisk/tasks/FlashZip.kt +++ b/app/src/main/java/com/topjohnwu/magisk/tasks/FlashZip.kt @@ -1,73 +1,96 @@ package com.topjohnwu.magisk.tasks import android.net.Uri - +import com.skoumal.teanity.extensions.subscribeK import com.topjohnwu.magisk.App import com.topjohnwu.magisk.Const -import com.topjohnwu.magisk.utils.* +import com.topjohnwu.magisk.utils.fileName +import com.topjohnwu.magisk.utils.inject +import com.topjohnwu.magisk.utils.readUri +import com.topjohnwu.magisk.utils.unzip import com.topjohnwu.superuser.Shell -import com.topjohnwu.superuser.internal.UiThreadHandler - +import io.reactivex.Single import java.io.File import java.io.FileNotFoundException import java.io.IOException -abstract class FlashZip(private val mUri: Uri, - private val console: MutableList, - private val logs: MutableList) { +abstract class FlashZip( + private val mUri: Uri, + private val console: MutableList, + private val logs: MutableList +) { - private val tmpFile: File = File(App.self.cacheDir, "install.zip") + private val app: App by inject() + private val tmpFile: File = File(app.cacheDir, "install.zip") @Throws(IOException::class) private fun unzipAndCheck(): Boolean { - unzip(tmpFile, tmpFile.parentFile!!, "META-INF/com/google/android", true) - return Shell.su("grep -q '#MAGISK' ${File(tmpFile.parentFile, "updater-script")}") - .exec().isSuccess + val parentFile = tmpFile.parentFile ?: return false + tmpFile.unzip(parentFile, "META-INF/com/google/android", true) + + val updaterScript = File(parentFile, "updater-script") + return Shell + .su("grep -q '#MAGISK' $updaterScript") + .exec() + .isSuccess } @Throws(IOException::class) private fun flash(): Boolean { console.add("- Copying zip to temp directory") - try { - App.self.readUri(mUri).use { input -> + + runCatching { + app.readUri(mUri).use { input -> tmpFile.outputStream().use { out -> input.copyTo(out) } } - } catch (e: FileNotFoundException) { - console.add("! Invalid Uri") - throw e - } catch (e: IOException) { - console.add("! Cannot copy to cache") - throw e + }.getOrElse { + when (it) { + is FileNotFoundException -> console.add("! Invalid Uri") + is IOException -> console.add("! Cannot copy to cache") + } + throw it } - try { - if (!unzipAndCheck()) { - console.add("! This zip is not a Magisk Module!") - return false - } - } catch (e: IOException) { + val isMagiskModule = runCatching { + unzipAndCheck() + }.getOrElse { console.add("! Unzip error") - throw e + throw it + } + + if (!isMagiskModule) { + console.add("! This zip is not a Magisk Module!") + return false } console.add("- Installing ${mUri.fileName}") - return Shell.su("cd " + tmpFile.parent!!, - "BOOTMODE=true sh update-binary dummy 1 $tmpFile") - .to(console, logs) - .exec().isSuccess + + val parentFile = tmpFile.parent ?: return false + + return Shell + .su( + "cd $parentFile", + "BOOTMODE=true sh update-binary dummy 1 $tmpFile" + ) + .to(console, logs) + .exec().isSuccess } - fun exec() { - App.THREAD_POOL.execute { - val success = try { + fun exec() = Single + .fromCallable { + runCatching { flash() - } catch (e: IOException) { + }.getOrElse { + it.printStackTrace() false + }.apply { + Shell.su("cd /", "rm -rf ${tmpFile.parent} ${Const.TMP_FOLDER_PATH}") + .submit() } - Shell.su("cd /", "rm -rf ${tmpFile.parent} ${Const.TMP_FOLDER_PATH}").submit() - UiThreadHandler.run { onResult(success) } } - } + .subscribeK(onError = { onResult(false) }) { onResult(it) } + .let { Unit } // ignores result disposable + protected abstract fun onResult(success: Boolean) } 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 e10d38420..39727e52d 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.Companion.rmAndLaunch(app.getPackageName(), + RootUtils.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 95389302f..13e6f65bf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java @@ -3,8 +3,6 @@ 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; @@ -29,6 +27,8 @@ 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"; @@ -56,7 +56,7 @@ public class PatchAPK { return builder.toString(); } - private static boolean findAndPatch(byte xml[], String from, String to) { + private static boolean findAndPatch(byte[] xml, String from, String to) { if (from.length() != to.length()) return false; CharBuffer buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(); @@ -83,7 +83,7 @@ public class PatchAPK { return true; } - private static boolean findAndPatch(byte xml[], int a, int b) { + private static boolean findAndPatch(byte[] xml, int a, int b) { IntBuffer buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); int len = xml.length / 4; for (int i = 0; i < len; ++i) { @@ -112,7 +112,7 @@ public class PatchAPK { Config.set(Config.Key.SU_MANAGER, pkg); Config.export(); - RootUtils.Companion.rmAndLaunch(BuildConfig.APPLICATION_ID, + RootUtils.rmAndLaunch(BuildConfig.APPLICATION_ID, new ComponentName(pkg, ClassMap.get(SplashActivity.class).getName())); return true; @@ -122,7 +122,7 @@ public class PatchAPK { try { JarMap jar = new JarMap(in); JarEntry je = jar.getJarEntry(Const.ANDROID_MANIFEST); - byte xml[] = jar.getRawData(je); + byte[] xml = jar.getRawData(je); if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) || !findAndPatch(xml, R.string.app_name, R.string.re_app_name)) diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt b/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt index baa9ed7dd..5a1716931 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/RootUtils.kt @@ -38,72 +38,70 @@ fun Intent.toCommand(args: MutableList) { } val extras = extras if (extras != null) { - for (key in extras.keySet()) { + loop@ 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(',') + when { + v is String -> arg = "--es" + v is Boolean -> arg = "--ez" + v is Int -> arg = "--ei" + v is Long -> arg = "--el" + v is Float -> arg = "--ef" + v is Uri -> arg = "--eu" + v is ComponentName -> { + arg = "--ecn" + value = v.flattenToString() } - // 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()) - "--esa" - else - continue /* Unsupported */ + v is ArrayList<*> -> { + if (v.size <= 0) + /* Impossible to know the type due to type erasure */ + continue@loop - val sb = StringBuilder() - val len = RArray.getLength(v) - for (i in 0 until len) { - sb.append(RArray.get(v, i)!!.toString().replace(",", "\\,")) - sb.append(',') + 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@loop /* 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 } - // Remove trailing comma - sb.deleteCharAt(sb.length - 1) - value = sb - } else - continue /* Unsupported */ + 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()) + "--esa" + else + continue@loop /* 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@loop + } /* Unsupported */ args.add(arg) args.add(key) @@ -153,10 +151,12 @@ class RootUtils : Shell.Initializer() { companion object { + @JvmStatic fun rmAndLaunch(rm: String, component: ComponentName) { Shell.su("(rm_launch $rm ${component.flattenToString()})").exec() } + @JvmStatic fun reboot() { Shell.su("/system/bin/reboot ${if (Config.recovery) "recovery" else ""}").submit() } diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.kt b/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.kt index 80a90a13a..322750717 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.kt @@ -9,16 +9,16 @@ import java.util.zip.ZipEntry import java.util.zip.ZipInputStream @Throws(IOException::class) -fun unzip(zip: File, folder: File, path: String = "", junkPath: Boolean = false) { - zip.inputStream().buffered().use { - unzip(it, folder, path, junkPath) +fun File.unzip(folder: File, path: String = "", junkPath: Boolean = false) { + inputStream().buffered().use { + it.unzip(folder, path, junkPath) } } @Throws(IOException::class) -fun unzip(zip: InputStream, folder: File, path: String, junkPath: Boolean) { +fun InputStream.unzip(folder: File, path: String, junkPath: Boolean) { try { - val zin = ZipInputStream(zip) + val zin = ZipInputStream(this) var entry: ZipEntry while (true) { entry = zin.nextEntry ?: break 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 aff566fb3..95e1364b6 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,8 +4,6 @@ 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; @@ -14,6 +12,8 @@ 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.Companion::reboot, 5000); + UiThreadHandler.handler.postDelayed(RootUtils::reboot, 5000); } }.exec(); });