diff --git a/java/base.go b/java/base.go index 717c7273f..ddabbc0c3 100644 --- a/java/base.go +++ b/java/base.go @@ -263,6 +263,9 @@ type DeviceProperties struct { // Only for libraries created by a sysprop_library module, SyspropPublicStub is the name of the // public stubs library. SyspropPublicStub string `blueprint:"mutated"` + + HiddenAPIPackageProperties + HiddenAPIFlagFileProperties } // Device properties that can be overridden by overriding module (e.g. override_android_app) @@ -563,6 +566,20 @@ func (j *Module) addHostAndDeviceProperties() { ) } +// provideHiddenAPIPropertyInfo populates a HiddenAPIPropertyInfo from hidden API properties and +// makes it available through the hiddenAPIPropertyInfoProvider. +func (j *Module) provideHiddenAPIPropertyInfo(ctx android.ModuleContext) { + hiddenAPIInfo := newHiddenAPIPropertyInfo() + + // Populate with flag file paths from the properties. + hiddenAPIInfo.extractFlagFilesFromProperties(ctx, &j.deviceProperties.HiddenAPIFlagFileProperties) + + // Populate with package rules from the properties. + hiddenAPIInfo.extractPackageRulesFromProperties(&j.deviceProperties.HiddenAPIPackageProperties) + + ctx.SetProvider(hiddenAPIPropertyInfoProvider, hiddenAPIInfo) +} + func (j *Module) OutputFiles(tag string) (android.Paths, error) { switch tag { case "": diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index 024c4fa50..c3053f88d 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -830,6 +830,8 @@ func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.Modul // Populate with package rules from the properties. input.extractPackageRulesFromProperties(&b.sourceOnlyProperties.HiddenAPIPackageProperties) + input.gatherPropertyInfo(ctx, contents) + // Add the stub dex jars from this module's fragment dependencies. input.DependencyStubDexJarsByScope.addStubDexJarsByModule(dependencyHiddenApiInfo.TransitiveStubDexJarsByScope) diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go index 83beb6d23..f95c83fe7 100644 --- a/java/bootclasspath_fragment_test.go +++ b/java/bootclasspath_fragment_test.go @@ -15,6 +15,7 @@ package java import ( + "strings" "testing" "android/soong/android" @@ -285,6 +286,119 @@ func TestBootclasspathFragment_StubLibs(t *testing.T) { android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope()) } +func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithBootclasspathFragment, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"), + FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"), + android.MockFS{ + "my-blocked.txt": nil, + "my-max-target-o-low-priority.txt": nil, + "my-max-target-p.txt": nil, + "my-max-target-q.txt": nil, + "my-max-target-r-low-priority.txt": nil, + "my-removed.txt": nil, + "my-unsupported-packages.txt": nil, + "my-unsupported.txt": nil, + "my-new-max-target-q.txt": nil, + }.AddToFixture(), + android.FixtureWithRootAndroidBp(` + bootclasspath_fragment { + name: "mybootclasspathfragment", + apex_available: ["myapex"], + contents: ["mybootlib", "mynewlibrary"], + hidden_api: { + unsupported: [ + "my-unsupported.txt", + ], + removed: [ + "my-removed.txt", + ], + max_target_r_low_priority: [ + "my-max-target-r-low-priority.txt", + ], + max_target_q: [ + "my-max-target-q.txt", + ], + max_target_p: [ + "my-max-target-p.txt", + ], + max_target_o_low_priority: [ + "my-max-target-o-low-priority.txt", + ], + blocked: [ + "my-blocked.txt", + ], + unsupported_packages: [ + "my-unsupported-packages.txt", + ], + split_packages: ["sdklibrary"], + package_prefixes: ["sdklibrary.all.mine"], + single_packages: ["sdklibrary.mine"], + }, + } + + java_library { + name: "mybootlib", + apex_available: ["myapex"], + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + min_sdk_version: "1", + compile_dex: true, + permitted_packages: ["mybootlib"], + } + + java_sdk_library { + name: "mynewlibrary", + apex_available: ["myapex"], + srcs: ["Test.java"], + min_sdk_version: "10", + compile_dex: true, + public: {enabled: true}, + permitted_packages: ["mysdklibrary"], + hidden_api: { + max_target_q: [ + "my-new-max-target-q.txt", + ], + split_packages: ["sdklibrary", "newlibrary"], + package_prefixes: ["newlibrary.all.mine"], + single_packages: ["newlibrary.mine"], + }, + } + `), + ).RunTest(t) + + // Make sure that the library exports hidden API properties for use by the bootclasspath_fragment. + library := result.Module("mynewlibrary", "android_common") + info := result.ModuleProvider(library, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo) + android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages) + android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes) + android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages) + for _, c := range HiddenAPIFlagFileCategories { + expectedMaxTargetQPaths := []string(nil) + if c.PropertyName == "max_target_q" { + expectedMaxTargetQPaths = []string{"my-new-max-target-q.txt"} + } + android.AssertPathsRelativeToTopEquals(t, c.PropertyName, expectedMaxTargetQPaths, info.FlagFilesByCategory[c]) + } + + // Make sure that the signature-patterns.csv is passed all the appropriate package properties + // from the bootclasspath_fragment and its contents. + fragment := result.ModuleForTests("mybootclasspathfragment", "android_common") + rule := fragment.Output("modular-hiddenapi/signature-patterns.csv") + expectedCommand := strings.Join([]string{ + "--split-package newlibrary", + "--split-package sdklibrary", + "--package-prefix newlibrary.all.mine", + "--package-prefix sdklibrary.all.mine", + "--single-package newlibrary.mine", + "--single-package sdklibrary", + }, " ") + android.AssertStringDoesContain(t, "signature patterns command", rule.RuleParams.Command, expectedCommand) +} + func TestBootclasspathFragment_Test(t *testing.T) { result := android.GroupFixturePreparers( prepareForTestWithBootclasspathFragment, diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 3a58675ec..7b678037c 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -440,7 +440,18 @@ var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{ }, } -var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ +type hiddenAPIFlagFileCategories []*hiddenAPIFlagFileCategory + +func (c hiddenAPIFlagFileCategories) byProperty(name string) *hiddenAPIFlagFileCategory { + for _, category := range c { + if category.PropertyName == name { + return category + } + } + panic(fmt.Errorf("no category exists with property name %q in %v", name, c)) +} + +var HiddenAPIFlagFileCategories = hiddenAPIFlagFileCategories{ // See HiddenAPIFlagFileProperties.Unsupported { PropertyName: "unsupported", @@ -517,13 +528,20 @@ var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ // FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category. type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths -// append appends the supplied flags files to the corresponding category in this map. +// append the supplied flags files to the corresponding category in this map. func (s FlagFilesByCategory) append(other FlagFilesByCategory) { for _, category := range HiddenAPIFlagFileCategories { s[category] = append(s[category], other[category]...) } } +// sort the paths for each category in this map. +func (s FlagFilesByCategory) sort() { + for category, value := range s { + s[category] = android.SortedUniquePaths(value) + } +} + // HiddenAPIInfo contains information provided by the hidden API processing. // // That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API @@ -706,6 +724,8 @@ type HiddenAPIPropertyInfo struct { SplitPackages []string } +var hiddenAPIPropertyInfoProvider = blueprint.NewProvider(HiddenAPIPropertyInfo{}) + // newHiddenAPIPropertyInfo creates a new initialized HiddenAPIPropertyInfo struct. func newHiddenAPIPropertyInfo() HiddenAPIPropertyInfo { return HiddenAPIPropertyInfo{ @@ -730,6 +750,24 @@ func (i *HiddenAPIPropertyInfo) extractPackageRulesFromProperties(p *HiddenAPIPa i.SplitPackages = p.Hidden_api.Split_packages } +func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.Module) { + for _, module := range contents { + if ctx.OtherModuleHasProvider(module, hiddenAPIPropertyInfoProvider) { + info := ctx.OtherModuleProvider(module, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo) + i.FlagFilesByCategory.append(info.FlagFilesByCategory) + i.PackagePrefixes = append(i.PackagePrefixes, info.PackagePrefixes...) + i.SinglePackages = append(i.SinglePackages, info.SinglePackages...) + i.SplitPackages = append(i.SplitPackages, info.SplitPackages...) + } + } + + // Dedup and sort the information to ensure consistent builds. + i.FlagFilesByCategory.sort() + i.PackagePrefixes = android.SortedUniqueStrings(i.PackagePrefixes) + i.SinglePackages = android.SortedUniqueStrings(i.SinglePackages) + i.SplitPackages = android.SortedUniqueStrings(i.SplitPackages) +} + // HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are // needed for hidden API flag generation. type HiddenAPIFlagInput struct { diff --git a/java/java.go b/java/java.go index 1e99aa32f..f98f1e88c 100644 --- a/java/java.go +++ b/java/java.go @@ -607,6 +607,9 @@ func setUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter, dexer } func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { + + j.provideHiddenAPIPropertyInfo(ctx) + j.sdkVersion = j.SdkVersion(ctx) j.minSdkVersion = j.MinSdkVersion(ctx) j.maxSdkVersion = j.MaxSdkVersion(ctx) diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index 13ddbe768..c93055a51 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -675,8 +675,8 @@ func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, java.PrepareForTestWithJavaSdkLibraryFiles, - java.FixtureWithLastReleaseApis("mysdklibrary"), - java.FixtureConfigureApexBootJars("myapex:mybootlib"), + java.FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"), + java.FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"), prepareForSdkTestWithApex, // Add a platform_bootclasspath that depends on the fragment. @@ -691,6 +691,7 @@ func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { "my-removed.txt": nil, "my-unsupported-packages.txt": nil, "my-unsupported.txt": nil, + "my-new-max-target-q.txt": nil, }.AddToFixture(), android.FixtureWithRootAndroidBp(` sdk { @@ -708,7 +709,7 @@ func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { bootclasspath_fragment { name: "mybootclasspathfragment", apex_available: ["myapex"], - contents: ["mybootlib"], + contents: ["mybootlib", "mynewlibrary"], api: { stub_libs: ["mysdklibrary"], }, @@ -737,7 +738,9 @@ func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { unsupported_packages: [ "my-unsupported-packages.txt", ], - split_packages: ["*"], + split_packages: ["sdklibrary"], + package_prefixes: ["sdklibrary.all.mine"], + single_packages: ["sdklibrary.mine"], }, } @@ -759,6 +762,24 @@ func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { public: {enabled: true}, permitted_packages: ["mysdklibrary"], } + + java_sdk_library { + name: "mynewlibrary", + apex_available: ["myapex"], + srcs: ["Test.java"], + min_sdk_version: "10", + compile_dex: true, + public: {enabled: true}, + permitted_packages: ["mysdklibrary"], + hidden_api: { + max_target_q: [ + "my-new-max-target-q.txt", + ], + split_packages: ["sdklibrary", "newlibrary"], + package_prefixes: ["newlibrary.all.mine"], + single_packages: ["newlibrary.mine"], + }, + } `), ).RunTest(t) @@ -774,7 +795,10 @@ prebuilt_bootclasspath_fragment { prefer: false, visibility: ["//visibility:public"], apex_available: ["myapex"], - contents: ["mybootlib"], + contents: [ + "mybootlib", + "mynewlibrary", + ], api: { stub_libs: ["mysdklibrary"], }, @@ -782,7 +806,10 @@ prebuilt_bootclasspath_fragment { unsupported: ["hiddenapi/my-unsupported.txt"], removed: ["hiddenapi/my-removed.txt"], max_target_r_low_priority: ["hiddenapi/my-max-target-r-low-priority.txt"], - max_target_q: ["hiddenapi/my-max-target-q.txt"], + max_target_q: [ + "hiddenapi/my-max-target-q.txt", + "hiddenapi/my-new-max-target-q.txt", + ], max_target_p: ["hiddenapi/my-max-target-p.txt"], max_target_o_low_priority: ["hiddenapi/my-max-target-o-low-priority.txt"], blocked: ["hiddenapi/my-blocked.txt"], @@ -805,6 +832,23 @@ java_import { permitted_packages: ["mybootlib"], } +java_sdk_library_import { + name: "mynewlibrary", + prefer: false, + visibility: ["//visibility:public"], + apex_available: ["myapex"], + shared_library: true, + compile_dex: true, + permitted_packages: ["mysdklibrary"], + public: { + jars: ["sdk_library/public/mynewlibrary-stubs.jar"], + stub_srcs: ["sdk_library/public/mynewlibrary_stub_sources"], + current_api: "sdk_library/public/mynewlibrary.txt", + removed_api: "sdk_library/public/mynewlibrary-removed.txt", + sdk_version: "current", + }, +} + java_sdk_library_import { name: "mysdklibrary", prefer: false, @@ -827,6 +871,7 @@ my-unsupported.txt -> hiddenapi/my-unsupported.txt my-removed.txt -> hiddenapi/my-removed.txt my-max-target-r-low-priority.txt -> hiddenapi/my-max-target-r-low-priority.txt my-max-target-q.txt -> hiddenapi/my-max-target-q.txt +my-new-max-target-q.txt -> hiddenapi/my-new-max-target-q.txt my-max-target-p.txt -> hiddenapi/my-max-target-p.txt my-max-target-o-low-priority.txt -> hiddenapi/my-max-target-o-low-priority.txt my-blocked.txt -> hiddenapi/my-blocked.txt @@ -838,6 +883,9 @@ my-unsupported-packages.txt -> hiddenapi/my-unsupported-packages.txt .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar +.intermediates/mynewlibrary.stubs/android_common/javac/mynewlibrary.stubs.jar -> sdk_library/public/mynewlibrary-stubs.jar +.intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_api.txt -> sdk_library/public/mynewlibrary.txt +.intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_removed.txt -> sdk_library/public/mynewlibrary-removed.txt .intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt .intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt