Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +8 −9 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter import com.android.hoststubgen.filters.ConstantFilter import com.android.hoststubgen.filters.DefaultHookInjectingFilter import com.android.hoststubgen.filters.FilterPolicy import com.android.hoststubgen.filters.FilterRemapper import com.android.hoststubgen.filters.ImplicitOutputFilter import com.android.hoststubgen.filters.OutputFilter import com.android.hoststubgen.filters.StubIntersectingFilter Loading Loading @@ -75,7 +76,9 @@ class HostStubGen(val options: HostStubGenOptions) { } // Build the filters. val (filter, policyFileRemapper) = buildFilter(errors, allClasses, options) val filter = buildFilter(errors, allClasses, options) val filterRemapper = FilterRemapper(filter) // Transform the jar. convert( Loading @@ -87,7 +90,7 @@ class HostStubGen(val options: HostStubGenOptions) { allClasses, errors, stats, policyFileRemapper, filterRemapper, options.numShards.get, options.shard.get, ) Loading Loading @@ -117,7 +120,7 @@ class HostStubGen(val options: HostStubGenOptions) { errors: HostStubGenErrors, allClasses: ClassNodes, options: HostStubGenOptions, ): Pair<OutputFilter, Remapper?> { ): OutputFilter { // We build a "chain" of multiple filters here. // // The filters are build in from "inside", meaning the first filter created here is Loading Loading @@ -170,14 +173,10 @@ class HostStubGen(val options: HostStubGenOptions) { filter, ) var policyFileRemapper: Remapper? = null // Next, "text based" filter, which allows to override polices without touching // the target code. options.policyOverrideFile.ifSet { val (f, p) = createFilterFromTextPolicyFile(it, allClasses, filter) filter = f policyFileRemapper = p filter = createFilterFromTextPolicyFile(it, allClasses, filter) } // If `--intersect-stub-jar` is provided, load from these jar files too. Loading @@ -192,7 +191,7 @@ class HostStubGen(val options: HostStubGenOptions) { // Apply the implicit filter. filter = ImplicitOutputFilter(errors, allClasses, filter) return Pair(filter, policyFileRemapper) return filter } /** Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt +10 −2 Original line number Diff line number Diff line Loading @@ -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('.', '/') } Loading Loading @@ -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()) } Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt +19 −0 Original line number Diff line number Diff line Loading @@ -87,4 +87,23 @@ abstract class DelegatingFilter( ): List<String> { return fallback.getMethodCallHooks(className, methodName, descriptor) } 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) } } tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt 0 → 100644 +41 −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 org.objectweb.asm.commons.Remapper /** * A [Remapper] that uses [OutputFilter.remapType] */ class FilterRemapper(val filter: OutputFilter) : Remapper() { private val cache = mutableMapOf<String, String>() override fun mapType(typeInternalName: String?): String? { if (typeInternalName == null) { return null } cache[typeInternalName]?.let { return it } var mapped = filter.remapType(typeInternalName) ?: typeInternalName cache[typeInternalName] = mapped return mapped } // TODO Do we need to implement mapPackage(), etc too? } No newline at end of file tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt +32 −1 Original line number Diff line number Diff line Loading @@ -89,4 +89,35 @@ abstract class OutputFilter { List<String> { return emptyList() } /** * Take a class (internal) name. If the class needs to be renamed, return the new name. * This is used by [FilterRemapper]. */ 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 } } Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +8 −9 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter import com.android.hoststubgen.filters.ConstantFilter import com.android.hoststubgen.filters.DefaultHookInjectingFilter import com.android.hoststubgen.filters.FilterPolicy import com.android.hoststubgen.filters.FilterRemapper import com.android.hoststubgen.filters.ImplicitOutputFilter import com.android.hoststubgen.filters.OutputFilter import com.android.hoststubgen.filters.StubIntersectingFilter Loading Loading @@ -75,7 +76,9 @@ class HostStubGen(val options: HostStubGenOptions) { } // Build the filters. val (filter, policyFileRemapper) = buildFilter(errors, allClasses, options) val filter = buildFilter(errors, allClasses, options) val filterRemapper = FilterRemapper(filter) // Transform the jar. convert( Loading @@ -87,7 +90,7 @@ class HostStubGen(val options: HostStubGenOptions) { allClasses, errors, stats, policyFileRemapper, filterRemapper, options.numShards.get, options.shard.get, ) Loading Loading @@ -117,7 +120,7 @@ class HostStubGen(val options: HostStubGenOptions) { errors: HostStubGenErrors, allClasses: ClassNodes, options: HostStubGenOptions, ): Pair<OutputFilter, Remapper?> { ): OutputFilter { // We build a "chain" of multiple filters here. // // The filters are build in from "inside", meaning the first filter created here is Loading Loading @@ -170,14 +173,10 @@ class HostStubGen(val options: HostStubGenOptions) { filter, ) var policyFileRemapper: Remapper? = null // Next, "text based" filter, which allows to override polices without touching // the target code. options.policyOverrideFile.ifSet { val (f, p) = createFilterFromTextPolicyFile(it, allClasses, filter) filter = f policyFileRemapper = p filter = createFilterFromTextPolicyFile(it, allClasses, filter) } // If `--intersect-stub-jar` is provided, load from these jar files too. Loading @@ -192,7 +191,7 @@ class HostStubGen(val options: HostStubGenOptions) { // Apply the implicit filter. filter = ImplicitOutputFilter(errors, allClasses, filter) return Pair(filter, policyFileRemapper) return filter } /** Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt +10 −2 Original line number Diff line number Diff line Loading @@ -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('.', '/') } Loading Loading @@ -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()) } Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt +19 −0 Original line number Diff line number Diff line Loading @@ -87,4 +87,23 @@ abstract class DelegatingFilter( ): List<String> { return fallback.getMethodCallHooks(className, methodName, descriptor) } 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) } }
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt 0 → 100644 +41 −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 org.objectweb.asm.commons.Remapper /** * A [Remapper] that uses [OutputFilter.remapType] */ class FilterRemapper(val filter: OutputFilter) : Remapper() { private val cache = mutableMapOf<String, String>() override fun mapType(typeInternalName: String?): String? { if (typeInternalName == null) { return null } cache[typeInternalName]?.let { return it } var mapped = filter.remapType(typeInternalName) ?: typeInternalName cache[typeInternalName] = mapped return mapped } // TODO Do we need to implement mapPackage(), etc too? } No newline at end of file
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt +32 −1 Original line number Diff line number Diff line Loading @@ -89,4 +89,35 @@ abstract class OutputFilter { List<String> { return emptyList() } /** * Take a class (internal) name. If the class needs to be renamed, return the new name. * This is used by [FilterRemapper]. */ 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 } }