Add hidden API properties to java_sdk_library modules
Previously, hidden API properties were only allowed on
bootclasspath_fragment and platform_bootclasspath module types. This
change allows them to be specified on java_sdk_library modules too. It
involves the following changes:
1. Add the properties to the java.Module.
2. Populate and provide a HiddenAPIPropertyInfo struct from
java_sdk_library modules.
3. Modify bootclasspath_fragment to merge information gathered from its
content libraries as if it was specified on the fragment itself.
Bug: 240406019
Test: m nothing
packages/modules/common/build/mainline_modules_sdks.sh
# Ran the previous command with and without this change to make
# sure that this change does not change the sdk snapshot
# contents.
Change-Id: I64eb71c2039ddc14cf380689d0cec7ec221f5b88
diff --git a/java/base.go b/java/base.go
index 94daf37..fe92b47 100644
--- a/java/base.go
+++ b/java/base.go
@@ -267,6 +267,9 @@
// 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)
@@ -564,6 +567,20 @@
)
}
+// 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 7580352..9316807 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -830,6 +830,8 @@
// 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 83beb6d..f95c83f 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 @@
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 3a58675..7b67803 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -440,7 +440,18 @@
},
}
-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 @@
// 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 @@
SplitPackages []string
}
+var hiddenAPIPropertyInfoProvider = blueprint.NewProvider(HiddenAPIPropertyInfo{})
+
// newHiddenAPIPropertyInfo creates a new initialized HiddenAPIPropertyInfo struct.
func newHiddenAPIPropertyInfo() HiddenAPIPropertyInfo {
return HiddenAPIPropertyInfo{
@@ -730,6 +750,24 @@
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 6b7ac75..210b883 100644
--- a/java/java.go
+++ b/java/java.go
@@ -629,6 +629,9 @@
}
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)