Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt 0 → 100644 +61 −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.toHumanReadableClassName import com.android.hoststubgen.utils.Trie /** * Filter to apply a policy to classes inside a package, either directly or indirectly. */ class PackageFilter( fallback: OutputFilter ) : DelegatingFilter(fallback) { private val mPackagePolicies = PackagePolicyTrie() // We want to pick the most specific filter for a package name. // Since any package with a matching prefix is a valid match, we can use a prefix tree // to help us find the nearest matching filter. private class PackagePolicyTrie : Trie<String, String, FilterPolicyWithReason>() { // Split package name into individual component override fun splitToComponents(key: String): Iterator<String> { return key.split('.').iterator() } } private fun getPackageKey(packageName: String): String { return packageName.toHumanReadableClassName() } private fun getPackageKeyFromClass(className: String): String { val clazz = className.toHumanReadableClassName() val idx = clazz.lastIndexOf('.') return if (idx >= 0) clazz.substring(0, idx) else "" } /** * Add a policy to all classes inside a package, either directly or indirectly. */ fun addPolicy(packageName: String, policy: FilterPolicyWithReason) { mPackagePolicies[getPackageKey(packageName)] = policy } override fun getPolicyForClass(className: String): FilterPolicyWithReason { return mPackagePolicies[getPackageKeyFromClass(className)] ?: super.getPolicyForClass(className) } } tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt +28 −5 Original line number Diff line number Diff line Loading @@ -64,7 +64,8 @@ fun createFilterFromTextPolicyFile( log.i("Loading offloaded annotations from $filename ...") log.withIndent { val subclassFilter = SubclassFilter(classes, fallback) val imf = InMemoryOutputFilter(classes, subclassFilter) val packageFilter = PackageFilter(subclassFilter) val imf = InMemoryOutputFilter(classes, packageFilter) var lineNo = 0 Loading @@ -78,10 +79,7 @@ fun createFilterFromTextPolicyFile( var className = "" while (true) { var line = reader.readLine() if (line == null) { break } var line = reader.readLine() ?: break lineNo++ line = normalizeTextLine(line) Loading @@ -95,6 +93,31 @@ fun createFilterFromTextPolicyFile( val fields = line.split(whitespaceRegex).toTypedArray() when (fields[0].lowercase()) { "p", "package" -> { if (fields.size < 3) { throw ParseException("Package ('p') expects 2 fields.") } val name = fields[1] val rawPolicy = fields[2] if (resolveExtendingClass(name) != null) { throw ParseException("Package can't be a super class type") } if (resolveSpecialClass(name) != SpecialClass.NotSpecial) { throw ParseException("Package can't be a special class type") } if (rawPolicy.startsWith("!")) { throw ParseException("Package can't have a substitution") } if (rawPolicy.startsWith("~")) { throw ParseException("Package can't have a class load hook") } val policy = parsePolicy(rawPolicy) if (!policy.isUsableWithClasses) { throw ParseException("Package can't have policy '$policy'") } packageFilter.addPolicy(name, policy.withReason(FILTER_REASON)) } "c", "class" -> { if (fields.size < 3) { throw ParseException("Class ('c') expects 2 fields.") Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt 0 → 100644 +58 −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.utils abstract class Trie<Key, Component, Value> { private val root = TrieNode<Component, Value>() abstract fun splitToComponents(key: Key): Iterator<Component> operator fun set(key: Key, value: Value) { val node = root.getExactNode(splitToComponents(key)) node.value = value } operator fun get(key: Key): Value? { return root.getNearestValue(null, splitToComponents(key)) } private class TrieNode<Component, Value> { private val children = mutableMapOf<Component, TrieNode<Component, Value>>() var value: Value? = null fun getExactNode(components: Iterator<Component>): TrieNode<Component, Value> { val n = components.next() val child = children.getOrPut(n) { TrieNode() } return if (components.hasNext()) { child.getExactNode(components) } else { child } } fun getNearestValue(current: Value?, components: Iterator<Component>): Value? { val n = components.next() val child = children[n] ?: return current val newValue = child.value ?: current return if (components.hasNext()) { child.getNearestValue(newValue, components) } else { newValue } } } } tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt +92 −0 Original line number Diff line number Diff line Loading @@ -2706,6 +2706,98 @@ SourceFile: "TinyFrameworkPackageRedirect.java" RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub ## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/A; } SourceFile: "A.java" ## Class: com/android/hoststubgen/test/tinyframework/packagetest/B.class Compiled from "B.java" public class com.android.hoststubgen.test.tinyframework.packagetest.B minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/B; } SourceFile: "B.java" ## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.sub.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/A; } SourceFile: "A.java" ## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/B.class Compiled from "B.java" public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.sub.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/B; } SourceFile: "B.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 Loading tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt +32 −0 Original line number Diff line number Diff line Loading @@ -2177,6 +2177,38 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub ## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 2 } SourceFile: "A.java" RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 2 } SourceFile: "A.java" RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 Loading Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt 0 → 100644 +61 −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.toHumanReadableClassName import com.android.hoststubgen.utils.Trie /** * Filter to apply a policy to classes inside a package, either directly or indirectly. */ class PackageFilter( fallback: OutputFilter ) : DelegatingFilter(fallback) { private val mPackagePolicies = PackagePolicyTrie() // We want to pick the most specific filter for a package name. // Since any package with a matching prefix is a valid match, we can use a prefix tree // to help us find the nearest matching filter. private class PackagePolicyTrie : Trie<String, String, FilterPolicyWithReason>() { // Split package name into individual component override fun splitToComponents(key: String): Iterator<String> { return key.split('.').iterator() } } private fun getPackageKey(packageName: String): String { return packageName.toHumanReadableClassName() } private fun getPackageKeyFromClass(className: String): String { val clazz = className.toHumanReadableClassName() val idx = clazz.lastIndexOf('.') return if (idx >= 0) clazz.substring(0, idx) else "" } /** * Add a policy to all classes inside a package, either directly or indirectly. */ fun addPolicy(packageName: String, policy: FilterPolicyWithReason) { mPackagePolicies[getPackageKey(packageName)] = policy } override fun getPolicyForClass(className: String): FilterPolicyWithReason { return mPackagePolicies[getPackageKeyFromClass(className)] ?: super.getPolicyForClass(className) } }
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt +28 −5 Original line number Diff line number Diff line Loading @@ -64,7 +64,8 @@ fun createFilterFromTextPolicyFile( log.i("Loading offloaded annotations from $filename ...") log.withIndent { val subclassFilter = SubclassFilter(classes, fallback) val imf = InMemoryOutputFilter(classes, subclassFilter) val packageFilter = PackageFilter(subclassFilter) val imf = InMemoryOutputFilter(classes, packageFilter) var lineNo = 0 Loading @@ -78,10 +79,7 @@ fun createFilterFromTextPolicyFile( var className = "" while (true) { var line = reader.readLine() if (line == null) { break } var line = reader.readLine() ?: break lineNo++ line = normalizeTextLine(line) Loading @@ -95,6 +93,31 @@ fun createFilterFromTextPolicyFile( val fields = line.split(whitespaceRegex).toTypedArray() when (fields[0].lowercase()) { "p", "package" -> { if (fields.size < 3) { throw ParseException("Package ('p') expects 2 fields.") } val name = fields[1] val rawPolicy = fields[2] if (resolveExtendingClass(name) != null) { throw ParseException("Package can't be a super class type") } if (resolveSpecialClass(name) != SpecialClass.NotSpecial) { throw ParseException("Package can't be a special class type") } if (rawPolicy.startsWith("!")) { throw ParseException("Package can't have a substitution") } if (rawPolicy.startsWith("~")) { throw ParseException("Package can't have a class load hook") } val policy = parsePolicy(rawPolicy) if (!policy.isUsableWithClasses) { throw ParseException("Package can't have policy '$policy'") } packageFilter.addPolicy(name, policy.withReason(FILTER_REASON)) } "c", "class" -> { if (fields.size < 3) { throw ParseException("Class ('c') expects 2 fields.") Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt 0 → 100644 +58 −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.utils abstract class Trie<Key, Component, Value> { private val root = TrieNode<Component, Value>() abstract fun splitToComponents(key: Key): Iterator<Component> operator fun set(key: Key, value: Value) { val node = root.getExactNode(splitToComponents(key)) node.value = value } operator fun get(key: Key): Value? { return root.getNearestValue(null, splitToComponents(key)) } private class TrieNode<Component, Value> { private val children = mutableMapOf<Component, TrieNode<Component, Value>>() var value: Value? = null fun getExactNode(components: Iterator<Component>): TrieNode<Component, Value> { val n = components.next() val child = children.getOrPut(n) { TrieNode() } return if (components.hasNext()) { child.getExactNode(components) } else { child } } fun getNearestValue(current: Value?, components: Iterator<Component>): Value? { val n = components.next() val child = children[n] ?: return current val newValue = child.value ?: current return if (components.hasNext()) { child.getNearestValue(newValue, components) } else { newValue } } } }
tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt +92 −0 Original line number Diff line number Diff line Loading @@ -2706,6 +2706,98 @@ SourceFile: "TinyFrameworkPackageRedirect.java" RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub ## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/A; } SourceFile: "A.java" ## Class: com/android/hoststubgen/test/tinyframework/packagetest/B.class Compiled from "B.java" public class com.android.hoststubgen.test.tinyframework.packagetest.B minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/B; } SourceFile: "B.java" ## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.sub.A(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/A; } SourceFile: "A.java" ## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/B.class Compiled from "B.java" public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/B super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 1 public com.android.hoststubgen.test.tinyframework.packagetest.sub.B(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 x: aload_0 x: invokespecial #x // Method java/lang/Object."<init>":()V x: return LineNumberTable: LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/B; } SourceFile: "B.java" ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 Loading
tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt +32 −0 Original line number Diff line number Diff line Loading @@ -2177,6 +2177,38 @@ RuntimeVisibleAnnotations: RuntimeInvisibleAnnotations: x: #x() android.hosttest.annotation.HostSideTestWholeClassStub ## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 2 } SourceFile: "A.java" RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class Compiled from "A.java" public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 0, attributes: 2 } SourceFile: "A.java" RuntimeVisibleAnnotations: x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInStub x: #x() com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl ## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class Compiled from "C1.java" public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 Loading