Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d68baf51 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[HostStubGen] Code cleanup" into main

parents 5c83d353 50418c15
Loading
Loading
Loading
Loading
+56 −20
Original line number Diff line number Diff line
@@ -30,12 +30,15 @@ import com.android.hoststubgen.filters.TextFileFilterPolicyBuilder
import com.android.hoststubgen.hosthelper.HostStubGenProcessedAsKeep
import com.android.hoststubgen.utils.ClassPredicate
import com.android.hoststubgen.visitors.BaseAdapter
import com.android.hoststubgen.visitors.ImplGeneratingAdapter
import com.android.hoststubgen.visitors.PackageRedirectRemapper
import java.io.PrintWriter
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.commons.ClassRemapper
import org.objectweb.asm.util.CheckClassAdapter
import org.objectweb.asm.util.TraceClassVisitor

/**
 * This class implements bytecode transformation of HostStubGen.
@@ -133,21 +136,10 @@ class HostStubGenClassProcessor(
        return filter
    }

    fun processClassBytecode(bytecode: ByteArray): ByteArray {
        val cr = ClassReader(bytecode)

        // If the class was already processed previously, skip
        val clz = allClasses.getClass(cr.className)
        if (clz.findAnyAnnotation(processedAnnotation) != null) {
            return bytecode
        }
    private fun buildVisitor(base: ClassVisitor, className: String): ClassVisitor {
        // Connect to the base visitor
        var outVisitor: ClassVisitor = base

        // COMPUTE_FRAMES wouldn't be happy if code uses
        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
        val cw = ClassWriter(flags)

        // Connect to the class writer
        var outVisitor: ClassVisitor = cw
        if (options.enableClassChecker.get) {
            outVisitor = CheckClassAdapter(outVisitor)
        }
@@ -158,15 +150,59 @@ class HostStubGenClassProcessor(
        val visitorOptions = BaseAdapter.Options(
            errors = errors,
            stats = stats,
            enablePreTrace = options.enablePreTrace.get,
            enablePostTrace = options.enablePostTrace.get,
            deleteClassFinals = options.deleteFinals.get,
            deleteMethodFinals = options.deleteFinals.get,
        )
        outVisitor = BaseAdapter.getVisitor(
            cr.className, allClasses, outVisitor, filter,
            packageRedirector, visitorOptions

        val verbosePrinter = PrintWriter(log.getWriter(LogLevel.Verbose))

        // Inject TraceClassVisitor for debugging.
        if (options.enablePostTrace.get) {
            outVisitor = TraceClassVisitor(outVisitor, verbosePrinter)
        }

        // Handle --package-redirect
        if (!packageRedirector.isEmpty) {
            // Don't apply the remapper on redirect-from classes.
            // Otherwise, if the target jar actually contains the "from" classes (which
            // may or may not be the case) they'd be renamed.
            // But we update all references in other places, so, a method call to a "from" class
            // would be replaced with the "to" class. All type references (e.g. variable types)
            // will be updated too.
            if (!packageRedirector.isTarget(className)) {
                outVisitor = ClassRemapper(outVisitor, packageRedirector)
            } else {
                log.v(
                    "Class $className is a redirect-from class, not applying" +
                            " --package-redirect"
                )
            }
        }

        outVisitor = ImplGeneratingAdapter(allClasses, outVisitor, filter, visitorOptions)

        // Inject TraceClassVisitor for debugging.
        if (options.enablePreTrace.get) {
            outVisitor = TraceClassVisitor(outVisitor, verbosePrinter)
        }

        return outVisitor
    }

    fun processClassBytecode(bytecode: ByteArray): ByteArray {
        val cr = ClassReader(bytecode)

        // If the class was already processed previously, skip
        val clz = allClasses.getClass(cr.className)
        if (clz.findAnyAnnotation(processedAnnotation) != null) {
            return bytecode
        }

        // COMPUTE_FRAMES wouldn't be happy if code uses
        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
        val cw = ClassWriter(flags)

        val outVisitor = buildVisitor(cw, cr.className)

        cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
        return cw.toByteArray()
+13 −14
Original line number Diff line number Diff line
@@ -97,13 +97,12 @@ abstract class DelegatingFilter(
    }

    override fun getMethodCallReplaceTo(
        callerClassName: String,
        callerMethodName: String,
        className: String,
        methodName: String,
        descriptor: String,
    ): MethodReplaceTarget? {
        return fallback.getMethodCallReplaceTo(
            callerClassName, callerMethodName, className, methodName, descriptor)
            className, methodName, descriptor
        )
    }
}
+64 −21
Original line number Diff line number Diff line
@@ -28,10 +28,12 @@ class InMemoryOutputFilter(
    private val classes: ClassNodes,
    fallback: OutputFilter,
) : DelegatingFilter(fallback) {
    private val mPolicies: MutableMap<String, FilterPolicyWithReason> = mutableMapOf()
    private val mRenames: MutableMap<String, String> = mutableMapOf()
    private val mRedirectionClasses: MutableMap<String, String> = mutableMapOf()
    private val mClassLoadHooks: MutableMap<String, String> = mutableMapOf()
    private val mPolicies = mutableMapOf<String, FilterPolicyWithReason>()
    private val mRenames = mutableMapOf<String, String>()
    private val mRedirectionClasses = mutableMapOf<String, String>()
    private val mClassLoadHooks = mutableMapOf<String, String>()
    private val mMethodCallReplaceSpecs = mutableListOf<MethodCallReplaceSpec>()
    private val mTypeRenameSpecs = mutableListOf<TypeRenameSpec>()

    private fun getClassKey(className: String): String {
        return className.toHumanReadableClassName()
@@ -45,10 +47,6 @@ class InMemoryOutputFilter(
        return getClassKey(className) + "." + methodName + ";" + signature
    }

    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
        return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className)
    }

    private fun checkClass(className: String) {
        if (classes.findClass(className) == null) {
            log.w("Unknown class $className")
@@ -74,6 +72,10 @@ class InMemoryOutputFilter(
        }
    }

    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
        return mPolicies[getClassKey(className)] ?: super.getPolicyForClass(className)
    }

    fun setPolicyForClass(className: String, policy: FilterPolicyWithReason) {
        checkClass(className)
        mPolicies[getClassKey(className)] = policy
@@ -135,11 +137,52 @@ class InMemoryOutputFilter(
    }

    override fun getClassLoadHooks(className: String): List<String> {
        return addNonNullElement(super.getClassLoadHooks(className),
            mClassLoadHooks[getClassKey(className)])
        return addNonNullElement(
            super.getClassLoadHooks(className),
            mClassLoadHooks[getClassKey(className)]
        )
    }

    fun setClassLoadHook(className: String, methodName: String) {
        mClassLoadHooks[getClassKey(className)] = methodName.toHumanReadableMethodName()
    }

    override fun hasAnyMethodCallReplace(): Boolean {
        return mMethodCallReplaceSpecs.isNotEmpty() || super.hasAnyMethodCallReplace()
    }

    override fun getMethodCallReplaceTo(
        className: String,
        methodName: String,
        descriptor: String,
    ): MethodReplaceTarget? {
        // Maybe use 'Tri' if we end up having too many replacements.
        mMethodCallReplaceSpecs.forEach {
            if (className == it.fromClass &&
                methodName == it.fromMethod
            ) {
                if (it.fromDescriptor == "*" || descriptor == it.fromDescriptor) {
                    return MethodReplaceTarget(it.toClass, it.toMethod)
                }
            }
        }
        return super.getMethodCallReplaceTo(className, methodName, descriptor)
    }

    fun setMethodCallReplaceSpec(spec: MethodCallReplaceSpec) {
        mMethodCallReplaceSpecs.add(spec)
    }

    override fun remapType(className: String): String? {
        mTypeRenameSpecs.forEach {
            if (it.typeInternalNamePattern.matcher(className).matches()) {
                return it.typeInternalNamePrefix + className
            }
        }
        return super.remapType(className)
    }

    fun setRemapTypeSpec(spec: TypeRenameSpec) {
        mTypeRenameSpecs.add(spec)
    }
}
+4 −6
Original line number Diff line number Diff line
@@ -108,8 +108,6 @@ abstract class OutputFilter {
     * If a method call should be forwarded to another method, return the target's class / method.
     */
    open fun getMethodCallReplaceTo(
        callerClassName: String,
        callerMethodName: String,
        className: String,
        methodName: String,
        descriptor: String,
+33 −34
Original line number Diff line number Diff line
@@ -58,6 +58,23 @@ enum class SpecialClass {
    RFile,
}

data class MethodCallReplaceSpec(
    val fromClass: String,
    val fromMethod: String,
    val fromDescriptor: String,
    val toClass: String,
    val toMethod: String,
)

/**
 * When a package name matches [typeInternalNamePattern], we prepend [typeInternalNamePrefix]
 * to it.
 */
data class TypeRenameSpec(
    val typeInternalNamePattern: Pattern,
    val typeInternalNamePrefix: String,
)

/**
 * This receives [TextFileFilterPolicyBuilder] parsing result.
 */
@@ -99,7 +116,7 @@ interface PolicyFileProcessor {
        className: String,
        methodName: String,
        methodDesc: String,
        replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec,
        replaceSpec: MethodCallReplaceSpec,
    )
}

