Merge "Reland: Pass jars with resources to R8"
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index eaee20d..3066c79 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -159,11 +159,12 @@
android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
}
- android.AssertPathsRelativeToTopEquals(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/stub-flags.csv"}, info.StubFlagsPaths)
android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/index.csv"}, info.IndexPaths)
- android.AssertPathsRelativeToTopEquals(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/all-flags.csv"}, info.AllFlagsPaths)
+
+ android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
+ android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/all-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
}
func TestPlatformBootclasspathDependencies(t *testing.T) {
diff --git a/cc/config/global.go b/cc/config/global.go
index 55e0d79..3daee38 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -46,7 +46,6 @@
"-O2",
"-g",
- "-fdebug-default-version=5",
"-fdebug-info-for-profiling",
"-fno-strict-aliasing",
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 107d34a..bb542c4 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -579,6 +579,14 @@
common := ctx.Module().(commonBootclasspathFragment)
output := common.produceHiddenAPIOutput(ctx, contents, input)
+ // If the source or prebuilts module does not provide a signature patterns file then generate one
+ // from the flags.
+ // TODO(b/192868581): Remove once the source and prebuilts provide a signature patterns file of
+ // their own.
+ if output.SignaturePatternsPath == nil {
+ output.SignaturePatternsPath = buildRuleSignaturePatternsFile(ctx, output.AllFlagsPath)
+ }
+
// Initialize a HiddenAPIInfo structure.
hiddenAPIInfo := HiddenAPIInfo{
// The monolithic hidden API processing needs access to the flag files that override the default
@@ -744,9 +752,6 @@
// Flag files by *hiddenAPIFlagFileCategory
Flag_files_by_category FlagFilesByCategory
- // The path to the generated stub-flags.csv file.
- Stub_flags_path android.OptionalPath
-
// The path to the generated annotation-flags.csv file.
Annotation_flags_path android.OptionalPath
@@ -756,6 +761,12 @@
// The path to the generated index.csv file.
Index_path android.OptionalPath
+ // The path to the generated signature-patterns.csv file.
+ Signature_patterns_path android.OptionalPath
+
+ // The path to the generated stub-flags.csv file.
+ Stub_flags_path android.OptionalPath
+
// The path to the generated all-flags.csv file.
All_flags_path android.OptionalPath
}
@@ -772,10 +783,12 @@
b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
// Copy all the generated file paths.
- b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
b.Annotation_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AnnotationFlagsPath)
b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath)
b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath)
+
+ b.Signature_patterns_path = android.OptionalPathForPath(hiddenAPIInfo.SignaturePatternsPath)
+ b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath)
// Copy stub_libs properties.
@@ -839,10 +852,11 @@
}
// Copy all the generated files, if available.
- copyOptionalPath(b.Stub_flags_path, "stub_flags")
copyOptionalPath(b.Annotation_flags_path, "annotation_flags")
copyOptionalPath(b.Metadata_path, "metadata")
copyOptionalPath(b.Index_path, "index")
+ copyOptionalPath(b.Signature_patterns_path, "signature_patterns")
+ copyOptionalPath(b.Stub_flags_path, "stub_flags")
copyOptionalPath(b.All_flags_path, "all_flags")
}
@@ -852,9 +866,6 @@
// specific properties.
type prebuiltBootclasspathFragmentProperties struct {
Hidden_api struct {
- // The path to the stub-flags.csv file created by the bootclasspath_fragment.
- Stub_flags *string `android:"path"`
-
// The path to the annotation-flags.csv file created by the bootclasspath_fragment.
Annotation_flags *string `android:"path"`
@@ -864,6 +875,12 @@
// The path to the index.csv file created by the bootclasspath_fragment.
Index *string `android:"path"`
+ // The path to the signature-patterns.csv file created by the bootclasspath_fragment.
+ Signature_patterns *string `android:"path"`
+
+ // The path to the stub-flags.csv file created by the bootclasspath_fragment.
+ Stub_flags *string `android:"path"`
+
// The path to the all-flags.csv file created by the bootclasspath_fragment.
All_flags *string `android:"path"`
}
@@ -892,6 +909,12 @@
// produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+ pathForOptionalSrc := func(src *string) android.Path {
+ if src == nil {
+ return nil
+ }
+ return android.PathForModuleSrc(ctx, *src)
+ }
pathForSrc := func(property string, src *string) android.Path {
if src == nil {
ctx.PropertyErrorf(property, "is required but was not specified")
@@ -906,11 +929,12 @@
output := HiddenAPIOutput{
HiddenAPIFlagOutput: HiddenAPIFlagOutput{
- AnnotationFlagsPath: pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
- MetadataPath: pathForSrc("hidden_api.metadata", module.prebuiltProperties.Hidden_api.Metadata),
- IndexPath: pathForSrc("hidden_api.index", module.prebuiltProperties.Hidden_api.Index),
- StubFlagsPath: pathForSrc("hidden_api.stub_flags", module.prebuiltProperties.Hidden_api.Stub_flags),
- AllFlagsPath: pathForSrc("hidden_api.all_flags", module.prebuiltProperties.Hidden_api.All_flags),
+ AnnotationFlagsPath: pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
+ MetadataPath: pathForSrc("hidden_api.metadata", module.prebuiltProperties.Hidden_api.Metadata),
+ IndexPath: pathForSrc("hidden_api.index", module.prebuiltProperties.Hidden_api.Index),
+ SignaturePatternsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Signature_patterns),
+ StubFlagsPath: pathForSrc("hidden_api.stub_flags", module.prebuiltProperties.Hidden_api.Stub_flags),
+ AllFlagsPath: pathForSrc("hidden_api.all_flags", module.prebuiltProperties.Hidden_api.All_flags),
},
EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 86ab825..8a06a99 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -297,7 +297,7 @@
//
// The rule is initialized but not built so that the caller can modify it and select an appropriate
// name.
-func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, moduleStubFlagsPaths android.Paths) {
+func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, stubFlagSubsets SignatureCsvSubsets) {
// Singleton rule which applies hiddenapi on all boot class path dex files.
rule := android.NewRuleBuilder(pctx, ctx)
@@ -317,7 +317,7 @@
// If no module stub flags paths are provided then this must be being called for a
// bootclasspath_fragment and not the whole platform_bootclasspath.
- if moduleStubFlagsPaths == nil {
+ if stubFlagSubsets == nil {
// This is being run on a fragment of the bootclasspath.
command.Flag("--fragment")
}
@@ -342,8 +342,8 @@
// If there are stub flag files that have been generated by fragments on which this depends then
// use them to validate the stub flag file generated by the rules created by this method.
- if len(moduleStubFlagsPaths) > 0 {
- validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, moduleStubFlagsPaths)
+ if len(stubFlagSubsets) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets)
// Add the file that indicates that the file generated by this is valid.
//
@@ -546,6 +546,20 @@
}
}
+// StubFlagSubset returns a SignatureCsvSubset that contains a path to a stub-flags.csv file and a
+// path to a signature-patterns.csv file that defines a subset of the monolithic stub flags file,
+// i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
+func (i *HiddenAPIInfo) StubFlagSubset() SignatureCsvSubset {
+ return SignatureCsvSubset{i.StubFlagsPath, i.SignaturePatternsPath}
+}
+
+// FlagSubset returns a SignatureCsvSubset that contains a path to an all-flags.csv file and a
+// path to a signature-patterns.csv file that defines a subset of the monolithic flags file, i.e.
+// out/soong/hiddenapi/hiddenapi-flags.csv, against which it will be compared.
+func (i *HiddenAPIInfo) FlagSubset() SignatureCsvSubset {
+ return SignatureCsvSubset{i.AllFlagsPath, i.SignaturePatternsPath}
+}
+
var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
// ModuleStubDexJars contains the stub dex jars provided by a single module.
@@ -782,6 +796,10 @@
// The path to the generated all-flags.csv file.
AllFlagsPath android.Path
+
+ // The path to the generated signature-patterns.txt file which defines the subset of the
+ // monolithic hidden API files provided in this.
+ SignaturePatternsPath android.Path
}
// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
@@ -848,7 +866,7 @@
// the annotationFlags.
func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
- flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
+ flagFilesByCategory FlagFilesByCategory, flagSubsets SignatureCsvSubsets, generatedRemovedDexSignatures android.OptionalPath) {
// Create the rule that will generate the flag files.
tempPath := tempPathForRestat(ctx, outputPath)
@@ -877,8 +895,8 @@
// If there are flag files that have been generated by fragments on which this depends then use
// them to validate the flag file generated by the rules created by this method.
- if len(allFlagsPaths) > 0 {
- validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, allFlagsPaths)
+ if len(flagSubsets) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets)
// Add the file that indicates that the file generated by this is valid.
//
@@ -890,20 +908,66 @@
rule.Build(name, desc)
}
+// SignatureCsvSubset describes a subset of a monolithic flags file, i.e. either
+// out/soong/hiddenapi/hiddenapi-stub-flags.txt or out/soong/hiddenapi/hiddenapi-flags.csv
+type SignatureCsvSubset struct {
+ // The path to the CSV file containing hidden API flags.
+ //
+ // It has the dex member signature as the first column, with flags, one per column, in the
+ // subsequent columns.
+ CsvFile android.Path
+
+ // The path to the CSV file containing the signature patterns.
+ //
+ // It is a single column CSV file with the column containing a signature pattern.
+ SignaturePatternsFile android.Path
+}
+
+type SignatureCsvSubsets []SignatureCsvSubset
+
+func (s SignatureCsvSubsets) RelativeToTop() []string {
+ result := []string{}
+ for _, subset := range s {
+ result = append(result, fmt.Sprintf("%s:%s", subset.CsvFile.RelativeToTop(), subset.SignaturePatternsFile.RelativeToTop()))
+ }
+ return result
+}
+
+// buildRuleSignaturePatternsFile creates a rule to generate a file containing the set of signature
+// patterns that will select a subset of the monolithic flags.
+func buildRuleSignaturePatternsFile(ctx android.ModuleContext, flagsPath android.Path) android.Path {
+ patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
+ // Create a rule to validate the output from the following rule.
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("signature_patterns").
+ FlagWithInput("--flags ", flagsPath).
+ FlagWithOutput("--output ", patternsFile)
+ rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
+
+ return patternsFile
+}
+
// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
-func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, modularFilePaths android.Paths) android.WritablePath {
+func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets) android.WritablePath {
// The file which is used to record that the flags file is valid.
validFile := pathForValidation(ctx, monolithicFilePath)
// Create a rule to validate the output from the following rule.
rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
+ command := rule.Command().
BuiltTool("verify_overlaps").
- Input(monolithicFilePath).
- Inputs(modularFilePaths).
- // If validation passes then update the file that records that.
- Text("&& touch").Output(validFile)
+ Input(monolithicFilePath)
+
+ for _, subset := range csvSubsets {
+ command.
+ Textf("%s:%s", subset.CsvFile, subset.SignaturePatternsFile).
+ Implicit(subset.CsvFile).Implicit(subset.SignaturePatternsFile)
+ }
+
+ // If validation passes then update the file that records that.
+ command.Text("&& touch").Output(validFile)
rule.Build(name+"Validation", desc+" validation")
return validFile
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
index 404b4c1..5956e3c 100644
--- a/java/hiddenapi_monolithic.go
+++ b/java/hiddenapi_monolithic.go
@@ -29,9 +29,6 @@
// that category.
FlagsFilesByCategory FlagFilesByCategory
- // The paths to the generated stub-flags.csv files.
- StubFlagsPaths android.Paths
-
// The paths to the generated annotation-flags.csv files.
AnnotationFlagsPaths android.Paths
@@ -41,8 +38,13 @@
// The paths to the generated index.csv files.
IndexPaths android.Paths
- // The paths to the generated all-flags.csv files.
- AllFlagsPaths android.Paths
+ // The subsets of the monolithic hiddenapi-stubs-flags.txt file that are provided by each
+ // bootclasspath_fragment modules.
+ StubFlagSubsets SignatureCsvSubsets
+
+ // The subsets of the monolithic hiddenapi-flags.csv file that are provided by each
+ // bootclasspath_fragment modules.
+ FlagSubsets SignatureCsvSubsets
// The classes jars from the libraries on the platform bootclasspath.
ClassesJars android.Paths
@@ -80,11 +82,12 @@
// append appends all the files from the supplied info to the corresponding files in this struct.
func (i *MonolithicHiddenAPIInfo) append(other *HiddenAPIInfo) {
i.FlagsFilesByCategory.append(other.FlagFilesByCategory)
- i.StubFlagsPaths = append(i.StubFlagsPaths, other.StubFlagsPath)
i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPath)
i.MetadataPaths = append(i.MetadataPaths, other.MetadataPath)
i.IndexPaths = append(i.IndexPaths, other.IndexPath)
- i.AllFlagsPaths = append(i.AllFlagsPaths, other.AllFlagsPath)
+
+ i.StubFlagSubsets = append(i.StubFlagSubsets, other.StubFlagSubset())
+ i.FlagSubsets = append(i.FlagSubsets, other.FlagSubset())
}
var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 3ff4c77..36baf7e 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -316,7 +316,7 @@
// Generate the monolithic stub-flags.csv file.
stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
- buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagsPaths)
+ buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagSubsets)
// Generate the annotation-flags.csv file from all the module annotations.
annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv")
@@ -329,7 +329,7 @@
allAnnotationFlagFiles := android.Paths{annotationFlags}
allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...)
allFlags := hiddenAPISingletonPaths(ctx).flags
- buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.AllFlagsPaths, android.OptionalPath{})
+ buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.FlagSubsets, android.OptionalPath{})
// Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations
// in the source code.
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
index c50dc24..7ffda62 100644
--- a/scripts/hiddenapi/Android.bp
+++ b/scripts/hiddenapi/Android.bp
@@ -83,3 +83,60 @@
},
},
}
+
+python_test_host {
+ name: "verify_overlaps_test",
+ main: "verify_overlaps_test.py",
+ srcs: [
+ "verify_overlaps.py",
+ "verify_overlaps_test.py",
+ ],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ },
+ test_options: {
+ unit_test: true,
+ },
+}
+
+python_binary_host {
+ name: "signature_patterns",
+ main: "signature_patterns.py",
+ srcs: ["signature_patterns.py"],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ },
+}
+
+python_test_host {
+ name: "signature_patterns_test",
+ main: "signature_patterns_test.py",
+ srcs: [
+ "signature_patterns.py",
+ "signature_patterns_test.py",
+ ],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ },
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/scripts/hiddenapi/signature_patterns.py b/scripts/hiddenapi/signature_patterns.py
new file mode 100755
index 0000000..91328e6
--- /dev/null
+++ b/scripts/hiddenapi/signature_patterns.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2021 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.
+"""
+Generate a set of signature patterns from the modular flags generated by a
+bootclasspath_fragment that can be used to select a subset of monolithic flags
+against which the modular flags can be compared.
+"""
+
+import argparse
+import csv
+
+def dict_reader(input):
+ return csv.DictReader(input, delimiter=',', quotechar='|', fieldnames=['signature'])
+
+def produce_patterns_from_file(file):
+ with open(file, 'r') as f:
+ return produce_patterns_from_stream(f)
+
+def produce_patterns_from_stream(stream):
+ patterns = []
+ allFlagsReader = dict_reader(stream)
+ for row in allFlagsReader:
+ signature = row['signature']
+ patterns.append(signature)
+ return patterns
+
+def main(args):
+ args_parser = argparse.ArgumentParser(description='Generate a set of signature patterns that select a subset of monolithic hidden API files.')
+ args_parser.add_argument('--flags', help='The stub flags file which contains an entry for every dex member')
+ args_parser.add_argument('--output', help='Generated signature prefixes')
+ args = args_parser.parse_args(args)
+
+ # Read in all the patterns into a list.
+ patterns = produce_patterns_from_file(args.flags)
+
+ # Write out all the patterns.
+ with open(args.output, 'w') as outputFile:
+ for pattern in patterns:
+ outputFile.write(pattern)
+ outputFile.write("\n")
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/scripts/hiddenapi/signature_patterns_test.py b/scripts/hiddenapi/signature_patterns_test.py
new file mode 100755
index 0000000..83c9db2
--- /dev/null
+++ b/scripts/hiddenapi/signature_patterns_test.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2021 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.
+
+"""Unit tests for signature_patterns.py."""
+import io
+import unittest
+
+from signature_patterns import *
+
+class TestGeneratedPatterns(unittest.TestCase):
+
+ def produce_patterns_from_string(self, csv):
+ with io.StringIO(csv) as f:
+ return produce_patterns_from_stream(f)
+
+ def test_generate(self):
+ patterns = self.produce_patterns_from_string('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+''')
+ expected = [
+ "Ljava/lang/Object;->hashCode()I",
+ "Ljava/lang/Object;->toString()Ljava/lang/String;",
+ ]
+ self.assertEqual(expected, patterns)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/hiddenapi/verify_overlaps.py b/scripts/hiddenapi/verify_overlaps.py
index bb0917e..8579321 100755
--- a/scripts/hiddenapi/verify_overlaps.py
+++ b/scripts/hiddenapi/verify_overlaps.py
@@ -19,51 +19,123 @@
import argparse
import csv
-
-args_parser = argparse.ArgumentParser(description='Verify that one set of hidden API flags is a subset of another.')
-args_parser.add_argument('all', help='All the flags')
-args_parser.add_argument('subsets', nargs=argparse.REMAINDER, help='Subsets of the flags')
-args = args_parser.parse_args()
-
+from itertools import chain
def dict_reader(input):
return csv.DictReader(input, delimiter=',', quotechar='|', fieldnames=['signature'])
-# Read in all the flags into a dict indexed by signature
-allFlagsBySignature = {}
-with open(args.all, 'r') as allFlagsFile:
- allFlagsReader = dict_reader(allFlagsFile)
- for row in allFlagsReader:
+def extract_subset_from_monolithic_flags_as_dict_from_file(monolithicFlagsDict, patternsFile):
+ """
+ Extract a subset of flags from the dict containing all the monolithic flags.
+
+ :param monolithicFlagsDict: the dict containing all the monolithic flags.
+ :param patternsFile: a file containing a list of signature patterns that
+ define the subset.
+ :return: the dict from signature to row.
+ """
+ with open(patternsFile, 'r') as stream:
+ return extract_subset_from_monolithic_flags_as_dict_from_stream(monolithicFlagsDict, stream)
+
+def extract_subset_from_monolithic_flags_as_dict_from_stream(monolithicFlagsDict, stream):
+ """
+ Extract a subset of flags from the dict containing all the monolithic flags.
+
+ :param monolithicFlagsDict: the dict containing all the monolithic flags.
+ :param stream: a stream containing a list of signature patterns that define
+ the subset.
+ :return: the dict from signature to row.
+ """
+ dict = {}
+ for signature in stream:
+ signature = signature.rstrip()
+ dict[signature] = monolithicFlagsDict.get(signature, {})
+ return dict
+
+def read_signature_csv_from_stream_as_dict(stream):
+ """
+ Read the csv contents from the stream into a dict. The first column is assumed to be the
+ signature and used as the key. The whole row is stored as the value.
+
+ :param stream: the csv contents to read
+ :return: the dict from signature to row.
+ """
+ dict = {}
+ reader = dict_reader(stream)
+ for row in reader:
signature = row['signature']
- allFlagsBySignature[signature]=row
+ dict[signature] = row
+ return dict
-failed = False
-for subsetPath in args.subsets:
+def read_signature_csv_from_file_as_dict(csvFile):
+ """
+ Read the csvFile into a dict. The first column is assumed to be the
+ signature and used as the key. The whole row is stored as the value.
+
+ :param csvFile: the csv file to read
+ :return: the dict from signature to row.
+ """
+ with open(csvFile, 'r') as f:
+ return read_signature_csv_from_stream_as_dict(f)
+
+def compare_signature_flags(monolithicFlagsDict, modularFlagsDict):
+ """
+ Compare the signature flags between the two dicts.
+
+ :param monolithicFlagsDict: the dict containing the subset of the monolithic
+ flags that should be equal to the modular flags.
+ :param modularFlagsDict:the dict containing the flags produced by a single
+ bootclasspath_fragment module.
+ :return: list of mismatches., each mismatch is a tuple where the first item
+ is the signature, and the second and third items are lists of the flags from
+ modular dict, and monolithic dict respectively.
+ """
mismatchingSignatures = []
- with open(subsetPath, 'r') as subsetFlagsFile:
- subsetReader = dict_reader(subsetFlagsFile)
- for row in subsetReader:
- signature = row['signature']
- if signature in allFlagsBySignature:
- allFlags = allFlagsBySignature.get(signature)
- if allFlags != row:
- mismatchingSignatures.append((signature, row.get(None, []), allFlags.get(None, [])))
- else:
- mismatchingSignatures.append((signature, row.get(None, []), []))
+ # Create a sorted set of all the signatures from both the monolithic and
+ # modular dicts.
+ allSignatures = sorted(set(chain(monolithicFlagsDict.keys(), modularFlagsDict.keys())))
+ for signature in allSignatures:
+ monolithicRow = monolithicFlagsDict.get(signature, {})
+ monolithicFlags = monolithicRow.get(None, [])
+ modularRow = modularFlagsDict.get(signature, {})
+ modularFlags = modularRow.get(None, [])
+ if monolithicFlags != modularFlags:
+ mismatchingSignatures.append((signature, modularFlags, monolithicFlags))
+ return mismatchingSignatures
+def main(argv):
+ args_parser = argparse.ArgumentParser(description='Verify that sets of hidden API flags are each a subset of the monolithic flag file.')
+ args_parser.add_argument('monolithicFlags', help='The monolithic flag file')
+ args_parser.add_argument('modularFlags', nargs=argparse.REMAINDER, help='Flags produced by individual bootclasspath_fragment modules')
+ args = args_parser.parse_args(argv[1:])
- if mismatchingSignatures:
- failed = True
- print("ERROR: Hidden API flags are inconsistent:")
- print("< " + subsetPath)
- print("> " + args.all)
- for mismatch in mismatchingSignatures:
- print()
- print("< " + mismatch[0] + "," + ",".join(mismatch[1]))
- if mismatch[2] != []:
- print("> " + mismatch[0] + "," + ",".join(mismatch[2]))
- else:
- print("> " + mismatch[0] + " - missing")
+ # Read in the monolithic flags into a dict indexed by signature
+ monolithicFlagsPath = args.monolithicFlags
+ monolithicFlagsDict = read_signature_csv_from_file_as_dict(monolithicFlagsPath)
-if failed:
- sys.exit(1)
+ # For each subset specified on the command line, create dicts for the flags
+ # provided by the subset and the corresponding flags from the complete set of
+ # flags and compare them.
+ failed = False
+ for modularPair in args.modularFlags:
+ parts = modularPair.split(":")
+ modularFlagsPath = parts[0]
+ modularPatternsPath = parts[1]
+ modularFlagsDict = read_signature_csv_from_file_as_dict(modularFlagsPath)
+ monolithicFlagsSubsetDict = extract_subset_from_monolithic_flags_as_dict_from_file(monolithicFlagsDict, modularPatternsPath)
+ mismatchingSignatures = compare_signature_flags(monolithicFlagsSubsetDict, modularFlagsDict)
+ if mismatchingSignatures:
+ failed = True
+ print("ERROR: Hidden API flags are inconsistent:")
+ print("< " + modularFlagsPath)
+ print("> " + monolithicFlagsPath)
+ for mismatch in mismatchingSignatures:
+ signature = mismatch[0]
+ print()
+ print("< " + ",".join([signature]+ mismatch[1]))
+ print("> " + ",".join([signature]+ mismatch[2]))
+
+ if failed:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/scripts/hiddenapi/verify_overlaps_test.py b/scripts/hiddenapi/verify_overlaps_test.py
new file mode 100755
index 0000000..b6d5fa3
--- /dev/null
+++ b/scripts/hiddenapi/verify_overlaps_test.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2021 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.
+
+"""Unit tests for verify_overlaps_test.py."""
+import io
+import unittest
+
+from verify_overlaps import *
+
+class TestDetectOverlaps(unittest.TestCase):
+
+ def read_signature_csv_from_string_as_dict(self, csv):
+ with io.StringIO(csv) as f:
+ return read_signature_csv_from_stream_as_dict(f)
+
+ def extract_subset_from_monolithic_flags_as_dict_from_string(self, monolithic, patterns):
+ with io.StringIO(patterns) as f:
+ return extract_subset_from_monolithic_flags_as_dict_from_stream(monolithic, f)
+
+ extractInput = '''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+'''
+
+ def test_extract_subset(self):
+ monolithic = self.read_signature_csv_from_string_as_dict(TestDetectOverlaps.extractInput)
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+''')
+
+ patterns = 'Ljava/lang/Object;->hashCode()I'
+
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ expected = {
+ 'Ljava/lang/Object;->hashCode()I': {
+ None: ['public-api', 'system-api', 'test-api'],
+ 'signature': 'Ljava/lang/Object;->hashCode()I',
+ },
+ }
+ self.assertEqual(expected, subset)
+
+ def test_match(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = []
+ self.assertEqual(expected, mismatches)
+
+ def test_mismatch_overlapping_flags(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['public-api', 'system-api', 'test-api'],
+ ['public-api'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+
+ def test_mismatch_monolithic_blocked(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['public-api', 'system-api', 'test-api'],
+ ['blocked'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_mismatch_modular_blocked(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['blocked'],
+ ['public-api', 'system-api', 'test-api'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_missing_from_monolithic(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('')
+ modular = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
+''')
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->toString()Ljava/lang/String;',
+ ['public-api', 'system-api', 'test-api'],
+ [],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_missing_from_modular(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
+''')
+ modular = {}
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->hashCode()I',
+ [],
+ ['public-api', 'system-api', 'test-api'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+ def test_blocked_missing_from_modular(self):
+ monolithic = self.read_signature_csv_from_string_as_dict('''
+Ljava/lang/Object;->hashCode()I,blocked
+''')
+ modular = {}
+ mismatches = compare_signature_flags(monolithic, modular)
+ expected = [
+ (
+ 'Ljava/lang/Object;->hashCode()I',
+ [],
+ ['blocked'],
+ ),
+ ]
+ self.assertEqual(expected, mismatches)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index c7ad798..9166109 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -134,10 +134,11 @@
image_name: "art",
contents: ["mybootlib"],
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/stub-flags.csv",
all_flags: "hiddenapi/all-flags.csv",
},
}
@@ -161,10 +162,11 @@
image_name: "art",
contents: ["mysdk_mybootlib@current"],
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/stub-flags.csv",
all_flags: "hiddenapi/all-flags.csv",
},
}
@@ -185,10 +187,11 @@
}
`),
checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
`),
@@ -332,10 +335,11 @@
stub_libs: ["mycoreplatform"],
},
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/stub-flags.csv",
all_flags: "hiddenapi/all-flags.csv",
},
}
@@ -416,10 +420,11 @@
stub_libs: ["mysdk_mycoreplatform@current"],
},
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/stub-flags.csv",
all_flags: "hiddenapi/all-flags.csv",
},
}
@@ -494,10 +499,11 @@
}
`),
checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
.intermediates/myothersdklibrary.stubs/android_common/javac/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
@@ -538,8 +544,16 @@
rule = module.Output("updatable-bcp-packages.txt")
expectedContents := `'mybootlib\nmyothersdklibrary\n'`
android.AssertStringEquals(t, "updatable-bcp-packages.txt", expectedContents, rule.Args["content"])
+
+ rule = module.Output("out/soong/hiddenapi/hiddenapi-flags.csv.valid")
+ android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " snapshot/hiddenapi/all-flags.csv:snapshot/hiddenapi/signature-patterns.csv ")
}),
snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
+ snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
+ module := result.ModuleForTests("platform-bootclasspath", "android_common")
+ rule := module.Output("out/soong/hiddenapi/hiddenapi-flags.csv.valid")
+ android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/all-flags.csv:out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv ")
+ }),
snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
)
}
@@ -636,10 +650,11 @@
},
],
hidden_api: {
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/stub-flags.csv",
all_flags: "hiddenapi/all-flags.csv",
},
}
@@ -838,10 +853,11 @@
max_target_o_low_priority: ["hiddenapi/my-max-target-o-low-priority.txt"],
blocked: ["hiddenapi/my-blocked.txt"],
unsupported_packages: ["hiddenapi/my-unsupported-packages.txt"],
- stub_flags: "hiddenapi/stub-flags.csv",
annotation_flags: "hiddenapi/annotation-flags.csv",
metadata: "hiddenapi/metadata.csv",
index: "hiddenapi/index.csv",
+ signature_patterns: "hiddenapi/signature-patterns.csv",
+ stub_flags: "hiddenapi/stub-flags.csv",
all_flags: "hiddenapi/all-flags.csv",
},
}
@@ -881,10 +897,11 @@
my-max-target-o-low-priority.txt -> hiddenapi/my-max-target-o-low-priority.txt
my-blocked.txt -> hiddenapi/my-blocked.txt
my-unsupported-packages.txt -> hiddenapi/my-unsupported-packages.txt
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar