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

Commit 0fa7e444 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

[HostStubGen] Support method call redirection

Flag: EXEMPT host side test change only
Bug: 292141694
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh

Change-Id: I344d60dfdc2f1e66e45fe6c7d298993719a7b54a
parent d3c056bb
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -117,6 +117,14 @@ fun resolveClassNameWithDefaultPackage(className: String, defaultPackageName: St
    return "$defaultPackageName.$className"
}

fun splitWithLastPeriod(name: String): Pair<String, String>? {
    val pos = name.lastIndexOf('.')
    if (pos < 0) {
        return null
    }
    return Pair(name.substring(0, pos), name.substring(pos + 1))
}

fun String.toJvmClassName(): String {
    return this.replace('.', '/')
}
@@ -198,11 +206,11 @@ fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) {
/**
 * Given a method descriptor, insert an [argType] as the first argument to it.
 */
fun prependArgTypeToMethodDescriptor(methodDescriptor: String, argType: Type): String {
fun prependArgTypeToMethodDescriptor(methodDescriptor: String, classInternalName: String): String {
    val returnType = Type.getReturnType(methodDescriptor)
    val argTypes = Type.getArgumentTypes(methodDescriptor).toMutableList()

    argTypes.add(0, argType)
    argTypes.add(0, Type.getType("L" + classInternalName + ";"))

    return Type.getMethodDescriptor(returnType, *argTypes.toTypedArray())
}
+15 −0
Original line number Diff line number Diff line
@@ -91,4 +91,19 @@ abstract class DelegatingFilter(
    override fun remapType(className: String): String? {
        return fallback.remapType(className)
    }

    override fun hasAnyMethodCallReplace(): Boolean {
        return fallback.hasAnyMethodCallReplace()
    }

    override fun getMethodCallReplaceTo(
        callerClassName: String,
        callerMethodName: String,
        className: String,
        methodName: String,
        descriptor: String,
    ): MethodReplaceTarget? {
        return fallback.getMethodCallReplaceTo(
            callerClassName, callerMethodName, className, methodName, descriptor)
    }
}
+24 −1
Original line number Diff line number Diff line
@@ -97,4 +97,27 @@ abstract class OutputFilter {
    open fun remapType(className: String): String? {
        return null
    }

    data class MethodReplaceTarget(val className: String, val methodName: String)

    /**
     * Return if this filter may return non-null from [getMethodCallReplaceTo].
     * (Used for a small optimization)
     */
    open fun hasAnyMethodCallReplace(): Boolean {
        return false
    }

    /**
     * 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,
    ): MethodReplaceTarget? {
        return null
    }
}
+26 −2
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@ package com.android.hoststubgen.filters

import com.android.hoststubgen.ParseException
import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.splitWithLastPeriod
import com.android.hoststubgen.asm.toHumanReadableClassName
import com.android.hoststubgen.asm.toJvmClassName
import com.android.hoststubgen.log
import com.android.hoststubgen.normalizeTextLine
import com.android.hoststubgen.whitespaceRegex
@@ -75,6 +77,8 @@ fun createFilterFromTextPolicyFile(
        var syspropsPolicy: FilterPolicyWithReason? = null
        var rFilePolicy: FilterPolicyWithReason? = null
        val typeRenameSpec = mutableListOf<TextFilePolicyRemapperFilter.TypeRenameSpec>()
        val methodReplaceSpec =
            mutableListOf<TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec>()

        try {
            BufferedReader(FileReader(filename)).use { reader ->
@@ -249,10 +253,26 @@ fun createFilterFromTextPolicyFile(
                                        policy.getSubstitutionBasePolicy()
                                                .withReason(FILTER_REASON))

                                // Keep "from" -> "to" mapping.
                                val classAndMethod = splitWithLastPeriod(fromName)
                                if (classAndMethod != null) {
                                    // If the substitution target contains a ".", then
                                    // it's a method call redirect.
                                    methodReplaceSpec.add(
                                        TextFilePolicyMethodReplaceFilter.MethodCallReplaceSpec(
                                            className.toJvmClassName(),
                                            name,
                                            signature,
                                            classAndMethod.first.toJvmClassName(),
                                            classAndMethod.second,
                                        )
                                    )
                                } else {
                                    // It's an in-class replace.
                                    // ("@RavenwoodReplace" equivalent)
                                    imf.setRenameTo(className, fromName, signature, name)
                                }
                            }
                        }
                        "r", "rename" -> {
                            if (fields.size < 3) {
                                throw ParseException("Rename ('r') expects 2 fields.")
@@ -284,10 +304,14 @@ fun createFilterFromTextPolicyFile(
        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 ret
    }
}
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.hoststubgen.filters

import com.android.hoststubgen.asm.ClassNodes

/**
 * Filter used by TextFileFilterPolicyParser for "method call relacement".
 */
class TextFilePolicyMethodReplaceFilter(
    val spec: List<MethodCallReplaceSpec>,
    val classes: ClassNodes,
    val fallback: OutputFilter,
) : DelegatingFilter(fallback) {

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

    override fun hasAnyMethodCallReplace(): Boolean {
        return true
    }

    override fun getMethodCallReplaceTo(
        callerClassName: String,
        callerMethodName: String,
        className: String,
        methodName: String,
        descriptor: String,
    ): MethodReplaceTarget? {
        // Maybe use 'Tri' if we end up having too many replacements.
        spec.forEach {
            if (className == it.fromClass &&
                methodName == it.fromMethod &&
                descriptor == it.fromDescriptor
                ) {
                return MethodReplaceTarget(it.toClass, it.toMethod)
            }
        }
        return null
    }
}
Loading