diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt index 8dd591021..31a5d31df 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt @@ -26,7 +26,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import timber.log.Timber -import java.io.File import java.io.IOException import java.io.InputStream import java.io.OutputStream @@ -100,20 +99,16 @@ class DownloadService : NotificationService() { val apk = subject.file.toFile() service.fetchFile(subject.stub.link).byteStream().writeTo(apk) - // Patch - val patched = File(apk.parent, "patched.apk") - val label = applicationInfo.nonLocalizedLabel - if (!HideAPK.patch(this, apk, patched, packageName, label)) { - throw IOException("HideAPK patch error") + // Patch and install + val session = APKInstall.startSession(this) + session.openStream(this).use { + val label = applicationInfo.nonLocalizedLabel + if (!HideAPK.patch(this, apk, it, packageName, label)) { + throw IOException("HideAPK patch error") + } } apk.delete() - - // Install - val session = APKInstall.startSession(this) - patched.inputStream().copyAndClose(session.openStream(this)) subject.intent = session.waitIntent() - - patched.delete() } else { ActivityTracker.foreground?.let { // Relaunch the process if we are foreground diff --git a/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt b/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt index 3ec7ecc66..6ec467e29 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt @@ -1,7 +1,6 @@ package com.topjohnwu.magisk.core.tasks import android.app.Activity -import android.app.ProgressDialog import android.content.Context import android.content.Intent import android.widget.Toast @@ -26,8 +25,8 @@ import kotlinx.coroutines.Runnable import kotlinx.coroutines.withContext import timber.log.Timber import java.io.File -import java.io.FileOutputStream import java.io.IOException +import java.io.OutputStream import java.security.SecureRandom object HideAPK { @@ -66,29 +65,29 @@ object HideAPK { fun patch( context: Context, - apk: File, out: File, + apk: File, out: OutputStream, pkg: String, label: CharSequence ): Boolean { val info = context.packageManager.getPackageArchiveInfo(apk.path, 0) ?: return false val name = info.applicationInfo.nonLocalizedLabel.toString() try { - val jar = JarMap.open(apk, true) - val je = jar.getJarEntry(ANDROID_MANIFEST) - val xml = AXML(jar.getRawData(je)) + JarMap.open(apk, true).use { jar -> + val je = jar.getJarEntry(ANDROID_MANIFEST) + val xml = AXML(jar.getRawData(je)) - if (!xml.findAndPatch(APPLICATION_ID to pkg, name to label.toString())) - return false + if (!xml.findAndPatch(APPLICATION_ID to pkg, name to label.toString())) + return false - // Write apk changes - jar.getOutputStream(je).write(xml.bytes) - val keys = Keygen(context) - SignApk.sign(keys.cert, keys.key, jar, FileOutputStream(out)) + // Write apk changes + jar.getOutputStream(je).use { it.write(xml.bytes) } + val keys = Keygen(context) + SignApk.sign(keys.cert, keys.key, jar, out) + return true + } } catch (e: Exception) { Timber.e(e) return false } - - return true } private fun launchApp(activity: Activity, pkg: String) { @@ -116,19 +115,18 @@ object HideAPK { } // Generate a new random package name and signature - val repack = File(activity.cacheDir, "patched.apk") val pkg = genPackageName() Config.keyStoreRaw = "" - if (!patch(activity, stub, repack, pkg, label)) - return false - // Install and auto launch app val session = APKInstall.startSession(activity, pkg, onFailure) { launchApp(activity, pkg) } try { - session.install(activity, repack) + val success = session.openStream(activity).use { + patch(activity, stub, it, pkg, label) + } + if (!success) return false } catch (e: IOException) { Timber.e(e) return false @@ -139,7 +137,7 @@ object HideAPK { @Suppress("DEPRECATION") suspend fun hide(activity: Activity, label: String) { - val dialog = ProgressDialog(activity).apply { + val dialog = android.app.ProgressDialog(activity).apply { setTitle(activity.getString(R.string.hide_app_title)) isIndeterminate = true setCancelable(false) @@ -157,7 +155,7 @@ object HideAPK { @Suppress("DEPRECATION") suspend fun restore(activity: Activity) { - val dialog = ProgressDialog(activity).apply { + val dialog = android.app.ProgressDialog(activity).apply { setTitle(activity.getString(R.string.restore_img_msg)) isIndeterminate = true setCancelable(false) diff --git a/app/src/main/java/com/topjohnwu/magisk/signing/SignApk.java b/app/src/main/java/com/topjohnwu/magisk/signing/SignApk.java index 821216cb0..f14001328 100644 --- a/app/src/main/java/com/topjohnwu/magisk/signing/SignApk.java +++ b/app/src/main/java/com/topjohnwu/magisk/signing/SignApk.java @@ -492,7 +492,7 @@ public class SignApk { } public static void sign(X509Certificate cert, PrivateKey key, - JarMap inputJar, FileOutputStream outputFile) throws Exception { + JarMap inputJar, OutputStream outputStream) throws Exception { int alignment = 4; int hashes = 0; @@ -531,7 +531,7 @@ public class SignApk { // This assumes outputChunks are array-backed. To avoid this assumption, the // code could be rewritten to use FileChannel. for (ByteBuffer outputChunk : outputChunks) { - outputFile.write(outputChunk.array(), + outputStream.write(outputChunk.array(), outputChunk.arrayOffset() + outputChunk.position(), outputChunk.remaining()); outputChunk.position(outputChunk.limit()); }