diff options
| author | 2023-11-09 20:41:29 +0000 | |
|---|---|---|
| committer | 2023-11-09 20:41:29 +0000 | |
| commit | eb8140823f5fbfebcf7dd66f0d28df6b40a7ad13 (patch) | |
| tree | fee18d20067f4c02d40938f75d72de46deb3d50e | |
| parent | dc4b512ec4b7acb2e2cea5d471fe5779a3d36e57 (diff) | |
| parent | a0d4c585d3bf5aec7fc9ddb97ba0812162487f26 (diff) | |
Merge "Add option to limit what classes can have annotations" into main
15 files changed, 531 insertions, 35 deletions
diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING index 970362611f53..e02492d68bb4 100644 --- a/tools/hoststubgen/TEST_MAPPING +++ b/tools/hoststubgen/TEST_MAPPING @@ -1,6 +1,8 @@ { // TODO: Change to presubmit. "postsubmit": [ - { "name": "tiny-framework-dump-test" } + { "name": "tiny-framework-dump-test" }, + { "name": "hoststubgentest" }, + { "name": "hoststubgen-invoke-test" } ] } diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp index 182940e6f7c5..fd4ec8bd5931 100644 --- a/tools/hoststubgen/hoststubgen/Android.bp +++ b/tools/hoststubgen/hoststubgen/Android.bp @@ -99,6 +99,18 @@ java_binary_host { visibility: ["//visibility:public"], } +java_test_host { + name: "hoststubgentest", + // main_class: "com.android.hoststubgen.Main", + srcs: ["test/**/*.kt"], + static_libs: [ + "hoststubgen", + "truth", + ], + test_suites: ["general-tests"], + visibility: ["//visibility:private"], +} + // File that contains the standard command line argumetns to hoststubgen. // This is only for the prototype. The productionized version is "ravenwood-standard-options". filegroup { diff --git a/tools/hoststubgen/hoststubgen/invoketest/Android.bp b/tools/hoststubgen/hoststubgen/invoketest/Android.bp new file mode 100644 index 000000000000..7e90e421a1f9 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/invoketest/Android.bp @@ -0,0 +1,20 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +sh_test_host { + name: "hoststubgen-invoke-test", + src: "hoststubgen-invoke-test.sh", + test_suites: ["general-tests"], + + // Note: java_data: ["hoststubgen"] will only install the jar file, but not the command wrapper. + java_data: [ + "hoststubgen", + "hoststubgen-test-tiny-framework", + ], +} diff --git a/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh new file mode 100755 index 000000000000..34b2145b8d22 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/invoketest/hoststubgen-invoke-test.sh @@ -0,0 +1,163 @@ +#!/bin/bash +# Copyright (C) 2023 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. + +set -e # Exit when any command files + +# This script runs HostStubGen directly with various arguments and make sure +# the tool behaves in the expected way. + + +echo "# Listing files in the test environment" +ls -lR + +echo "# Dumping the environment variables" +env + +# Set up the constants and variables + +export TEMP=$TEST_TMPDIR + +JAR=hoststubgen-test-tiny-framework.jar +STUB=$TEMP/stub.jar +IMPL=$TEMP/impl.jar + +ANNOTATION_FILTER=$TEMP/annotation-filter.txt + +HOSTSTUBGEN_OUT=$TEMP/output.txt + +# Because of `set -e`, we can't return non-zero from functions, so we store +# HostStubGen result in it. +HOSTSTUBGEN_RC=0 + +# Define the functions to + + +# Note, because the build rule will only install hoststubgen.jar, but not the wrapper script, +# we need to execute it manually with the java command. +hoststubgen() { + java -jar ./hoststubgen.jar "$@" +} + +run_hoststubgen() { + local test_name="$1" + local annotation_filter="$2" + + echo "# Test: $test_name" + + rm -f $HOSTSTUBGEN_OUT + + local filter_arg="" + + if [[ "$annotation_filter" != "" ]] ; then + echo "$annotation_filter" > $ANNOTATION_FILTER + filter_arg="--annotation-allowed-classes-file $ANNOTATION_FILTER" + echo "=== filter ===" + cat $ANNOTATION_FILTER + fi + + hoststubgen \ + --debug \ + --in-jar $JAR \ + --out-stub-jar $STUB \ + --out-impl-jar $IMPL \ + $filter_arg \ + |& tee $HOSTSTUBGEN_OUT + HOSTSTUBGEN_RC=${PIPESTATUS[0]} + echo "HostStubGen exited with $HOSTSTUBGEN_RC" + return 0 +} + +run_hoststubgen_for_success() { + run_hoststubgen "$@" + + if (( $HOSTSTUBGEN_RC != 0 )) ; then + echo "HostStubGen expected to finish successfully, but failed with $rc" + return 1 + fi +} + +run_hoststubgen_for_failure() { + local test_name="$1" + local expected_error_message="$2" + shift 2 + + run_hoststubgen "$test_name" "$@" + + if (( $HOSTSTUBGEN_RC == 0 )) ; then + echo "HostStubGen expected to fail, but it didn't fail" + return 1 + fi + + # The output should contain the expected message. (note we se fgrep here.) + grep -Fq "$expected_error_message" $HOSTSTUBGEN_OUT +} + +# Start the tests... + +# Pass "" as a filter to _not_ add `--annotation-allowed-classes-file`. +run_hoststubgen_for_success "No annotation filter" "" + +# Now, we use " ", so we do add `--annotation-allowed-classes-file`. +run_hoststubgen_for_failure "No classes are allowed to have annotations" \ + "not allowed to have Ravenwood annotations" \ + " " + +run_hoststubgen_for_success "All classes allowed (wildcard)" \ + " +* # Allow all classes +" + +run_hoststubgen_for_failure "All classes disallowed (wildcard)" \ + "not allowed to have Ravenwood annotations" \ + " +!* # Disallow all classes +" + +run_hoststubgen_for_failure "Some classes not allowed (1)" \ + "not allowed to have Ravenwood annotations" \ + " +android.hosttest.* +com.android.hoststubgen.* +com.supported.* +" + +run_hoststubgen_for_failure "Some classes not allowed (2)" \ + "not allowed to have Ravenwood annotations" \ + " +android.hosttest.* +com.android.hoststubgen.* +com.unsupported.* +" + +run_hoststubgen_for_success "All classes allowed (package wildcard)" \ + " +android.hosttest.* +com.android.hoststubgen.* +com.supported.* +com.unsupported.* +" + + +run_hoststubgen_for_failure "One specific class disallowed" \ + "TinyFrameworkClassAnnotations is not allowed to have Ravenwood annotations" \ + " +!com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations +* # All other classes allowed +" + + + +echo "All tests passed" +exit 0
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt index 872d56856c33..f32dc721873e 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt @@ -27,6 +27,7 @@ import com.android.hoststubgen.filters.OutputFilter import com.android.hoststubgen.filters.StubIntersectingFilter import com.android.hoststubgen.filters.createFilterFromTextPolicyFile import com.android.hoststubgen.filters.printAsTextPolicy +import com.android.hoststubgen.utils.ClassFilter import com.android.hoststubgen.visitors.BaseAdapter import com.android.hoststubgen.visitors.PackageRedirectRemapper import org.objectweb.asm.ClassReader @@ -167,6 +168,14 @@ class HostStubGen(val options: HostStubGenOptions) { filter ) + val annotationAllowedClassesFilter = options.annotationAllowedClassesFile.let { filename -> + if (filename == null) { + ClassFilter.newNullFilter(true) // Allow all classes + } else { + ClassFilter.loadFromFile(filename, false) + } + } + // Next, Java annotation based filter. filter = AnnotationBasedFilter( errors, @@ -181,7 +190,8 @@ class HostStubGen(val options: HostStubGenOptions) { options.nativeSubstituteAnnotations, options.classLoadHookAnnotations, options.stubStaticInitializerAnnotations, - filter + annotationAllowedClassesFilter, + filter, ) // Next, "text based" filter, which allows to override polices without touching diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt index d74612d48de2..aab02b8de254 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt @@ -51,6 +51,8 @@ class HostStubGenOptions( var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(), + var annotationAllowedClassesFile: String? = null, + var defaultClassLoadHook: String? = null, var defaultMethodCallHook: String? = null, @@ -171,6 +173,9 @@ class HostStubGenOptions( "--package-redirect" -> ret.packageRedirects += parsePackageRedirect(ai.nextArgRequired(arg)) + "--annotation-allowed-classes-file" -> + ret.annotationAllowedClassesFile = ai.nextArgRequired(arg) + "--default-class-load-hook" -> ret.defaultClassLoadHook = ai.nextArgRequired(arg) @@ -314,6 +319,7 @@ class HostStubGenOptions( nativeSubstituteAnnotations=$nativeSubstituteAnnotations, classLoadHookAnnotations=$classLoadHookAnnotations, packageRedirects=$packageRedirects, + $annotationAllowedClassesFile=$annotationAllowedClassesFile, defaultClassLoadHook=$defaultClassLoadHook, defaultMethodCallHook=$defaultMethodCallHook, intersectStubJars=$intersectStubJars, diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt index f75062b3a878..937e56c2cbb5 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt @@ -58,4 +58,29 @@ fun <T> addNonNullElement(a: List<T>, b: T?): List<T> { return listOf(b) } return a + b -}
\ No newline at end of file +} + + +/** + * Exception for a parse error in a file + */ +class ParseException : Exception, UserErrorException { + val hasSourceInfo: Boolean + + constructor(message: String) : super(message) { + hasSourceInfo = false + } + + constructor(message: String, file: String, line: Int) : + super("$message in file $file line $line") { + hasSourceInfo = true + } + + fun withSourceInfo(filename: String, lineNo: Int): ParseException { + if (hasSourceInfo) { + return this // Already has source information. + } else { + return ParseException(this.message ?: "", filename, lineNo) + } + } +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt index 9f3ec4d2b450..9bb5381eef06 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt @@ -25,9 +25,11 @@ import com.android.hoststubgen.asm.CLASS_INITIALIZER_NAME import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.findAnnotationValueAsString import com.android.hoststubgen.asm.findAnyAnnotation +import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.asm.toHumanReadableMethodName import com.android.hoststubgen.asm.toJvmClassName import com.android.hoststubgen.log +import com.android.hoststubgen.utils.ClassFilter import org.objectweb.asm.tree.AnnotationNode import org.objectweb.asm.tree.ClassNode @@ -51,6 +53,7 @@ class AnnotationBasedFilter( nativeSubstituteAnnotations_: Set<String>, classLoadHookAnnotations_: Set<String>, stubStaticInitializerAnnotations_: Set<String>, + private val annotationAllowedClassesFilter: ClassFilter, fallback: OutputFilter, ) : DelegatingFilter(fallback) { private var stubAnnotations = convertToInternalNames(stubAnnotations_) @@ -62,7 +65,8 @@ class AnnotationBasedFilter( private var substituteAnnotations = convertToInternalNames(substituteAnnotations_) private var nativeSubstituteAnnotations = convertToInternalNames(nativeSubstituteAnnotations_) private var classLoadHookAnnotations = convertToInternalNames(classLoadHookAnnotations_) - private var stubStaticInitializerAnnotations = convertToInternalNames(stubStaticInitializerAnnotations_) + private var stubStaticInitializerAnnotations = + convertToInternalNames(stubStaticInitializerAnnotations_) /** Annotations that control API visibility. */ private var visibilityAnnotations: Set<String> = convertToInternalNames( @@ -135,15 +139,22 @@ class AnnotationBasedFilter( * name1 - 4 are only used in exception messages. */ private fun findAnnotation( - visibles: List<AnnotationNode>?, - invisibles: List<AnnotationNode>?, - type: String, - name1: String, - name2: String = "", - name3: String = "", + className: String, + visibles: List<AnnotationNode>?, + invisibles: List<AnnotationNode>?, + type: String, + name1: String, + name2: String = "", + name3: String = "", ): FilterPolicyWithReason? { detectInvalidAnnotations(visibles, invisibles, type, name1, name2, name3) + if (!annotationAllowedClassesFilter.matches(className)) { + throw InvalidAnnotationException( + "Class ${className.toHumanReadableClassName()} is not allowed to have " + + "Ravenwood annotations. Contact g/ravenwood for more details.") + } + findAnyAnnotation(stubAnnotations, visibles, invisibles)?.let { return FilterPolicy.Stub.withReason(reasonAnnotation) } @@ -170,6 +181,7 @@ class AnnotationBasedFilter( val cn = classes.getClass(className) findAnnotation( + cn.name, cn.visibleAnnotations, cn.invisibleAnnotations, "class", @@ -193,6 +205,7 @@ class AnnotationBasedFilter( cn.fields?.firstOrNull { it.name == fieldName }?.let {fn -> findAnnotation( + cn.name, fn.visibleAnnotations, fn.invisibleAnnotations, "field", @@ -229,6 +242,7 @@ class AnnotationBasedFilter( // If there's no substitution, then we check the annotation. findAnnotation( + cn.name, mn.visibleAnnotations, mn.invisibleAnnotations, "method", diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt index 46546e8b9491..416f08505867 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt @@ -15,7 +15,7 @@ */ package com.android.hoststubgen.filters -import com.android.hoststubgen.UserErrorException +import com.android.hoststubgen.ParseException import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.log import com.android.hoststubgen.normalizeTextLine @@ -46,30 +46,6 @@ private fun isVisible(access: Int): Boolean { return (access and (Opcodes.ACC_PUBLIC or Opcodes.ACC_PROTECTED)) != 0 } -/** - * Exception for a parse error. - */ -private class ParseException : Exception, UserErrorException { - val hasSourceInfo: Boolean - - constructor(message: String) : super(message) { - hasSourceInfo = false - } - - constructor(message: String, file: String, line: Int) : - super("$message in file $file line $line") { - hasSourceInfo = true - } - - fun withSourceInfo(filename: String, lineNo: Int): ParseException { - if (hasSourceInfo) { - return this // Already has source information. - } else { - return ParseException(this.message ?: "", filename, lineNo) - } - } -} - private const val FILTER_REASON = "file-override" /** diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt new file mode 100644 index 000000000000..01a7ab3eacfa --- /dev/null +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2023 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 + +import com.android.hoststubgen.ParseException +import com.android.hoststubgen.asm.toHumanReadableClassName +import com.android.hoststubgen.asm.toJvmClassName +import com.android.hoststubgen.normalizeTextLine +import java.io.File + +/** + * General purpose filter for class names. + */ +class ClassFilter private constructor ( + val defaultResult: Boolean, +) { + private data class FilterElement( + val allowed: Boolean, + val internalName: String, + val isPrefix: Boolean, + ) { + fun matches(classInternalName: String): Boolean { + if (isPrefix) { + return classInternalName.startsWith(internalName) + } else { + return classInternalName == internalName + } + } + } + + private val elements: MutableList<FilterElement> = mutableListOf() + + private val cache: MutableMap<String, Boolean> = mutableMapOf() + + /** + * Takes an internal class name (e.g. "com/android/hoststubgen/ClassName") and returns if + * matches the filter or not. + */ + fun matches(classInternalName: String): Boolean { + cache[classInternalName]?.let { + return it + } + + var result = defaultResult + run outer@{ + elements.forEach { e -> + if (e.matches(classInternalName)) { + result = e.allowed + return@outer // break equivalent. + } + } + } + cache[classInternalName] = result + + return result + } + + fun getCacheSizeForTest(): Int { + return cache.size + } + + companion object { + /** + * Return a filter that alawys returns true or false. + */ + fun newNullFilter(defaultResult: Boolean): ClassFilter { + return ClassFilter(defaultResult) + } + + /** Build a filter from a file. */ + fun loadFromFile(filename: String, defaultResult: Boolean): ClassFilter { + return buildFromString(File(filename).readText(), defaultResult, filename) + } + + /** Build a filter from a string (for unit tests). */ + fun buildFromString( + filterString: String, + defaultResult: Boolean, + filenameForErrorMessage: String + ): ClassFilter { + val ret = ClassFilter(defaultResult) + + var lineNo = 0 + filterString.split('\n').forEach { s -> + lineNo++ + + var line = normalizeTextLine(s) + + if (line.isEmpty()) { + return@forEach // skip empty lines. + } + + line = line.toHumanReadableClassName() // Convert all the slashes to periods. + + var allow = true + if (line.startsWith("!")) { + allow = false + line = line.substring(1).trimStart() + } + + // Special case -- matches any class names. + if (line == "*") { + ret.elements.add(FilterElement(allow, "", true)) + return@forEach + } + + // Handle wildcard -- e.g. "package.name.*" + if (line.endsWith(".*")) { + ret.elements.add(FilterElement( + allow, line.substring(0, line.length - 2).toJvmClassName(), true)) + return@forEach + } + + // Any other uses of "*" would be an error. + if (line.contains('*')) { + throw ParseException( + "Wildcard (*) can only show up as the last element", + filenameForErrorMessage, + lineNo + ) + } + ret.elements.add(FilterElement(allow, line.toJvmClassName(), false)) + } + + return ret + } + } +}
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp index 3dc6da348937..e7873d6eecc3 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/Android.bp @@ -16,6 +16,7 @@ java_library { static_libs: [ "hoststubgen-annotations", ], + visibility: ["//frameworks/base/tools/hoststubgen:__subpackages__"], } // Create stub/impl jars from "hoststubgen-test-tiny-framework", using the following 3 rules. @@ -30,6 +31,7 @@ java_genrule_host { ":hoststubgen-test-tiny-framework", "policy-override-tiny-framework.txt", ], + visibility: ["//visibility:private"], } java_genrule_host { @@ -41,6 +43,7 @@ java_genrule_host { out: [ "host_stub.jar", ], + visibility: ["//visibility:private"], } java_genrule_host { @@ -52,6 +55,7 @@ java_genrule_host { out: [ "host_impl.jar", ], + visibility: ["//visibility:private"], } // Same as "hoststubgen-test-tiny-framework-host", but with more options, to test more hoststubgen @@ -71,6 +75,7 @@ java_genrule_host { ":hoststubgen-test-tiny-framework", "policy-override-tiny-framework.txt", ], + visibility: ["//visibility:private"], } java_genrule_host { @@ -82,6 +87,7 @@ java_genrule_host { out: [ "host_stub.jar", ], + visibility: ["//visibility:private"], } java_genrule_host { @@ -93,6 +99,7 @@ java_genrule_host { out: [ "host_impl.jar", ], + visibility: ["//visibility:private"], } // Compile the test jar, using 2 rules. diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt new file mode 100644 index 000000000000..bd9e85e17890 --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/annotation-allowed-classes-tiny-framework.txt @@ -0,0 +1,29 @@ +# Only classes listed here can use the hoststubgen annotations. + +# For each class, we check each item in this file, and when a match is found, we +# either allow it if the line doesn't have a !, or disallow if the line has a !. +# All the lines after the matching line will be ignored. + + +# To allow a specific class to use annotations: +# com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations + +# To disallow a specific class to use annotations: +# !com.android.hoststubgen.test.tinyframework.TinyFrameworkClassAnnotations + +# To allow a specific package to use annotations: +# com.android.hoststubgen.test.* + +# To disallow a specific package to use annotations: +# !com.android.hoststubgen.test.* + + +com.android.hoststubgen.test.tinyframework.* +com.supported.* +com.unsupported.* + +# Use this to allow all packages +# * + +# Use this to allow all packages +# !*
\ No newline at end of file diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh index e212890592ff..872bbf878de4 100755 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/run-test-manually.sh @@ -93,6 +93,7 @@ run $HOSTSTUBGEN \ --gen-keep-all-file out/tiny-framework_keep_all.txt \ --gen-input-dump-file out/tiny-framework_dump.txt \ --package-redirect com.unsupported:com.supported \ + --annotation-allowed-classes-file annotation-allowed-classes-tiny-framework.txt \ $HOSTSTUBGEN_OPTS # Extract the jar files, so we can look into them. diff --git a/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt new file mode 100644 index 000000000000..f6515142ccdb --- /dev/null +++ b/tools/hoststubgen/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2023 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 + +import com.android.hoststubgen.ParseException +import com.google.common.truth.Truth.assertThat +import org.junit.Assert.fail +import org.junit.Test + +class ClassFilterTest { + @Test + fun testDefaultTrue() { + val f = ClassFilter.newNullFilter(true) + assertThat(f.matches("a/b/c")).isEqualTo(true) + } + + @Test + fun testDefaultFalse() { + val f = ClassFilter.newNullFilter(false) + assertThat(f.matches("a/b/c")).isEqualTo(false) + } + + @Test + fun testComplex1() { + val f = ClassFilter.buildFromString(""" + # ** this is a comment ** + a.b.c # allow + !a.b.d # disallow + * # allow all + """.trimIndent(), false, "X") + assertThat(f.getCacheSizeForTest()).isEqualTo(0) + + assertThat(f.matches("a/b/c")).isEqualTo(true) + assertThat(f.getCacheSizeForTest()).isEqualTo(1) + + assertThat(f.matches("a/b/d")).isEqualTo(false) + assertThat(f.matches("x")).isEqualTo(true) + + assertThat(f.getCacheSizeForTest()).isEqualTo(3) + + // Make sure the cache is working + assertThat(f.matches("x")).isEqualTo(true) + } + + @Test + fun testComplex2() { + val f = ClassFilter.buildFromString(""" + a.b.c # allow + !a.* # disallow everything else in package "a". + !d.e.f # disallow d.e.f. + + # everything else is allowed by default + """.trimIndent(), true, "X") + assertThat(f.matches("a/b/c")).isEqualTo(true) + assertThat(f.matches("a/x")).isEqualTo(false) + assertThat(f.matches("d/e/f")).isEqualTo(false) + assertThat(f.matches("d/e/f/g")).isEqualTo(true) + assertThat(f.matches("x")).isEqualTo(true) + } + + @Test + fun testBadFilter1() { + try { + ClassFilter.buildFromString(""" + a* + """.trimIndent(), true, "FILENAME") + fail("ParseException didn't happen") + } catch (e: ParseException) { + assertThat(e.message).contains("Wildcard") + assertThat(e.message).contains("FILENAME") + assertThat(e.message).contains("line 1") + } + } +}
\ No newline at end of file diff --git a/tools/hoststubgen/scripts/run-all-tests.sh b/tools/hoststubgen/scripts/run-all-tests.sh index ba1d404eba68..4afa2d7a659a 100755 --- a/tools/hoststubgen/scripts/run-all-tests.sh +++ b/tools/hoststubgen/scripts/run-all-tests.sh @@ -33,6 +33,9 @@ MUST_BUILD_MODULES=( # First, build all the test / etc modules. This shouldn't fail. run m "${MUST_BUILD_MODULES[@]}" +# Run the hoststubgen unittests / etc +run atest hoststubgentest hoststubgen-invoke-test + # Next, run the golden check. This should always pass too. # The following scripts _should_ pass too, but they depend on the internal paths to soong generated # files, and they may fail when something changes in the build system. |