mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 08:27:43 +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.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() {
|
|||||||
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
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
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
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
|||||||
|
|
||||||
@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 {
|
|||||||
|
|
||||||
@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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
// 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());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user