mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 09:17:50 +00:00
Directly stream apk into install session
This commit is contained in:
parent
6df42a4be7
commit
d11038f3de
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user