From 0785945635df80337a8154200eed6645276e438a Mon Sep 17 00:00:00 2001 From: Viktor De Pasquale Date: Thu, 11 Jul 2019 18:44:05 +0200 Subject: [PATCH] Added appending installers to modules --- .../magisk/model/download/DownloadService.kt | 2 + .../model/download/RemoteFileService.kt | 71 +++++++++++++++++-- .../model/entity/internal/DownloadSubject.kt | 8 +++ .../com/topjohnwu/magisk/utils/XNetwork.kt | 22 ++++-- app/src/main/res/values/strings.xml | 1 + 5 files changed, 95 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt index 7ea6c13b3..c68bea1f6 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt @@ -43,6 +43,7 @@ open class DownloadService : RemoteFileService() { override fun onFinished(file: File, subject: DownloadSubject) = when (subject) { is Magisk -> onFinishedInternal(file, subject) is Module -> onFinishedInternal(file, subject) + else -> Unit } private fun onFinishedInternal( @@ -73,6 +74,7 @@ open class DownloadService : RemoteFileService() { ) = when (subject) { is Magisk -> addActionsInternal(file, subject) is Module -> addActionsInternal(file, subject) + else -> this } private fun NotificationCompat.Builder.addActionsInternal( diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt index f1cbb4711..29b792d9b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt @@ -8,14 +8,21 @@ import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.R import com.topjohnwu.magisk.data.repository.FileRepository import com.topjohnwu.magisk.model.entity.internal.DownloadSubject +import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* +import com.topjohnwu.magisk.utils.cachedFile +import com.topjohnwu.magisk.utils.withStreams import com.topjohnwu.magisk.utils.writeToCachedFile import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.superuser.ShellUtils import io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers import okhttp3.ResponseBody import org.koin.android.ext.android.inject import timber.log.Timber import java.io.File +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream abstract class RemoteFileService : NotificationService() { @@ -33,14 +40,17 @@ abstract class RemoteFileService : NotificationService() { // --- - private fun start(subject: DownloadSubject) = search(subject) + private fun startInternal(subject: DownloadSubject) = search(subject) .onErrorResumeNext(download(subject)) .doOnSubscribe { update(subject.hashCode()) { it.setContentTitle(subject.fileName) } } - .subscribeK { + .observeOn(AndroidSchedulers.mainThread()) + .doOnSuccess { runCatching { onFinished(it, subject) }.onFailure { Timber.e(it) } finish(it, subject) } + private fun start(subject: DownloadSubject) = startInternal(subject).subscribeK() + private fun search(subject: DownloadSubject) = Single.fromCallable { if (!Config.isDownloadCacheEnabled) { throw IllegalStateException("The download cache is disabled") @@ -56,7 +66,7 @@ abstract class RemoteFileService : NotificationService() { .let { File(Const.EXTERNAL_PATH, it) } } - if (subject is DownloadSubject.Magisk) { + if (subject is Magisk) { if (!ShellUtils.checkSum("MD5", file, subject.magisk.hash)) { throw IllegalStateException("The given file doesn't match the hash") } @@ -66,8 +76,57 @@ abstract class RemoteFileService : NotificationService() { } private fun download(subject: DownloadSubject) = repo.downloadFile(subject.url) - .map { it.toFile(subject.hashCode(), subject.fileName) } - .map { map(subject, it) } + .map { + when (subject) { + is Module -> appendInstaller(it, subject) + else -> it.toFile(subject.hashCode(), subject.fileName) + } + } + + private fun appendInstaller(body: ResponseBody, subject: DownloadSubject): File { + update(subject.hashCode()) { + it.setContentText(getString(R.string.download_module)) + } + + val installer = startInternal(Installer).blockingGet() + val target = cachedFile(subject.fileName) + + val input = ZipInputStream(body.byteStream()) + val output = ZipOutputStream(target.outputStream()) + + withStreams(input, output) { zin, zout -> + zout.putNextEntry(ZipEntry("META-INF/")) + zout.putNextEntry(ZipEntry("META-INF/com/")) + 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")) + installer.inputStream().copyTo(zout).also { zout.flush() } + + zout.putNextEntry(ZipEntry("META-INF/com/google/android/updater-script")) + zout.write("#MAGISK\n".toByteArray(charset("UTF-8"))) + + var off = -1 + var entry: ZipEntry? = zin.nextEntry + while (entry != null) { + Timber.i("Let's gooo (${entry.name})") + if (off < 0) { + off = entry.name.indexOf('/') + 1 + } + + val path = entry.name.substring(off) + if (path.isNotEmpty() && !path.startsWith("META-INF")) { + zout.putNextEntry(ZipEntry(path)) + if (!entry.isDirectory) { + zin.copyTo(zout).also { zout.flush() } + } + } + + entry = zin.nextEntry + } + } + + return target + } // --- @@ -87,6 +146,8 @@ abstract class RemoteFileService : NotificationService() { } private fun finish(file: File, subject: DownloadSubject) = finishWork(subject.hashCode()) { + if (subject is Installer) return@finishWork null + it.addActions(file, subject) .setContentText(getString(R.string.download_complete)) .setSmallIcon(android.R.drawable.stat_sys_download_done) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt index 9be5934b8..028b5330f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt @@ -1,6 +1,8 @@ package com.topjohnwu.magisk.model.entity.internal import android.os.Parcelable +import com.topjohnwu.magisk.BuildConfig +import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.model.entity.MagiskJson import com.topjohnwu.magisk.model.entity.Repo @@ -33,4 +35,10 @@ sealed class DownloadSubject : Parcelable { } + @Parcelize + object Installer : DownloadSubject() { + override val fileName: String get() = "module_installer(${BuildConfig.VERSION_CODE}).sh" + override val url: String get() = Const.Url.MODULE_INSTALLER + } + } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/XNetwork.kt b/app/src/main/java/com/topjohnwu/magisk/utils/XNetwork.kt index df7c91c41..591ae5187 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/XNetwork.kt +++ b/app/src/main/java/com/topjohnwu/magisk/utils/XNetwork.kt @@ -10,16 +10,30 @@ inline fun ResponseBody.writeToCachedFile( context: Context, fileName: String, progress: (Long) -> Unit = {} -): File { - val file = File(context.cacheDir, fileName) - withStreams(byteStream(), file.outputStream()) { inStream, outStream -> +): File = byteStream().writeToCachedFile(context, fileName, progress) + +inline fun InputStream.writeToCachedFile( + context: Context, + fileName: String, + progress: (Long) -> Unit = {} +) = context.cachedFile(fileName).apply { + writeToFile(this, progress) +} + +inline fun InputStream.writeToFile(file: File, progress: (Long) -> Unit = {}) = file.apply { + writeTo(file.outputStream(), progress) +} + +inline fun InputStream.writeTo(output: OutputStream, progress: (Long) -> Unit = {}) { + withStreams(this, output) { inStream, outStream -> inStream.copyToWithProgress(outStream, progress) } - return file } fun ResponseBody.writeToString() = string() +fun Context.cachedFile(name: String) = File(cacheDir, name) + inline fun InputStream.copyToWithProgress( out: OutputStream, progressEmitter: (Long) -> Unit, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 92e51ddb8..baebfea75 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -73,6 +73,7 @@ Download complete Looking for local copies… %1$.2f / %2$.2f MB + Injecting installer… Error downloading file Magisk Update Available! Magisk Manager Update Available!