diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bd57d1d8b..cc9294829 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -98,7 +98,7 @@ dependencies { implementation("io.noties.markwon:image:${vMarkwon}") implementation("com.caverock:androidsvg:1.4") - val vLibsu = "2.5.1" + val vLibsu = "2.5.2" implementation("com.github.topjohnwu.libsu:core:${vLibsu}") implementation("com.github.topjohnwu.libsu:io:${vLibsu}") diff --git a/app/src/main/java/com/topjohnwu/magisk/core/App.kt b/app/src/main/java/com/topjohnwu/magisk/core/App.kt index 4adab55bd..9ce1ab5f1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/App.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/App.kt @@ -12,6 +12,7 @@ import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.FileProvider import com.topjohnwu.magisk.core.su.SuCallbackHandler +import com.topjohnwu.magisk.core.utils.IODispatcherExecutor import com.topjohnwu.magisk.core.utils.RootInit import com.topjohnwu.magisk.core.utils.updateConfig import com.topjohnwu.magisk.di.koinModules @@ -31,8 +32,9 @@ open class App() : Application() { init { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER) - Shell.Config.addInitializers(RootInit::class.java) + Shell.Config.setInitializers(RootInit::class.java) Shell.Config.setTimeout(2) + Shell.EXECUTOR = IODispatcherExecutor() FileProvider.callHandler = SuCallbackHandler // Always log full stack trace with Timber diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt index e68c217c8..208aa5b82 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt @@ -9,11 +9,11 @@ import com.topjohnwu.magisk.core.ForegroundTracker import com.topjohnwu.magisk.core.utils.ProgressInputStream import com.topjohnwu.magisk.core.view.Notifications import com.topjohnwu.magisk.data.network.GithubRawServices +import com.topjohnwu.magisk.ktx.checkSum import com.topjohnwu.magisk.ktx.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.superuser.ShellUtils import kotlinx.coroutines.launch import okhttp3.ResponseBody import org.koin.android.ext.android.inject @@ -48,7 +48,7 @@ abstract class RemoteFileService : NotificationService() { private suspend fun start(subject: DownloadSubject) { if (subject !is Magisk || !subject.file.exists() || - !ShellUtils.checkSum("MD5", subject.file, subject.magisk.md5)) { + !subject.file.checkSum("MD5", subject.magisk.md5)) { val stream = service.fetchFile(subject.url).toProgressStream(subject) when (subject) { is Module -> diff --git a/app/src/main/java/com/topjohnwu/magisk/core/utils/IODispatcherExecutor.kt b/app/src/main/java/com/topjohnwu/magisk/core/utils/IODispatcherExecutor.kt new file mode 100644 index 000000000..c12f037d3 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/core/utils/IODispatcherExecutor.kt @@ -0,0 +1,36 @@ +package com.topjohnwu.magisk.core.utils + +import kotlinx.coroutines.* +import java.util.concurrent.* + +class IODispatcherExecutor : AbstractExecutorService() { + + private val job = SupervisorJob().apply { invokeOnCompletion { future.run() } } + private val scope = CoroutineScope(job + Dispatchers.IO) + private val future = FutureTask(Callable { true }) + + override fun execute(command: Runnable) { + scope.launch { + command.run() + } + } + + override fun shutdown() = job.cancel() + + override fun shutdownNow(): List { + job.cancel() + return emptyList() + } + + override fun isShutdown() = job.isCancelled + + override fun isTerminated() = job.isCancelled && job.isCompleted + + override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean { + return try { + future.get(timeout, unit) + } catch (e: TimeoutException) { + false + } + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt b/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt index 8c816b58e..fbbece90b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ktx/XJava.kt @@ -8,10 +8,12 @@ import java.io.InputStream import java.io.OutputStream import java.lang.reflect.Field import java.lang.reflect.Method +import java.security.MessageDigest import java.text.SimpleDateFormat import java.util.* import java.util.zip.ZipEntry import java.util.zip.ZipInputStream +import kotlin.experimental.and fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) { var entry: ZipEntry? = nextEntry @@ -22,7 +24,24 @@ fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) { } fun InputStream.writeTo(file: File) = - withStreams(this, file.outputStream()) { reader, writer -> reader.copyTo(writer) } + withStreams(this, file.outputStream()) { reader, writer -> reader.copyTo(writer) } + +fun File.checkSum(alg: String, reference: String) = runCatching { + inputStream().use { + val digest = MessageDigest.getInstance(alg) + it.copyTo(object : OutputStream() { + override fun write(b: Int) { + digest.update(b.toByte()) + } + override fun write(b: ByteArray, off: Int, len: Int) { + digest.update(b, off, len) + } + }) + val sb = StringBuilder() + digest.digest().forEach { b -> sb.append("%02x".format(b and 0xff.toByte())) } + sb.toString() == reference + } +}.getOrElse { false } inline fun withStreams( inStream: In,