From f4502f8be80031bbf31817077821212c6c1925bb Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 29 Oct 2024 12:13:19 -0700 Subject: [PATCH] Add our own API desugaring Fix #8452 --- app/apk/build.gradle.kts | 11 +++ .../topjohnwu/magisk/core/utils/Desugar.java | 32 +++++++++ .../main/java/DesugarClassVisitorFactory.kt | 67 +++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 app/core/src/main/java/com/topjohnwu/magisk/core/utils/Desugar.java create mode 100644 buildSrc/src/main/java/DesugarClassVisitorFactory.kt diff --git a/app/apk/build.gradle.kts b/app/apk/build.gradle.kts index 6f3bc30db..280428f58 100644 --- a/app/apk/build.gradle.kts +++ b/app/apk/build.gradle.kts @@ -1,3 +1,6 @@ +import com.android.build.api.instrumentation.FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS +import com.android.build.api.instrumentation.InstrumentationScope + plugins { id("com.android.application") kotlin("android") @@ -46,6 +49,14 @@ android { compileOptions { isCoreLibraryDesugaringEnabled = true } + + androidComponents { + onVariants { + it.instrumentation.setAsmFramesComputationMode(COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS) + it.instrumentation.transformClassesWith( + DesugarClassVisitorFactory::class.java, InstrumentationScope.ALL) {} + } + } } dependencies { diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/utils/Desugar.java b/app/core/src/main/java/com/topjohnwu/magisk/core/utils/Desugar.java new file mode 100644 index 000000000..b36826863 --- /dev/null +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/utils/Desugar.java @@ -0,0 +1,32 @@ +package com.topjohnwu.magisk.core.utils; + +import android.os.Build; + +import java.nio.file.attribute.FileTime; +import java.util.zip.ZipEntry; + +public class Desugar { + public static FileTime getLastModifiedTime(ZipEntry entry) { + if (Build.VERSION.SDK_INT >= 26) { + return entry.getLastModifiedTime(); + } else { + return FileTime.fromMillis(entry.getTime()); + } + } + + public static FileTime getLastAccessTime(ZipEntry entry) { + if (Build.VERSION.SDK_INT >= 26) { + return entry.getLastAccessTime(); + } else { + return null; + } + } + + public static FileTime getCreationTime(ZipEntry entry) { + if (Build.VERSION.SDK_INT >= 26) { + return entry.getCreationTime(); + } else { + return null; + } + } +} diff --git a/buildSrc/src/main/java/DesugarClassVisitorFactory.kt b/buildSrc/src/main/java/DesugarClassVisitorFactory.kt new file mode 100644 index 000000000..d3fec6473 --- /dev/null +++ b/buildSrc/src/main/java/DesugarClassVisitorFactory.kt @@ -0,0 +1,67 @@ +import com.android.build.api.instrumentation.AsmClassVisitorFactory +import com.android.build.api.instrumentation.ClassContext +import com.android.build.api.instrumentation.ClassData +import com.android.build.api.instrumentation.InstrumentationParameters +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.MethodVisitor +import org.objectweb.asm.Opcodes +import org.objectweb.asm.Opcodes.ASM9 + +private const val DESUGAR_CLASS_NAME = "com/topjohnwu/magisk/core/utils/Desugar" +private const val ZIP_ENTRY_GET_TIME_DESC = "()Ljava/nio/file/attribute/FileTime;" +private const val DESUGAR_GET_TIME_DESC = "(Ljava/util/zip/ZipEntry;)Ljava/nio/file/attribute/FileTime;" + +abstract class DesugarClassVisitorFactory : AsmClassVisitorFactory { + override fun createClassVisitor( + classContext: ClassContext, + nextClassVisitor: ClassVisitor + ): ClassVisitor { + return DesugarClassVisitor(nextClassVisitor) + } + + override fun isInstrumentable(classData: ClassData) = true + + class DesugarClassVisitor(cv: ClassVisitor) : ClassVisitor(ASM9, cv) { + override fun visitMethod( + access: Int, + name: String?, + descriptor: String?, + signature: String?, + exceptions: Array? + ): MethodVisitor { + return DesugarMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions)) + } + } + + class DesugarMethodVisitor(mv: MethodVisitor?) : MethodVisitor(ASM9, mv) { + override fun visitMethodInsn( + opcode: Int, + owner: String, + name: String, + descriptor: String, + isInterface: Boolean + ) { + if (!process(name, descriptor)) { + super.visitMethodInsn(opcode, owner, name, descriptor, isInterface) + } + } + + private fun process(name: String, descriptor: String): Boolean { + if (descriptor != ZIP_ENTRY_GET_TIME_DESC) + return false + when (name) { + "getLastModifiedTime", "getLastAccessTime", "getCreationTime" -> { + mv.visitMethodInsn( + Opcodes.INVOKESTATIC, + DESUGAR_CLASS_NAME, + name, + DESUGAR_GET_TIME_DESC, + false + ) + } + else -> return false + } + return true + } + } +}