mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-02-25 19:27:24 +00:00
Always update stub APK when upgrade
This commit is contained in:
parent
050a073771
commit
c951b208a1
@ -13,29 +13,26 @@ import android.os.Bundle
|
|||||||
import androidx.collection.SparseArrayCompat
|
import androidx.collection.SparseArrayCompat
|
||||||
import androidx.collection.isNotEmpty
|
import androidx.collection.isNotEmpty
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.toFile
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.StubApk
|
import com.topjohnwu.magisk.StubApk
|
||||||
import com.topjohnwu.magisk.core.ActivityTracker
|
import com.topjohnwu.magisk.core.ActivityTracker
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.Info
|
|
||||||
import com.topjohnwu.magisk.core.JobService
|
import com.topjohnwu.magisk.core.JobService
|
||||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||||
import com.topjohnwu.magisk.core.cmp
|
import com.topjohnwu.magisk.core.cmp
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.core.intent
|
import com.topjohnwu.magisk.core.intent
|
||||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
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.copyAll
|
||||||
|
import com.topjohnwu.magisk.core.ktx.copyAndClose
|
||||||
import com.topjohnwu.magisk.core.ktx.forEach
|
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.set
|
||||||
import com.topjohnwu.magisk.core.ktx.withStreams
|
import com.topjohnwu.magisk.core.ktx.withStreams
|
||||||
import com.topjohnwu.magisk.core.ktx.writeTo
|
import com.topjohnwu.magisk.core.ktx.writeTo
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
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.MediaStoreUtils.outputStream
|
||||||
import com.topjohnwu.magisk.core.utils.ProgressInputStream
|
import com.topjohnwu.magisk.core.utils.ProgressInputStream
|
||||||
import com.topjohnwu.magisk.utils.APKInstall
|
import com.topjohnwu.magisk.utils.APKInstall
|
||||||
@ -46,11 +43,9 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.util.Properties
|
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
@ -169,7 +164,7 @@ class DownloadEngine(
|
|||||||
when (subject) {
|
when (subject) {
|
||||||
is Subject.App -> handleApp(stream, subject)
|
is Subject.App -> handleApp(stream, subject)
|
||||||
is Subject.Module -> handleModule(stream, subject.file)
|
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
|
val activity = ActivityTracker.foreground
|
||||||
if (activity != null && subject.autoLaunch) {
|
if (activity != null && subject.autoLaunch) {
|
||||||
@ -178,7 +173,6 @@ class DownloadEngine(
|
|||||||
} else {
|
} else {
|
||||||
notifyFinish(subject)
|
notifyFinish(subject)
|
||||||
}
|
}
|
||||||
subject.postDownload?.invoke()
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
notifyFail(subject)
|
notifyFail(subject)
|
||||||
@ -271,23 +265,14 @@ class DownloadEngine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleApp(stream: InputStream, subject: Subject.App) {
|
private suspend fun handleApp(stream: InputStream, subject: Subject.App) {
|
||||||
suspend fun writeTee(output: OutputStream) {
|
val external = subject.file.outputStream()
|
||||||
val uri = MediaStoreUtils.getFile("${subject.title}.apk").uri
|
|
||||||
val external = uri.outputStream()
|
|
||||||
stream.copyAndClose(TeeOutputStream(external, output))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRunningAsStub) {
|
if (isRunningAsStub) {
|
||||||
val updateApk = StubApk.update(context)
|
val updateApk = StubApk.update(context)
|
||||||
try {
|
try {
|
||||||
// Download full APK to stub update path
|
// 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
|
// Also upgrade stub
|
||||||
notifyUpdate(subject.notifyId) {
|
notifyUpdate(subject.notifyId) {
|
||||||
it.setProgress(0, 0, true)
|
it.setProgress(0, 0, true)
|
||||||
@ -296,7 +281,9 @@ class DownloadEngine(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract stub
|
// Extract stub
|
||||||
val apk = subject.file.toFile()
|
val zf = ZipFile(updateApk)
|
||||||
|
val apk = context.cachedFile("stub.apk")
|
||||||
|
apk.delete()
|
||||||
zf.getInputStream(zf.getEntry("assets/stub.apk")).writeTo(apk)
|
zf.getInputStream(zf.getEntry("assets/stub.apk")).writeTo(apk)
|
||||||
zf.close()
|
zf.close()
|
||||||
|
|
||||||
@ -304,17 +291,6 @@ class DownloadEngine(
|
|||||||
subject.intent = HideAPK.upgrade(context, apk)
|
subject.intent = HideAPK.upgrade(context, apk)
|
||||||
?: throw IOException("HideAPK patch error")
|
?: throw IOException("HideAPK patch error")
|
||||||
apk.delete()
|
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
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// If any error occurred, do not let stub load the new APK
|
// If any error occurred, do not let stub load the new APK
|
||||||
updateApk.delete()
|
updateApk.delete()
|
||||||
@ -322,14 +298,14 @@ class DownloadEngine(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val session = APKInstall.startSession(context)
|
val session = APKInstall.startSession(context)
|
||||||
writeTee(session.openStream(context))
|
stream.copyAndClose(TeeOutputStream(external, session.openStream(context)))
|
||||||
subject.intent = session.waitIntent()
|
subject.intent = session.waitIntent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleModule(src: InputStream, file: Uri) {
|
private suspend fun handleModule(src: InputStream, file: Uri) {
|
||||||
val input = ZipInputStream(src.buffered())
|
val input = ZipInputStream(src)
|
||||||
val output = ZipOutputStream(file.outputStream().buffered())
|
val output = ZipOutputStream(file.outputStream())
|
||||||
|
|
||||||
withStreams(input, output) { zin, zout ->
|
withStreams(input, output) { zin, zout ->
|
||||||
zout.putNextEntry(ZipEntry("META-INF/"))
|
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/"))
|
||||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/"))
|
zout.putNextEntry(ZipEntry("META-INF/com/google/android/"))
|
||||||
zout.putNextEntry(ZipEntry("META-INF/com/google/android/update-binary"))
|
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.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script"))
|
||||||
zout.write("#MAGISK\n".toByteArray())
|
zout.write("#MAGISK\n".toByteArray())
|
||||||
|
@ -20,11 +20,6 @@ import kotlinx.parcelize.Parcelize
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
enum class Action {
|
|
||||||
Flash,
|
|
||||||
Download
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Subject : Parcelable {
|
sealed class Subject : Parcelable {
|
||||||
|
|
||||||
abstract val url: String
|
abstract val url: String
|
||||||
@ -32,19 +27,17 @@ sealed class Subject : Parcelable {
|
|||||||
abstract val title: String
|
abstract val title: String
|
||||||
abstract val notifyId: Int
|
abstract val notifyId: Int
|
||||||
open val autoLaunch: Boolean get() = true
|
open val autoLaunch: Boolean get() = true
|
||||||
open val postDownload: (() -> Unit)? get() = null
|
|
||||||
|
|
||||||
open fun pendingIntent(context: Context): PendingIntent? = null
|
open fun pendingIntent(context: Context): PendingIntent? = null
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
class Module(
|
class Module(
|
||||||
val module: OnlineModule,
|
private val module: OnlineModule,
|
||||||
val action: Action,
|
override val autoLaunch: Boolean,
|
||||||
override val notifyId: Int = Notifications.nextId()
|
override val notifyId: Int = Notifications.nextId()
|
||||||
) : Subject() {
|
) : Subject() {
|
||||||
override val url: String get() = module.zipUrl
|
override val url: String get() = module.zipUrl
|
||||||
override val title: String get() = module.downloadFilename
|
override val title: String get() = module.downloadFilename
|
||||||
override val autoLaunch: Boolean get() = action == Action.Flash
|
|
||||||
|
|
||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
override val file by lazy {
|
override val file by lazy {
|
||||||
@ -65,12 +58,9 @@ sealed class Subject : Parcelable {
|
|||||||
|
|
||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
override val file by lazy {
|
override val file by lazy {
|
||||||
AppContext.cachedFile("manager.apk").apply { delete() }.toUri()
|
MediaStoreUtils.getFile("${title}.apk").uri
|
||||||
}
|
}
|
||||||
|
|
||||||
@IgnoredOnParcel
|
|
||||||
override var postDownload: (() -> Unit)? = null
|
|
||||||
|
|
||||||
@IgnoredOnParcel
|
@IgnoredOnParcel
|
||||||
var intent: Intent? = null
|
var intent: Intent? = null
|
||||||
override fun pendingIntent(context: Context) = intent?.toPending(context)
|
override fun pendingIntent(context: Context) = intent?.toPending(context)
|
||||||
|
@ -2,7 +2,6 @@ package com.topjohnwu.magisk.dialog
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
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.DownloadEngine
|
||||||
import com.topjohnwu.magisk.core.download.Subject
|
import com.topjohnwu.magisk.core.download.Subject
|
||||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||||
@ -22,9 +21,7 @@ class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog
|
|||||||
dialog.apply {
|
dialog.apply {
|
||||||
|
|
||||||
fun download(install: Boolean) {
|
fun download(install: Boolean) {
|
||||||
val action = if (install) Action.Flash else Action.Download
|
DownloadEngine.startWithActivity(activity, Subject.Module(item, install))
|
||||||
val subject = Subject.Module(item, action)
|
|
||||||
DownloadEngine.startWithActivity(activity, subject)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val title = context.getString(R.string.repo_install_title,
|
val title = context.getString(R.string.repo_install_title,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user