Commit 71b0c8b4 authored by topjohnwu's avatar topjohnwu

Make stub patching 100% offline

parent cdc66c1a
...@@ -31,6 +31,7 @@ import java.io.IOException ...@@ -31,6 +31,7 @@ import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
...@@ -44,14 +45,12 @@ class DownloadService : NotificationService() { ...@@ -44,14 +45,12 @@ class DownloadService : NotificationService() {
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy()
job.cancel() job.cancel()
} }
private fun download(subject: Subject) { private fun download(subject: Subject) {
notifyUpdate(subject.notifyId) notifyUpdate(subject.notifyId)
val coroutineScope = CoroutineScope(job + Dispatchers.IO) CoroutineScope(job + Dispatchers.IO).launch {
coroutineScope.launch {
try { try {
val stream = service.fetchFile(subject.url).toProgressStream(subject) val stream = service.fetchFile(subject.url).toProgressStream(subject)
when (subject) { when (subject) {
...@@ -75,7 +74,7 @@ class DownloadService : NotificationService() { ...@@ -75,7 +74,7 @@ class DownloadService : NotificationService() {
} }
} }
private suspend fun handleApp(stream: InputStream, subject: Subject.App) { private fun handleApp(stream: InputStream, subject: Subject.App) {
fun writeTee(output: OutputStream) { fun writeTee(output: OutputStream) {
val uri = MediaStoreUtils.getFile("${subject.title}.apk").uri val uri = MediaStoreUtils.getFile("${subject.title}.apk").uri
val external = uri.outputStream() val external = uri.outputStream()
...@@ -96,9 +95,10 @@ class DownloadService : NotificationService() { ...@@ -96,9 +95,10 @@ class DownloadService : NotificationService() {
.setContentText("") .setContentText("")
} }
// Download // Extract stub
val apk = subject.file.toFile() val apk = subject.file.toFile()
service.fetchFile(subject.stub.link).byteStream().writeTo(apk) val zf = ZipFile(updateApk)
zf.getInputStream(zf.getEntry("assets/stub.apk")).writeTo(apk)
// Patch and install // Patch and install
val session = APKInstall.startSession(this) val session = APKInstall.startSession(this)
......
...@@ -22,8 +22,7 @@ data class MagiskJson( ...@@ -22,8 +22,7 @@ data class MagiskJson(
@Parcelize @Parcelize
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class StubJson( data class StubJson(
val versionCode: Int = -1, val versionCode: Int = -1
val link: String = ""
) : Parcelable ) : Parcelable
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
......
...@@ -9,9 +9,7 @@ import com.topjohnwu.magisk.R ...@@ -9,9 +9,7 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.StubApk import com.topjohnwu.magisk.StubApk
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.Provider import com.topjohnwu.magisk.core.Provider
import com.topjohnwu.magisk.core.di.ServiceLocator
import com.topjohnwu.magisk.core.utils.AXML import com.topjohnwu.magisk.core.utils.AXML
import com.topjohnwu.magisk.core.utils.Keygen import com.topjohnwu.magisk.core.utils.Keygen
import com.topjohnwu.magisk.ktx.await import com.topjohnwu.magisk.ktx.await
...@@ -40,8 +38,6 @@ object HideAPK { ...@@ -40,8 +38,6 @@ object HideAPK {
// Some arbitrary limit // Some arbitrary limit
const val MAX_LABEL_LENGTH = 32 const val MAX_LABEL_LENGTH = 32
private val svc get() = ServiceLocator.networkService
private fun genPackageName(): String { private fun genPackageName(): String {
val random = SecureRandom() val random = SecureRandom()
val len = 5 + random.nextInt(15) val len = 5 + random.nextInt(15)
...@@ -113,16 +109,12 @@ object HideAPK { ...@@ -113,16 +109,12 @@ object HideAPK {
activity.finish() activity.finish()
} }
@Suppress("BlockingMethodInNonBlockingContext") private fun patchAndHide(activity: Activity, label: String, onFailure: Runnable): Boolean {
private suspend fun patchAndHide(activity: Activity, label: String, onFailure: Runnable): Boolean {
val stub = File(activity.cacheDir, "stub.apk") val stub = File(activity.cacheDir, "stub.apk")
try { try {
svc.fetchFile(Info.remote.stub.link).byteStream().writeTo(stub) activity.assets.open("stub.apk").writeTo(stub)
} catch (e: IOException) { } catch (e: IOException) {
Timber.e(e) Timber.e(e)
stub.createNewFile()
val cmd = "\$MAGISKBIN/magiskinit -x manager ${stub.path}"
if (!Shell.cmd(cmd).exec().isSuccess)
return false return false
} }
......
...@@ -11,6 +11,7 @@ import org.gradle.api.Action ...@@ -11,6 +11,7 @@ import org.gradle.api.Action
import org.gradle.api.JavaVersion import org.gradle.api.JavaVersion
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Delete import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.StopExecutionException import org.gradle.api.tasks.StopExecutionException
import org.gradle.api.tasks.Sync import org.gradle.api.tasks.Sync
...@@ -218,13 +219,29 @@ fun Project.setupApp() { ...@@ -218,13 +219,29 @@ fun Project.setupApp() {
} }
android.applicationVariants.all { android.applicationVariants.all {
preBuildProvider.get().dependsOn(syncResources) val variantCapped = name.capitalize(Locale.ROOT)
val variantLowered = name.toLowerCase(Locale.ROOT)
val copyStub = tasks.register("copy${variantCapped}StubApk", Copy::class.java) {
dependsOn(syncResources)
into("src/main/assets")
from(rootProject.file("out/stub-${variantLowered}.apk")) {
rename { "stub.apk" }
}
onlyIf {
if (inputs.sourceFiles.files.size != 1)
throw StopExecutionException("Please build stub first! (./build.py stub)")
true
}
}
preBuildProvider.get().dependsOn(copyStub)
val keysDir = rootProject.file("tools/keys") val keysDir = rootProject.file("tools/keys")
val outSrcDir = File(buildDir, "generated/source/keydata/$name") val outSrcDir = File(buildDir, "generated/source/keydata/$name")
val outSrc = File(outSrcDir, "com/topjohnwu/magisk/signing/KeyData.java") val outSrc = File(outSrcDir, "com/topjohnwu/magisk/signing/KeyData.java")
val genSrcTask = tasks.register("generate${name.capitalize(Locale.ROOT)}KeyData") { val genSrcTask = tasks.register("generate${variantCapped}KeyData") {
inputs.dir(keysDir) inputs.dir(keysDir)
outputs.file(outSrc) outputs.file(outSrc)
doLast { doLast {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment