Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3f1ae0b5 authored by Paul Duffin's avatar Paul Duffin
Browse files

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
parent 1149c2c1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -267,6 +267,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)
@@ -564,6 +567,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 "":
+2 −0
Original line number Diff line number Diff line
@@ -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)

+114 −0
Original line number Diff line number Diff line
@@ -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,
+40 −2
Original line number Diff line number Diff line
@@ -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 {
+3 −0
Original line number Diff line number Diff line
@@ -629,6 +629,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)
Loading