You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Download Magisk Manager via new service
This commit is contained in:
@@ -14,9 +14,9 @@ import com.topjohnwu.magisk.extensions.provide
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.*
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
|
||||
import com.topjohnwu.magisk.ui.flash.FlashActivity
|
||||
import com.topjohnwu.magisk.utils.APKInstall
|
||||
import java.io.File
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
|
||||
@@ -33,6 +33,7 @@ open class DownloadService : RemoteFileService() {
|
||||
override fun onFinished(file: File, subject: DownloadSubject, id: Int) = when (subject) {
|
||||
is Magisk -> onFinishedInternal(file, subject, id)
|
||||
is Module -> onFinishedInternal(file, subject, id)
|
||||
is Manager -> onFinishedInternal(file, subject, id)
|
||||
}
|
||||
|
||||
private fun onFinishedInternal(
|
||||
@@ -55,6 +56,18 @@ open class DownloadService : RemoteFileService() {
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
private fun onFinishedInternal(
|
||||
file: File,
|
||||
subject: Manager,
|
||||
id: Int
|
||||
) {
|
||||
remove(id)
|
||||
when (subject.configuration) {
|
||||
is APK.Upgrade -> APKInstall.install(this, file)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
override fun NotificationCompat.Builder.addActions(
|
||||
@@ -63,6 +76,7 @@ open class DownloadService : RemoteFileService() {
|
||||
) = when (subject) {
|
||||
is Magisk -> addActionsInternal(file, subject)
|
||||
is Module -> addActionsInternal(file, subject)
|
||||
is Manager -> addActionsInternal(file, subject)
|
||||
}
|
||||
|
||||
private fun NotificationCompat.Builder.addActionsInternal(
|
||||
@@ -87,6 +101,14 @@ open class DownloadService : RemoteFileService() {
|
||||
else -> this
|
||||
}
|
||||
|
||||
private fun NotificationCompat.Builder.addActionsInternal(
|
||||
file: File,
|
||||
subject: Manager
|
||||
) = when (subject.configuration) {
|
||||
APK.Upgrade -> setContentIntent(APKInstall.installIntent(context, file))
|
||||
else -> this
|
||||
}
|
||||
|
||||
@Suppress("ReplaceSingleLineLet")
|
||||
private fun NotificationCompat.Builder.setContentIntent(intent: Intent) =
|
||||
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.topjohnwu.magisk.model.download
|
||||
|
||||
import android.content.ComponentName
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.ClassMap
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.ui.SplashActivity
|
||||
import com.topjohnwu.magisk.utils.PatchAPK
|
||||
import com.topjohnwu.magisk.utils.RootUtils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import dalvik.system.DexClassLoader
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
|
||||
private fun RemoteFileService.patchPackage(apk: File, id: Int): File {
|
||||
if (packageName != BuildConfig.APPLICATION_ID) {
|
||||
update(id) { notification ->
|
||||
notification.setProgress(0, 0, true)
|
||||
.setProgress(0, 0, true)
|
||||
.setContentTitle(getString(R.string.hide_manager_title))
|
||||
.setContentText("")
|
||||
}
|
||||
val patched = File(apk.parent, "patched.apk")
|
||||
try {
|
||||
// Try using the new APK to patch itself
|
||||
val loader = DexClassLoader(apk.path, apk.parent, null, ClassLoader.getSystemClassLoader())
|
||||
loader.loadClass("a.a")
|
||||
.getMethod("patchAPK", String::class.java, String::class.java, String::class.java)
|
||||
.invoke(null, apk.path, patched.path, packageName)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
// Fallback to use the current implementation
|
||||
PatchAPK.patch(apk.path, patched.path, packageName)
|
||||
}
|
||||
apk.delete()
|
||||
return patched
|
||||
} else {
|
||||
return apk
|
||||
}
|
||||
}
|
||||
|
||||
private fun RemoteFileService.restore(apk: File, id: Int): File {
|
||||
update(id) { notification ->
|
||||
notification.setProgress(0, 0, true)
|
||||
.setProgress(0, 0, true)
|
||||
.setContentTitle(getString(R.string.restore_img_msg))
|
||||
.setContentText("")
|
||||
}
|
||||
Config.export()
|
||||
// Make it world readable
|
||||
apk.setReadable(true, false)
|
||||
if (Shell.su("pm install $apk").exec().isSuccess)
|
||||
RootUtils.rmAndLaunch(packageName,
|
||||
ComponentName(BuildConfig.APPLICATION_ID,
|
||||
ClassMap.get<Class<*>>(SplashActivity::class.java).name))
|
||||
return apk
|
||||
}
|
||||
|
||||
fun RemoteFileService.handleAPK(apk: File, subject: DownloadSubject.Manager)
|
||||
= when (subject.configuration) {
|
||||
is Upgrade -> patchPackage(apk, subject.hashCode())
|
||||
is Restore -> restore(apk, subject.hashCode())
|
||||
}
|
||||
@@ -27,7 +27,7 @@ abstract class NotificationService : Service() {
|
||||
|
||||
// --
|
||||
|
||||
protected fun update(
|
||||
fun update(
|
||||
id: Int,
|
||||
body: (NotificationCompat.Builder) -> Unit = {}
|
||||
) {
|
||||
|
||||
@@ -11,8 +11,7 @@ import com.topjohnwu.magisk.extensions.firstMap
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.writeTo
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
|
||||
import com.topjohnwu.magisk.utils.ProgInputStream
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
@@ -80,6 +79,11 @@ abstract class RemoteFileService : NotificationService() {
|
||||
.map { stream.toModule(subject.file, it.byteStream()); subject.file }
|
||||
else -> Single.fromCallable { stream.writeTo(subject.file); subject.file }
|
||||
}
|
||||
}.map {
|
||||
when (subject) {
|
||||
is Manager -> handleAPK(it, subject)
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
@@ -17,7 +17,6 @@ data class UninstallerJson(
|
||||
val link: String = ""
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
@JsonSerializable
|
||||
data class MagiskJson(
|
||||
val version: String = "",
|
||||
@@ -25,12 +24,13 @@ data class MagiskJson(
|
||||
val link: String = "",
|
||||
val note: String = "",
|
||||
@Json(name = "md5") val hash: String = ""
|
||||
) : Parcelable
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
@JsonSerializable
|
||||
data class ManagerJson(
|
||||
val version: String = "",
|
||||
val versionCode: Int = -1,
|
||||
val link: String = "",
|
||||
val note: String = ""
|
||||
)
|
||||
) : Parcelable
|
||||
|
||||
@@ -16,6 +16,15 @@ sealed class Configuration : Parcelable {
|
||||
|
||||
}
|
||||
|
||||
sealed class APK : Configuration() {
|
||||
|
||||
@Parcelize
|
||||
object Upgrade : APK()
|
||||
|
||||
@Parcelize
|
||||
object Restore : APK()
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
object Download : Configuration()
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.extensions.cachedFile
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.model.entity.MagiskJson
|
||||
import com.topjohnwu.magisk.model.entity.ManagerJson
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import kotlinx.android.parcel.IgnoredOnParcel
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
@@ -20,8 +21,8 @@ sealed class DownloadSubject : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class Module(
|
||||
val module: Repo,
|
||||
val configuration: Configuration
|
||||
val module: Repo,
|
||||
val configuration: Configuration
|
||||
) : DownloadSubject() {
|
||||
override val url: String get() = module.zipUrl
|
||||
|
||||
@@ -31,6 +32,27 @@ sealed class DownloadSubject : Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class Manager(
|
||||
val configuration: Configuration.APK
|
||||
) : DownloadSubject() {
|
||||
|
||||
@IgnoredOnParcel
|
||||
val manager: ManagerJson = Info.remote.app
|
||||
|
||||
override val title: String
|
||||
get() = "MagiskManager-v${manager.version}(${manager.versionCode})"
|
||||
|
||||
override val url: String
|
||||
get() = manager.link
|
||||
|
||||
@IgnoredOnParcel
|
||||
override val file by lazy {
|
||||
get<Context>().cachedFile("manager.apk")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed class Magisk : DownloadSubject() {
|
||||
|
||||
abstract val configuration: Configuration
|
||||
|
||||
@@ -11,8 +11,11 @@ import com.topjohnwu.magisk.data.database.PolicyDao
|
||||
import com.topjohnwu.magisk.data.database.base.su
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.magisk.extensions.reboot
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.model.entity.ManagerJson
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
|
||||
import com.topjohnwu.magisk.utils.DownloadApp
|
||||
import com.topjohnwu.magisk.utils.SuLogger
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
@@ -73,9 +76,12 @@ open class GeneralReceiver : BroadcastReceiver() {
|
||||
}
|
||||
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context)
|
||||
Const.Key.BROADCAST_MANAGER_UPDATE -> {
|
||||
Info.remote = Info.remote.copy(app = Info.remote.app.copy(
|
||||
link = intent.getStringExtra(Const.Key.INTENT_SET_LINK) ?: ""))
|
||||
DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME))
|
||||
intent.getParcelableExtra<ManagerJson>(Const.Key.INTENT_SET_APP)?.let {
|
||||
Info.remote = Info.remote.copy(app = it)
|
||||
}
|
||||
DownloadService(context) {
|
||||
subject = DownloadSubject.Manager(Configuration.APK.Upgrade)
|
||||
}
|
||||
}
|
||||
Const.Key.BROADCAST_REBOOT -> reboot()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user