Commit d11038f3 authored by vvb2060's avatar vvb2060 Committed by John Wu

Directly stream apk into install session

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