diff --git a/android/singleton.go b/android/singleton.go index ccddeafd2..5f939967c 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -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)) diff --git a/android/visibility.go b/android/visibility.go index 79a534f56..89c0adc15 100644 --- a/android/visibility.go +++ b/android/visibility.go @@ -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 diff --git a/android/visibility_test.go b/android/visibility_test.go index bb43b1fa1..1a2eecafb 100644 --- a/android/visibility_test.go +++ b/android/visibility_test.go @@ -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 diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index 64a2e235f..efc889ccb 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -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 diff --git a/filesystem/system_image.go b/filesystem/system_image.go index 34f4ffb6d..78ce3770c 100644 --- a/filesystem/system_image.go +++ b/filesystem/system_image.go @@ -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}