Merge "Add more specific partition visibility rules" into main

This commit is contained in:
Cole Faust
2024-03-20 21:50:26 +00:00
committed by Gerrit Code Review
5 changed files with 202 additions and 37 deletions

View File

@@ -251,7 +251,7 @@ func (s *singletonContextAdaptor) FinalModule(module Module) Module {
func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
// get module reference for visibility enforcement
qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), s.ModuleType(referer))
qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), referer)
modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
result := make([]Module, 0, len(modules))

View File

@@ -58,19 +58,14 @@ const (
var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
type visibilityModuleReference struct {
name qualifiedModuleName
isPartitionModule bool
name qualifiedModuleName
module Module
}
func createVisibilityModuleReference(name, dir, typ string) visibilityModuleReference {
isPartitionModule := false
switch typ {
case "android_filesystem", "android_system_image":
isPartitionModule = true
}
func createVisibilityModuleReference(name, dir string, module Module) visibilityModuleReference {
return visibilityModuleReference{
name: createQualifiedModuleName(name, dir),
isPartitionModule: isPartitionModule,
name: createQualifiedModuleName(name, dir),
module: module,
}
}
@@ -214,21 +209,37 @@ func (r privateRule) String() string {
return "//visibility:private"
}
var anyPartitionRegex = regexp.MustCompile("^any_(system|system_ext|vendor|product|data|odm)_partition$")
// visibilityRule for //visibility:any_partition
type anyPartitionRule struct{}
type anyPartitionRule struct {
partitionType string
}
var _ visibilityRule = anyPartitionRule{}
type PartitionTypeInterface interface {
PartitionType() string
}
func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
return m.isPartitionModule
if m2, ok := m.module.(PartitionTypeInterface); ok {
return m2.PartitionType() == r.partitionType
}
return false
}
func (r anyPartitionRule) String() string {
return "//visibility:any_partition"
return "//visibility:any_" + r.partitionType + "_partition"
}
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
type visibilityRulesForModule struct {
rule compositeRule
implicitPartitionRules compositeRule
}
// The map from qualifiedModuleName to visibilityRule.
func moduleToVisibilityRuleMap(config Config) *sync.Map {
return config.Once(visibilityRuleMap, func() interface{} {
@@ -304,9 +315,6 @@ func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility [
if pkg == "visibility" {
switch name {
case "private", "public":
case "any_partition":
// any_partition can be used with another visibility fields
continue
case "legacy_public":
ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
continue
@@ -314,6 +322,10 @@ func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility [
// This keyword does not create a rule so pretend it does not exist.
ruleCount -= 1
default:
if anyPartitionRegex.MatchString(name) {
// any_*_partition can be used with another visibility fields
continue
}
ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v)
continue
}
@@ -352,15 +364,20 @@ func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
// Parse the visibility rules that control access to the module and store them by id
// for use when enforcing the rules.
var rule compositeRule
primaryProperty := m.base().primaryVisibilityProperty
if primaryProperty != nil {
if visibility := primaryProperty.getStrings(); visibility != nil {
rule := parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
if rule != nil {
moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
}
rule = parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
}
}
ipr := implicitPartitionRules(ctx)
if rule != nil || ipr != nil {
moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, visibilityRulesForModule{
rule: rule,
implicitPartitionRules: ipr,
})
}
}
func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule {
@@ -392,8 +409,13 @@ func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility [
hasNonPrivateRule = false
// This does not actually create a rule so continue onto the next rule.
continue
case "any_partition":
r = anyPartitionRule{}
default:
match := anyPartitionRegex.FindStringSubmatch(name)
if match != nil {
r = anyPartitionRule{
partitionType: match[1],
}
}
}
} else {
switch name {
@@ -432,6 +454,22 @@ func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility [
return rules
}
func implicitPartitionRules(ctx BaseModuleContext) compositeRule {
var result compositeRule
if ctx.SocSpecific() {
result = append(result, anyPartitionRule{partitionType: "vendor"})
} else if ctx.ProductSpecific() {
result = append(result, anyPartitionRule{partitionType: "product"})
} else if ctx.Module().InstallInData() {
result = append(result, anyPartitionRule{partitionType: "data"})
} else if ctx.SystemExtSpecific() {
result = append(result, anyPartitionRule{partitionType: "system_ext"})
} else if ctx.DeviceSpecific() {
result = append(result, anyPartitionRule{partitionType: "odm"})
}
return result
}
func isAllowedFromOutsideVendor(pkg string, name string) bool {
if pkg == "vendor" {
return name == "__subpackages__"
@@ -470,7 +508,7 @@ func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, propert
}
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.ModuleType())
qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module())
// Visit all the dependencies making sure that this module has access to them all.
ctx.VisitDirectDeps(func(dep Module) {
@@ -505,10 +543,13 @@ var defaultVisibility = compositeRule{publicRule{}}
// which is currently //visibility:public.
func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
value, ok := moduleToVisibilityRule.Load(qualified)
value := visibilityRulesForModule{}
if valueRaw, ok := moduleToVisibilityRule.Load(qualified); ok {
value = valueRaw.(visibilityRulesForModule)
}
var rule compositeRule
if ok {
rule = value.(compositeRule)
if value.rule != nil {
rule = value.rule
} else {
rule = packageDefaultVisibility(moduleToVisibilityRule, qualified)
}
@@ -518,6 +559,20 @@ func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) comp
if rule == nil {
rule = defaultVisibility
}
// If a partition rule wasn't specified, add implicit partition visibility
// rules based on the partition properties like vendor: true.
foundPartitionRule := false
for _, r := range rule {
if _, ok := r.(anyPartitionRule); ok {
foundPartitionRule = true
break
}
}
if !foundPartitionRule {
rule = append(rule, value.implicitPartitionRules...)
}
return rule
}
@@ -531,7 +586,7 @@ func packageDefaultVisibility(moduleToVisibilityRule *sync.Map, moduleId qualifi
for {
value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
if ok {
return value.(compositeRule)
return value.(visibilityRulesForModule).rule
}
if packageQualifiedId.isRootPackage() {
@@ -605,7 +660,7 @@ func EffectiveVisibilityRules(ctx BaseModuleContext, module Module) VisibilityRu
rule := effectiveVisibilityRules(ctx.Config(), qualified)
currentModule := createVisibilityModuleReference(moduleName, dir, ctx.OtherModuleType(module))
currentModule := createVisibilityModuleReference(moduleName, dir, module)
// Modules are implicitly visible to other modules in the same package,
// without checking the visibility rules. Here we need to add that visibility

View File

@@ -1905,7 +1905,7 @@ var visibilityTests = []struct {
},
},
{
name: "any_partition visibility works",
name: "any_system_partition visibility works",
fs: MockFS{
"top/Android.bp": []byte(`
android_filesystem {
@@ -1916,12 +1916,12 @@ var visibilityTests = []struct {
package(default_visibility=["//visibility:private"])
mock_library {
name: "bar",
visibility: ["//visibility:any_partition"],
visibility: ["//visibility:any_system_partition"],
}`),
},
},
{
name: "any_partition visibility works with the other visibility",
name: "any_system_partition visibility works with the other visibility",
fs: MockFS{
"top/Android.bp": []byte(`
android_filesystem {
@@ -1935,13 +1935,13 @@ var visibilityTests = []struct {
name: "bar",
visibility: [
"//top2",
"//visibility:any_partition"
"//visibility:any_system_partition"
],
}`),
},
},
{
name: "any_partition visibility doesn't work for non-partitions",
name: "any_system_partition visibility doesn't work for non-partitions",
fs: MockFS{
"top/Android.bp": []byte(`
mock_library {
@@ -1951,11 +1951,77 @@ var visibilityTests = []struct {
"top/nested/Android.bp": []byte(`
mock_library {
name: "bar",
visibility: ["//visibility:any_partition"],
visibility: ["//visibility:any_system_partition"],
}`),
},
expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
},
{
name: "any_system_partition visibility doesn't work for vendor partitions",
fs: MockFS{
"top/Android.bp": []byte(`
android_filesystem {
name: "foo",
partition_type: "vendor",
deps: ["bar"],
}`),
"top/nested/Android.bp": []byte(`
package(default_visibility=["//visibility:private"])
mock_library {
name: "bar",
visibility: ["//visibility:any_system_partition"],
}`),
},
expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
},
{
name: "Vendor modules are visible to any vendor partition by default",
fs: MockFS{
"top/Android.bp": []byte(`
android_filesystem {
name: "foo",
partition_type: "vendor",
deps: ["bar"],
}`),
"top/nested/Android.bp": []byte(`
package(default_visibility=["//visibility:private"])
mock_library {
name: "bar",
vendor: true,
}`),
},
},
{
name: "Not visible to vendor partitions when using any_system_partiton, even if vendor: true",
fs: MockFS{
"top/Android.bp": []byte(`
android_filesystem {
name: "foo",
partition_type: "vendor",
deps: ["bar"],
}`),
"top/nested/Android.bp": []byte(`
package(default_visibility=["//visibility:private"])
mock_library {
name: "bar",
vendor: true,
visibility: ["//visibility:any_system_partition"],
}`),
},
expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
},
{
name: "unknown any_partition specs throw errors",
fs: MockFS{
"top/nested/Android.bp": []byte(`
package(default_visibility=["//visibility:private"])
mock_library {
name: "bar",
visibility: ["//visibility:any_unknown_partition"],
}`),
},
expectedErrors: []string{`unrecognized visibility rule "//visibility:any_unknown_partition"`},
},
}
func TestVisibility(t *testing.T) {
@@ -1977,8 +2043,7 @@ func TestVisibility(t *testing.T) {
ctx.RegisterModuleType("mock_library", newMockLibraryModule)
ctx.RegisterModuleType("mock_parent", newMockParentFactory)
ctx.RegisterModuleType("mock_defaults", defaultsFactory)
// For testing //visibility:any_partition. The module type doesn't matter, just that it's registered under the name "android_filesystem"
ctx.RegisterModuleType("android_filesystem", newMockLibraryModule)
ctx.RegisterModuleType("android_filesystem", newMockFilesystemModule)
}),
prepareForTestWithFakePrebuiltModules,
// Add additional files to the mock filesystem
@@ -2032,6 +2097,37 @@ func (j *mockLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
type mockFilesystemModuleProperties struct {
Partition_type *string
Deps []string
}
type mockFilesystemModule struct {
ModuleBase
properties mockFilesystemModuleProperties
}
func (j *mockFilesystemModule) DepsMutator(ctx BottomUpMutatorContext) {
ctx.AddVariationDependencies(nil, dependencyTag{name: "mockdeps"}, j.properties.Deps...)
}
func (p *mockFilesystemModule) GenerateAndroidBuildActions(ModuleContext) {
}
func (p *mockFilesystemModule) PartitionType() string {
if p.properties.Partition_type == nil {
return "system"
}
return *p.properties.Partition_type
}
func newMockFilesystemModule() Module {
m := &mockFilesystemModule{}
m.AddProperties(&m.properties)
InitAndroidArchModule(m, DeviceSupported, MultilibCommon)
return m
}
type mockDefaults struct {
ModuleBase
DefaultsModuleBase

View File

@@ -88,6 +88,10 @@ type filesystemProperties struct {
// is ext4.
Type *string
// Identifies which partition this is for //visibility:any_system_image (and others) visibility
// checks, and will be used in the future for API surface checks.
Partition_type *string
// file_contexts file to make image. Currently, only ext4 is supported.
File_contexts *string `android:"path"`
@@ -175,6 +179,9 @@ func (f *filesystem) installFileName() string {
var pctx = android.NewPackageContext("android/soong/filesystem")
func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if !android.InList(f.PartitionType(), validPartitions) {
ctx.PropertyErrorf("partition_type", "partition_type must be one of %s, found: %s", validPartitions, f.PartitionType())
}
switch f.fsType(ctx) {
case ext4Type:
f.output = f.buildImageUsingBuildImage(ctx)
@@ -441,6 +448,10 @@ func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *andro
Text(android.PathForArbitraryOutput(ctx, stagingDir).String())
}
func (f *filesystem) PartitionType() string {
return proptools.StringDefault(f.properties.Partition_type, "system")
}
var _ android.AndroidMkEntriesProvider = (*filesystem)(nil)
// Implements android.AndroidMkEntriesProvider

View File

@@ -43,6 +43,9 @@ func systemImageFactory() android.Module {
}
func (s *systemImage) buildExtraFiles(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths {
if s.filesystem.properties.Partition_type != nil {
ctx.PropertyErrorf("partition_type", "partition_type must be unset on an android_system_image module. It is assumed to be 'system'.")
}
lc := s.buildLinkerConfigFile(ctx, root)
// Add more files if needed
return []android.OutputPath{lc}