You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Remove more code using RxJava
This commit is contained in:
@@ -8,23 +8,22 @@ import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.core.utils.SafetyNetHelper
|
||||
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||
import com.topjohnwu.magisk.extensions.DynamicClassLoader
|
||||
import com.topjohnwu.magisk.extensions.OnErrorListener
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.extensions.writeTo
|
||||
import com.topjohnwu.magisk.ui.safetynet.SafetyNetResult
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import dalvik.system.DexFile
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import kotlinx.coroutines.*
|
||||
import org.json.JSONObject
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.lang.reflect.InvocationHandler
|
||||
|
||||
/**
|
||||
@@ -38,11 +37,15 @@ abstract class ViewEvent {
|
||||
var handled = false
|
||||
}
|
||||
|
||||
abstract class ViewEventsWithScope: ViewEvent() {
|
||||
lateinit var scope: CoroutineScope
|
||||
}
|
||||
|
||||
class CheckSafetyNetEvent(
|
||||
private val callback: (SafetyNetResult) -> Unit = {}
|
||||
) : ViewEvent(), ContextExecutor, KoinComponent, SafetyNetHelper.Callback {
|
||||
) : ViewEventsWithScope(), ContextExecutor, KoinComponent, SafetyNetHelper.Callback {
|
||||
|
||||
private val magiskRepo by inject<MagiskRepository>()
|
||||
private val svc by inject<GithubRawServices>()
|
||||
|
||||
private lateinit var apk: File
|
||||
private lateinit var dex: File
|
||||
@@ -51,51 +54,72 @@ class CheckSafetyNetEvent(
|
||||
apk = File("${context.filesDir.parent}/snet", "snet.jar")
|
||||
dex = File(apk.parent, "snet.dex")
|
||||
|
||||
attest(context) {
|
||||
// Download and retry
|
||||
Shell.sh("rm -rf " + apk.parent).exec()
|
||||
apk.parentFile?.mkdir()
|
||||
download(context, true)
|
||||
scope.launch {
|
||||
attest(context) {
|
||||
// Download and retry
|
||||
withContext(Dispatchers.IO) {
|
||||
Shell.sh("rm -rf " + apk.parent).exec()
|
||||
apk.parentFile?.mkdir()
|
||||
}
|
||||
download(context, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun attest(context: Context, onError: OnErrorListener) {
|
||||
Completable.fromAction {
|
||||
val loader = DynamicClassLoader(apk)
|
||||
val dex = DexFile.loadDex(apk.path, dex.path, 0)
|
||||
private suspend fun attest(context: Context, onError: suspend (Exception) -> Unit) {
|
||||
try {
|
||||
val helper = withContext(Dispatchers.IO) {
|
||||
val loader = DynamicClassLoader(apk)
|
||||
val dex = DexFile.loadDex(apk.path, dex.path, 0)
|
||||
|
||||
// Scan through the dex and find our helper class
|
||||
var helperClass: Class<*>? = null
|
||||
for (className in dex.entries()) {
|
||||
if (className.startsWith("x.")) {
|
||||
val cls = loader.loadClass(className)
|
||||
if (InvocationHandler::class.java.isAssignableFrom(cls)) {
|
||||
helperClass = cls
|
||||
break
|
||||
// Scan through the dex and find our helper class
|
||||
var helperClass: Class<*>? = null
|
||||
for (className in dex.entries()) {
|
||||
if (className.startsWith("x.")) {
|
||||
val cls = loader.loadClass(className)
|
||||
if (InvocationHandler::class.java.isAssignableFrom(cls)) {
|
||||
helperClass = cls
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
helperClass ?: throw Exception()
|
||||
|
||||
val helper = helperClass
|
||||
.getMethod("get", Class::class.java, Context::class.java, Any::class.java)
|
||||
.invoke(null, SafetyNetHelper::class.java,
|
||||
context, this@CheckSafetyNetEvent) as SafetyNetHelper
|
||||
|
||||
if (helper.version < Const.SNET_EXT_VER)
|
||||
throw Exception()
|
||||
helper
|
||||
}
|
||||
helperClass ?: throw Exception()
|
||||
|
||||
val helper = helperClass
|
||||
.getMethod("get", Class::class.java, Context::class.java, Any::class.java)
|
||||
.invoke(null, SafetyNetHelper::class.java, context, this) as SafetyNetHelper
|
||||
|
||||
if (helper.version < Const.SNET_EXT_VER)
|
||||
throw Exception()
|
||||
|
||||
helper.attest()
|
||||
}.subscribeK(onError = onError)
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException)
|
||||
throw e
|
||||
onError(e)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun download(context: Context, askUser: Boolean) {
|
||||
fun downloadInternal() = magiskRepo.fetchSafetynet()
|
||||
.map { it.byteStream().writeTo(apk) }
|
||||
.subscribeK { attest(context) {
|
||||
fun downloadInternal() = scope.launch {
|
||||
val abort: suspend (Exception) -> Unit = {
|
||||
Timber.e(it)
|
||||
callback(SafetyNetResult())
|
||||
} }
|
||||
}
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
svc.fetchSafetynet().byteStream().writeTo(apk)
|
||||
}
|
||||
attest(context, abort)
|
||||
} catch (e: IOException) {
|
||||
if (e is CancellationException)
|
||||
throw e
|
||||
abort(e)
|
||||
}
|
||||
}
|
||||
|
||||
if (!askUser) {
|
||||
downloadInternal()
|
||||
@@ -126,27 +150,12 @@ class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), Activi
|
||||
override fun invoke(activity: BaseActivity) = activity.run(action)
|
||||
}
|
||||
|
||||
class OpenChangelogEvent(val item: Repo) : ViewEvent(), ContextExecutor {
|
||||
class OpenChangelogEvent(val item: Repo) : ViewEventsWithScope(), ContextExecutor {
|
||||
override fun invoke(context: Context) {
|
||||
MarkDownWindow.show(context, null, item.readme)
|
||||
}
|
||||
}
|
||||
|
||||
class RxPermissionEvent(
|
||||
val permissions: List<String>,
|
||||
val callback: PublishSubject<Boolean>
|
||||
) : ViewEvent(), ActivityExecutor {
|
||||
|
||||
override fun invoke(activity: BaseActivity) =
|
||||
activity.withPermissions(*permissions.toTypedArray()) {
|
||||
onSuccess {
|
||||
callback.onNext(true)
|
||||
}
|
||||
onFailure {
|
||||
callback.onNext(false)
|
||||
callback.onError(SecurityException("User refused permissions"))
|
||||
}
|
||||
scope.launch {
|
||||
MarkDownWindow.show(context, null, item::readme)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PermissionEvent(
|
||||
|
||||
@@ -8,6 +8,9 @@ import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ManagerInstallDialog : DialogEvent() {
|
||||
|
||||
@@ -28,7 +31,11 @@ class ManagerInstallDialog : DialogEvent() {
|
||||
if (Info.remote.app.note.isEmpty()) return
|
||||
applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
titleRes = R.string.app_changelog
|
||||
onClick { MarkDownWindow.show(context, null, Info.remote.app.note) }
|
||||
onClick {
|
||||
GlobalScope.launch(Dispatchers.Main.immediate) {
|
||||
MarkDownWindow.show(context, null, Info.remote.app.note)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user