mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 20:15:29 +00:00
Added appending installers to modules
This commit is contained in:
parent
967bdeae7b
commit
0785945635
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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,
|
||||
|
@ -73,6 +73,7 @@
|
||||
<string name="download_complete">Download complete</string>
|
||||
<string name="download_local">Looking for local copies…</string>
|
||||
<string name="download_progress">%1$.2f / %2$.2f MB</string>
|
||||
<string name="download_module">Injecting installer…</string>
|
||||
<string name="download_file_error">Error downloading file</string>
|
||||
<string name="magisk_update_title">Magisk Update Available!</string>
|
||||
<string name="manager_update_title">Magisk Manager Update Available!</string>
|
||||
|
Loading…
Reference in New Issue
Block a user