From c951b208a1e7fcd986a8c3c65a9a190ea4ecf58a Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 14 Mar 2024 14:31:02 -0700 Subject: [PATCH] Always update stub APK when upgrade --- .../magisk/core/download/DownloadEngine.kt | 76 +++++++------------ .../topjohnwu/magisk/core/download/Subject.kt | 16 +--- .../dialog/OnlineModuleInstallDialog.kt | 5 +- 3 files changed, 30 insertions(+), 67 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadEngine.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadEngine.kt index 25834f462..c6650df16 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadEngine.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadEngine.kt @@ -13,29 +13,26 @@ import android.os.Bundle import androidx.collection.SparseArrayCompat import androidx.collection.isNotEmpty import androidx.core.content.getSystemService -import androidx.core.net.toFile import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.MutableLiveData import com.topjohnwu.magisk.R import com.topjohnwu.magisk.StubApk import com.topjohnwu.magisk.core.ActivityTracker import com.topjohnwu.magisk.core.Const -import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.JobService import com.topjohnwu.magisk.core.base.BaseActivity import com.topjohnwu.magisk.core.cmp import com.topjohnwu.magisk.core.di.ServiceLocator import com.topjohnwu.magisk.core.intent import com.topjohnwu.magisk.core.isRunningAsStub -import com.topjohnwu.magisk.core.ktx.copyAndClose +import com.topjohnwu.magisk.core.ktx.cachedFile import com.topjohnwu.magisk.core.ktx.copyAll +import com.topjohnwu.magisk.core.ktx.copyAndClose import com.topjohnwu.magisk.core.ktx.forEach -import com.topjohnwu.magisk.core.ktx.selfLaunchIntent import com.topjohnwu.magisk.core.ktx.set import com.topjohnwu.magisk.core.ktx.withStreams import com.topjohnwu.magisk.core.ktx.writeTo import com.topjohnwu.magisk.core.tasks.HideAPK -import com.topjohnwu.magisk.core.utils.MediaStoreUtils import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream import com.topjohnwu.magisk.core.utils.ProgressInputStream import com.topjohnwu.magisk.utils.APKInstall @@ -46,11 +43,9 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import okhttp3.ResponseBody import timber.log.Timber -import java.io.ByteArrayInputStream import java.io.IOException import java.io.InputStream import java.io.OutputStream -import java.util.Properties import java.util.zip.ZipEntry import java.util.zip.ZipFile import java.util.zip.ZipInputStream @@ -169,7 +164,7 @@ class DownloadEngine( when (subject) { is Subject.App -> handleApp(stream, subject) is Subject.Module -> handleModule(stream, subject.file) - is Subject.Test -> stream.copyAndClose(subject.file.outputStream()) + else -> stream.copyAndClose(subject.file.outputStream()) } val activity = ActivityTracker.foreground if (activity != null && subject.autoLaunch) { @@ -178,7 +173,6 @@ class DownloadEngine( } else { notifyFinish(subject) } - subject.postDownload?.invoke() } catch (e: IOException) { Timber.e(e) notifyFail(subject) @@ -271,50 +265,32 @@ class DownloadEngine( } private suspend fun handleApp(stream: InputStream, subject: Subject.App) { - suspend fun writeTee(output: OutputStream) { - val uri = MediaStoreUtils.getFile("${subject.title}.apk").uri - val external = uri.outputStream() - stream.copyAndClose(TeeOutputStream(external, output)) - } + val external = subject.file.outputStream() if (isRunningAsStub) { val updateApk = StubApk.update(context) try { // Download full APK to stub update path - writeTee(updateApk.outputStream()) + stream.copyAndClose(TeeOutputStream(external, updateApk.outputStream())) - val zf = ZipFile(updateApk) - val prop = Properties() - prop.load(ByteArrayInputStream(zf.comment.toByteArray())) - val stubVersion = prop.getProperty("stubVersion").toIntOrNull() ?: -1 - if (Info.stub!!.version < stubVersion) { - // Also upgrade stub - notifyUpdate(subject.notifyId) { - it.setProgress(0, 0, true) - .setContentTitle(context.getString(R.string.hide_app_title)) - .setContentText("") - } - - // Extract stub - val apk = subject.file.toFile() - zf.getInputStream(zf.getEntry("assets/stub.apk")).writeTo(apk) - zf.close() - - // Patch and install - subject.intent = HideAPK.upgrade(context, apk) - ?: throw IOException("HideAPK patch error") - apk.delete() - } else { - ActivityTracker.foreground?.let { - // Relaunch the process if we are foreground - StubApk.restartProcess(it) - } ?: run { - // Or else kill the current process after posting notification - subject.intent = context.selfLaunchIntent() - subject.postDownload = { Runtime.getRuntime().exit(0) } - } - return + // Also upgrade stub + notifyUpdate(subject.notifyId) { + it.setProgress(0, 0, true) + .setContentTitle(context.getString(R.string.hide_app_title)) + .setContentText("") } + + // Extract stub + val zf = ZipFile(updateApk) + val apk = context.cachedFile("stub.apk") + apk.delete() + zf.getInputStream(zf.getEntry("assets/stub.apk")).writeTo(apk) + zf.close() + + // Patch and install + subject.intent = HideAPK.upgrade(context, apk) + ?: throw IOException("HideAPK patch error") + apk.delete() } catch (e: Exception) { // If any error occurred, do not let stub load the new APK updateApk.delete() @@ -322,14 +298,14 @@ class DownloadEngine( } } else { val session = APKInstall.startSession(context) - writeTee(session.openStream(context)) + stream.copyAndClose(TeeOutputStream(external, session.openStream(context))) subject.intent = session.waitIntent() } } private suspend fun handleModule(src: InputStream, file: Uri) { - val input = ZipInputStream(src.buffered()) - val output = ZipOutputStream(file.outputStream().buffered()) + val input = ZipInputStream(src) + val output = ZipOutputStream(file.outputStream()) withStreams(input, output) { zin, zout -> zout.putNextEntry(ZipEntry("META-INF/")) @@ -337,7 +313,7 @@ class DownloadEngine( zout.putNextEntry(ZipEntry("META-INF/com/google/")) zout.putNextEntry(ZipEntry("META-INF/com/google/android/")) zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary")) - context.assets.open("module_installer.sh").copyAll(zout) + context.assets.open("module_installer.sh").use { it.copyAll(zout) } zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script")) zout.write("#MAGISK\n".toByteArray()) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt index d75b035b1..d82ecae5c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt @@ -20,11 +20,6 @@ import kotlinx.parcelize.Parcelize import java.io.File import java.util.UUID -enum class Action { - Flash, - Download -} - sealed class Subject : Parcelable { abstract val url: String @@ -32,19 +27,17 @@ sealed class Subject : Parcelable { abstract val title: String abstract val notifyId: Int open val autoLaunch: Boolean get() = true - open val postDownload: (() -> Unit)? get() = null open fun pendingIntent(context: Context): PendingIntent? = null @Parcelize class Module( - val module: OnlineModule, - val action: Action, + private val module: OnlineModule, + override val autoLaunch: Boolean, override val notifyId: Int = Notifications.nextId() ) : Subject() { override val url: String get() = module.zipUrl override val title: String get() = module.downloadFilename - override val autoLaunch: Boolean get() = action == Action.Flash @IgnoredOnParcel override val file by lazy { @@ -65,12 +58,9 @@ sealed class Subject : Parcelable { @IgnoredOnParcel override val file by lazy { - AppContext.cachedFile("manager.apk").apply { delete() }.toUri() + MediaStoreUtils.getFile("${title}.apk").uri } - @IgnoredOnParcel - override var postDownload: (() -> Unit)? = null - @IgnoredOnParcel var intent: Intent? = null override fun pendingIntent(context: Context) = intent?.toPending(context) diff --git a/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt index 65e52b757..7d438e4dc 100644 --- a/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/dialog/OnlineModuleInstallDialog.kt @@ -2,7 +2,6 @@ package com.topjohnwu.magisk.dialog import com.topjohnwu.magisk.R import com.topjohnwu.magisk.core.di.ServiceLocator -import com.topjohnwu.magisk.core.download.Action import com.topjohnwu.magisk.core.download.DownloadEngine import com.topjohnwu.magisk.core.download.Subject import com.topjohnwu.magisk.core.model.module.OnlineModule @@ -22,9 +21,7 @@ class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog dialog.apply { fun download(install: Boolean) { - val action = if (install) Action.Flash else Action.Download - val subject = Subject.Module(item, action) - DownloadEngine.startWithActivity(activity, subject) + DownloadEngine.startWithActivity(activity, Subject.Module(item, install)) } val title = context.getString(R.string.repo_install_title,