@@ -116,9 +133,6 @@ class TextFileFilterPolicyBuilder(
    private var featureFlagsPolicy: FilterPolicyWithReason? = null
    private var syspropsPolicy: FilterPolicyWithReason? = null
    private var rFilePolicy: FilterPolicyWithReason? = null
    private val typeRenameSpec = mutableListOf<TextFilePolicyRemapperFilter.TypeRenameSpec>()
    private val methodReplaceSpec =
        mutableListOf<TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec>()

    /**
     * Fields for a filter chain used for "partial allowlisting", which are used by
@@ -126,17 +140,14 @@ class TextFileFilterPolicyBuilder(
     */
    private val annotationAllowedInMemoryFilter: InMemoryOutputFilter
    val annotationAllowedMembersFilter: OutputFilter
        get() = annotationAllowedInMemoryFilter

    private val annotationAllowedPolicy = FilterPolicy.AnnotationAllowed.withReason(FILTER_REASON)

    init {
        // Create a filter that checks "partial allowlisting".
        var aaf: OutputFilter = ConstantFilter(FilterPolicy.Remove, "default disallowed")

        aaf = InMemoryOutputFilter(classes, aaf)
        annotationAllowedInMemoryFilter = aaf

        annotationAllowedMembersFilter = annotationAllowedInMemoryFilter
        val filter = ConstantFilter(FilterPolicy.Remove, "default disallowed")
        annotationAllowedInMemoryFilter = InMemoryOutputFilter(classes, filter)
    }

    /**
@@ -153,20 +164,10 @@ class TextFileFilterPolicyBuilder(
     * Generate the resulting [OutputFilter].
     */
    fun createOutputFilter(): OutputFilter {
        var ret: OutputFilter = imf
        if (typeRenameSpec.isNotEmpty()) {
            ret = TextFilePolicyRemapperFilter(typeRenameSpec, ret)
        }
        if (methodReplaceSpec.isNotEmpty()) {
            ret = TextFilePolicyMethodReplaceFilter(methodReplaceSpec, classes, ret)
        }

        // Wrap the in-memory-filter with AHF.
        ret = AndroidHeuristicsFilter(
            classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, ret
        return AndroidHeuristicsFilter(
            classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, imf
        )

        return ret
    }

    private inner class Processor : PolicyFileProcessor {
@@ -180,9 +181,7 @@ class TextFileFilterPolicyBuilder(
        }

        override fun onRename(pattern: Pattern, prefix: String) {
            typeRenameSpec += TextFilePolicyRemapperFilter.TypeRenameSpec(
                pattern, prefix
            )
            imf.setRemapTypeSpec(TypeRenameSpec(pattern, prefix))
        }

        override fun onClassStart(className: String) {
@@ -284,12 +283,12 @@ class TextFileFilterPolicyBuilder(
            className: String,
            methodName: String,
            methodDesc: String,
            replaceSpec: TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec,
            replaceSpec: MethodCallReplaceSpec,
        ) {
            // Keep the source method, because the target method may call it.
            imf.setPolicyForMethod(className, methodName, methodDesc,
                FilterPolicy.Keep.withReason(FILTER_REASON))
            methodReplaceSpec.add(replaceSpec)
            imf.setMethodCallReplaceSpec(replaceSpec)
        }
    }
}
@@ -630,8 +629,8 @@ class TextFileFilterPolicyParser {
            if (classAndMethod != null) {
                // If the substitution target contains a ".", then
                // it's a method call redirect.
                val spec = TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec(
                        currentClassName!!.toJvmClassName(),
                val spec = MethodCallReplaceSpec(
                    className.toJvmClassName(),
                    methodName,
                    signature,
                    classAndMethod.first.toJvmClassName(),
Loading