From 6ae2c9387d1e4b88cfb5fdf57834ee5c3958de2b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 26 Jan 2021 04:17:37 -0800 Subject: [PATCH] Use stub APK hiding method for Android 5.0+ At the same time, disable app hiding on devices lower than 5.0 to simplify the logic in the app. By doing so, a hidden app always implies running as stub. --- .../magisk/core/download/ManagerHandler.kt | 30 +++++------- .../topjohnwu/magisk/core/tasks/HideAPK.kt | 47 +++++++------------ .../magisk/ui/settings/SettingsViewModel.kt | 8 +++- .../java/com/topjohnwu/signing/JarMap.java | 8 ---- 4 files changed, 35 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt index b9b8fd7cb..eb5168504 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/download/ManagerHandler.kt @@ -2,7 +2,6 @@ package com.topjohnwu.magisk.core.download import android.content.Context import androidx.core.net.toFile -import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.R import com.topjohnwu.magisk.core.Info @@ -14,7 +13,7 @@ import java.io.File private fun Context.patch(apk: File) { val patched = File(apk.parent, "patched.apk") - HideAPK.patch(this, apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel) + HideAPK.patch(this, apk, patched, packageName, applicationInfo.nonLocalizedLabel) apk.delete() patched.renameTo(apk) } @@ -28,24 +27,21 @@ private fun BaseDownloader.notifyHide(id: Int) { } suspend fun BaseDownloader.handleAPK(subject: Subject.Manager) { + if (!isRunningAsStub) + return val apk = subject.file.toFile() val id = subject.notifyID() - if (isRunningAsStub) { - // Move to upgrade location - apk.copyTo(DynAPK.update(this), overwrite = true) - apk.delete() - if (Info.stub!!.version < subject.stub.versionCode) { - notifyHide(id) - // Also upgrade stub - service.fetchFile(subject.stub.link).byteStream().writeTo(apk) - patch(apk) - } else { - // Simply relaunch the app - stopSelf() - relaunchApp(this) - } - } else if (packageName != BuildConfig.APPLICATION_ID) { + // Move to upgrade location + apk.copyTo(DynAPK.update(this), overwrite = true) + apk.delete() + if (Info.stub!!.version < subject.stub.versionCode) { notifyHide(id) + // Also upgrade stub + service.fetchFile(subject.stub.link).byteStream().writeTo(apk) patch(apk) + } else { + // Simply relaunch the app + stopSelf() + relaunchApp(this) } } 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 ff68a48e3..a64f868c3 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 @@ -3,12 +3,14 @@ package com.topjohnwu.magisk.core.tasks import android.app.ProgressDialog import android.content.Context import android.content.Intent -import android.os.Build.VERSION.SDK_INT import android.widget.Toast import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.core.* +import com.topjohnwu.magisk.core.Config +import com.topjohnwu.magisk.core.Const +import com.topjohnwu.magisk.core.Info +import com.topjohnwu.magisk.core.Provider import com.topjohnwu.magisk.core.utils.AXML import com.topjohnwu.magisk.core.utils.Keygen import com.topjohnwu.magisk.data.repository.NetworkService @@ -67,11 +69,11 @@ object HideAPK { fun patch( context: Context, - apk: String, out: String, + apk: File, out: File, pkg: String, label: CharSequence ): Boolean { try { - val jar = JarMap.open(apk) + val jar = JarMap.open(apk, true) val je = jar.getJarEntry(ANDROID_MANIFEST) val xml = AXML(jar.getRawData(je)) @@ -91,17 +93,12 @@ object HideAPK { } private suspend fun patchAndHide(context: Context, label: String): Boolean { - val src = if (!isRunningAsStub && SDK_INT >= 28) { - val stub = File(context.cacheDir, "stub.apk") - try { - svc.fetchFile(Info.remote.stub.link).byteStream().writeTo(stub) - } catch (e: IOException) { - Timber.e(e) - return false - } - stub.path - } else { - context.packageCodePath + val stub = File(context.cacheDir, "stub.apk") + try { + svc.fetchFile(Info.remote.stub.link).byteStream().writeTo(stub) + } catch (e: IOException) { + Timber.e(e) + return false } // Generate a new random package name and signature @@ -109,7 +106,7 @@ object HideAPK { val pkg = genPackageName() Config.keyStoreRaw = "" - if (!patch(context, src, repack.path, pkg, label)) + if (!patch(context, stub, repack, pkg, label)) return false // Install the application @@ -142,20 +139,8 @@ object HideAPK { } } - private suspend fun downloadAndRestore(context: Context): Boolean { - val apk = if (isRunningAsStub) { - DynAPK.current(context) - } else { - File(context.cacheDir, "manager.apk").also { apk -> - try { - svc.fetchFile(Info.remote.magisk.link).byteStream().writeTo(apk) - } catch (e: IOException) { - Timber.e(e) - return false - } - } - } - + private fun restoreImpl(context: Context): Boolean { + val apk = DynAPK.current(context) if (!Shell.su("adb_pm_install $apk").exec().isSuccess) return false @@ -176,7 +161,7 @@ object HideAPK { val dialog = ProgressDialog.show(context, context.getString(R.string.restore_img_msg), "", true) GlobalScope.launch { val result = withContext(Dispatchers.IO) { - downloadAndRestore(context) + restoreImpl(context) } if (!result) { Utils.toast(R.string.restore_manager_fail_toast, Toast.LENGTH_LONG) diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt index c9ab17bcd..68f9d6274 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt @@ -59,8 +59,12 @@ class SettingsViewModel( )) if (Info.env.isActive) { list.add(ClearRepoCache) - if (Const.USER_ID == 0 && Info.isConnected.get()) - list.add(if (hidden) Restore else Hide) + if (Build.VERSION.SDK_INT >= 21 && Const.USER_ID == 0) { + if (hidden) + list.add(Restore) + else if (Info.isConnected.get()) + list.add(Hide) + } } // Magisk diff --git a/app/src/main/java/com/topjohnwu/signing/JarMap.java b/app/src/main/java/com/topjohnwu/signing/JarMap.java index 2524c5a0b..544f725ee 100644 --- a/app/src/main/java/com/topjohnwu/signing/JarMap.java +++ b/app/src/main/java/com/topjohnwu/signing/JarMap.java @@ -19,18 +19,10 @@ public abstract class JarMap implements Closeable { LinkedHashMap entryMap; - public static JarMap open(String file) throws IOException { - return new FileMap(new File(file), true, ZipFile.OPEN_READ); - } - public static JarMap open(File file, boolean verify) throws IOException { return new FileMap(file, verify, ZipFile.OPEN_READ); } - public static JarMap open(String file, boolean verify) throws IOException { - return new FileMap(new File(file), verify, ZipFile.OPEN_READ); - } - public static JarMap open(InputStream is, boolean verify) throws IOException { return new StreamMap(is, verify); }