feat: disable AOT with useEmbeddedDex
This is a better option than enabling `vmSafeMode` for all installs, since that appears to disable many optimizations and tanks performance. Possibly old GrapheneOS builds are the exception, which still need `vmSafeMode` to disable AOT since `useEmbeddedDex` doesn't exist on API <29.
This commit is contained in:
parent
5f1ab76842
commit
23ef31a4bd
4 changed files with 72 additions and 13 deletions
|
|
@ -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<CopyDependenciesStep>().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..<dexCount) {
|
||||
val bytes = zip.openEntry(getDexName(idx))!!.read()
|
||||
val file = paths.patchingWorkingDir().resolve(getDexName(idx))
|
||||
file.writeBytes(bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZipWriter(apk, /* append = */ true).use { zip ->
|
||||
// Delete all the unaligned files from APK
|
||||
if (resourcesArscBytes != null)
|
||||
zip.deleteEntry("resources.arsc")
|
||||
|
||||
for (i in 0..<dexCount)
|
||||
zip.deleteEntry(getDexName(i))
|
||||
|
||||
// Write all the files back aligned this time
|
||||
if (resourcesArscBytes != null)
|
||||
zip.writeEntry("resources.arsc", resourcesArscBytes, ZipCompression.NONE, 4)
|
||||
|
||||
for (idx in 0..<dexCount) {
|
||||
val file = paths.patchingWorkingDir().resolve(getDexName(idx))
|
||||
val bytes = file.readBytes()
|
||||
zip.writeEntry(getDexName(idx), bytes, ZipCompression.NONE, 4)
|
||||
}
|
||||
} else {
|
||||
state = StepState.Skipped
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDexName(idx: Int) = "classes${if (idx == 0) "" else (idx + 1)}.dex"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package com.aliucord.manager.patcher.steps.patch
|
||||
|
||||
import com.aliucord.manager.R
|
||||
|
|
@ -88,5 +86,5 @@ class ReorganizeDexStep : Step(), KoinComponent {
|
|||
}
|
||||
}
|
||||
|
||||
private inline fun getDexName(idx: Int) = "classes${if (idx == 0) "" else (idx + 1)}.dex"
|
||||
private fun getDexName(idx: Int) = "classes${if (idx == 0) "" else (idx + 1)}.dex"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ package com.aliucord.manager.patcher.util
|
|||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import com.aliucord.manager.util.isGrapheneOS
|
||||
import pxb.android.axml.*
|
||||
|
||||
object ManifestPatcher {
|
||||
private const val ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"
|
||||
private const val DEBUGGABLE = "debuggable"
|
||||
private const val VM_SAFE_MODE = "vmSafeMode"
|
||||
private const val USE_EMBEDDED_DEX = "useEmbeddedDex"
|
||||
private const val REQUEST_LEGACY_EXTERNAL_STORAGE = "requestLegacyExternalStorage"
|
||||
private const val NETWORK_SECURITY_CONFIG = "networkSecurityConfig"
|
||||
private const val LABEL = "label"
|
||||
|
|
@ -94,12 +96,14 @@ object ManifestPatcher {
|
|||
) {
|
||||
private var addDebuggable = debuggable
|
||||
private var addLegacyStorage = true
|
||||
private var useVmSafeMode = true
|
||||
private var addVmSafeMode = true
|
||||
private var addUseEmbeddedDex = true
|
||||
|
||||
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
|
||||
if (name == NETWORK_SECURITY_CONFIG) return
|
||||
if (name == REQUEST_LEGACY_EXTERNAL_STORAGE) addLegacyStorage = false
|
||||
if (name == VM_SAFE_MODE) useVmSafeMode = false
|
||||
if (name == VM_SAFE_MODE) addVmSafeMode = false
|
||||
if (name == USE_EMBEDDED_DEX) addUseEmbeddedDex = false
|
||||
if (name == DEBUGGABLE) addDebuggable = false
|
||||
super.attr(ns, name, resourceId, type, value)
|
||||
}
|
||||
|
|
@ -137,9 +141,17 @@ object ManifestPatcher {
|
|||
TYPE_INT_BOOLEAN,
|
||||
1
|
||||
)
|
||||
if (useVmSafeMode) super.attr(ANDROID_NAMESPACE, VM_SAFE_MODE, android.R.attr.vmSafeMode, TYPE_INT_BOOLEAN, 1)
|
||||
if (addDebuggable) super.attr(ANDROID_NAMESPACE, DEBUGGABLE, android.R.attr.debuggable, TYPE_INT_BOOLEAN, 1)
|
||||
|
||||
// Disable AOT (Necessary for AOSP Android 15)
|
||||
if (Build.VERSION.SDK_INT >= 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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue