diff --git a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt index 4efcfc1..f94376d 100644 --- a/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt +++ b/app/src/main/kotlin/com/aliucord/manager/patcher/steps/install/AlignmentStep.kt @@ -2,6 +2,7 @@ package com.aliucord.manager.patcher.steps.install import android.os.Build import com.aliucord.manager.R +import com.aliucord.manager.manager.PathManager import com.aliucord.manager.patcher.StepRunner import com.aliucord.manager.patcher.steps.StepGroup import com.aliucord.manager.patcher.steps.base.Step @@ -9,29 +10,69 @@ import com.aliucord.manager.patcher.steps.base.StepState import com.aliucord.manager.patcher.steps.download.CopyDependenciesStep import com.github.diamondminer88.zip.* import org.koin.core.component.KoinComponent +import org.koin.core.component.inject /** - * Align certain files in the APK to a 4KiB boundary. + * Align certain files in the APK to the respective boundaries. */ class AlignmentStep : Step(), KoinComponent { + private val paths: PathManager by inject() + override val group = StepGroup.Install override val localizedName = R.string.patch_step_alignment override suspend fun execute(container: StepRunner) { val apk = container.getStep().patchedApk + if (Build.VERSION.SDK_INT < 29) { + state = StepState.Skipped + return + } + + var resourcesArscBytes: ByteArray? = null + var dexCount: Int = -1 + // Align resources.arsc due to targeting API 30 for silent install if (Build.VERSION.SDK_INT >= 30) { - val bytes = ZipReader(apk) + resourcesArscBytes = ZipReader(apk) .use { it.openEntry("resources.arsc")?.read() } ?: throw IllegalArgumentException("APK is missing resources.arsc") + } - ZipWriter(apk, /* append = */ true).use { - it.deleteEntry("resources.arsc") - it.writeEntry("resources.arsc", bytes, ZipCompression.NONE, 4096) + // Align dex files due to using useEmbeddedDex (ref. ManifestPatcher) + if (Build.VERSION.SDK_INT >= 29) { + ZipReader(apk).use { zip -> + // Count the amount of dex files currently in the apk + dexCount = zip.entryNames.count { it.endsWith(".dex") } + + // Copy all the dex files that need to be moved out of the apk + for (idx in 0.. + // Delete all the unaligned files from APK + if (resourcesArscBytes != null) + zip.deleteEntry("resources.arsc") + + for (i in 0..= 29 && addUseEmbeddedDex) { + super.attr(ANDROID_NAMESPACE, USE_EMBEDDED_DEX, android.R.attr.useEmbeddedDex, TYPE_INT_BOOLEAN, 1) + } + // GrapheneOS also forces AOT, disable it in a worse way if below API 29 + else if (isGrapheneOS() && addVmSafeMode) { + super.attr(ANDROID_NAMESPACE, VM_SAFE_MODE, android.R.attr.vmSafeMode, TYPE_INT_BOOLEAN, 1) + } + super.end() } } diff --git a/app/src/main/kotlin/com/aliucord/manager/util/Utils.kt b/app/src/main/kotlin/com/aliucord/manager/util/Utils.kt index 70c98f0..d1f814b 100644 --- a/app/src/main/kotlin/com/aliucord/manager/util/Utils.kt +++ b/app/src/main/kotlin/com/aliucord/manager/util/Utils.kt @@ -76,6 +76,14 @@ fun isMiui(): Boolean { ?.isNotEmpty() ?: false } + +/** + * Checks whether this device is possibly running GrapheneOS. + */ +fun isGrapheneOS(): Boolean { + return Build.USER == "grapheneos" || Build.HOST == "grapheneos" +} + /** * Gets a system property from build.prop */