Add defaults_visibility support

Bug: 130796911
Test: m nothing
Change-Id: I7b9462d3360be2bbeaf6ff38c5328f45ff5b5ebb
diff --git a/android/defaults.go b/android/defaults.go
index 2cfd77a..f489c02 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -68,11 +68,20 @@
 	module.AddProperties(module.defaults())
 }
 
+// The Defaults_visibility property.
+type DefaultsVisibilityProperties struct {
+
+	// Controls the visibility of the defaults module itself.
+	Defaults_visibility []string
+}
+
 type DefaultsModuleBase struct {
 	DefaultableModuleBase
 
 	// Container for defaults of the common properties
 	commonProperties commonProperties
+
+	defaultsVisibilityProperties DefaultsVisibilityProperties
 }
 
 // The common pattern for defaults modules is to register separate instances of
@@ -107,6 +116,9 @@
 
 	// Return the defaults common properties.
 	common() *commonProperties
+
+	// Return the defaults visibility properties.
+	defaultsVisibility() *DefaultsVisibilityProperties
 }
 
 func (d *DefaultsModuleBase) isDefaults() bool {
@@ -126,6 +138,10 @@
 	return &d.commonProperties
 }
 
+func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties {
+	return &d.defaultsVisibilityProperties
+}
+
 func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
 }
 
@@ -142,17 +158,19 @@
 
 	// Add properties that will not have defaults applied to them.
 	base := module.base()
-	module.AddProperties(&base.nameProperties)
+	defaultsVisibility := module.defaultsVisibility()
+	module.AddProperties(&base.nameProperties, defaultsVisibility)
 
-	// There is currently no way to control the visibility of a defaults module, i.e. there is no
-	// primary visibility property.
-	base.primaryVisibilityProperty = nil
+	// The defaults_visibility property controls the visibility of a defaults module.
+	base.primaryVisibilityProperty =
+		newVisibilityProperty("defaults_visibility", &defaultsVisibility.Defaults_visibility)
 
 	// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
 	// Instead it is stored in a separate instance of commonProperties created above so use that.
 	// The visibility property needs to be checked (but not parsed) by the visibility module during
 	// its checking phase and parsing phase.
 	base.visibilityPropertyInfo = []visibilityProperty{
+		base.primaryVisibilityProperty,
 		newVisibilityProperty("visibility", &commonProperties.Visibility),
 	}
 
diff --git a/android/module.go b/android/module.go
index 5bb1177..138b9cd 100644
--- a/android/module.go
+++ b/android/module.go
@@ -305,6 +305,11 @@
 	// If no `default_visibility` property can be found then the module uses the
 	// global default of `//visibility:legacy_public`.
 	//
+	// The `visibility` property has no effect on a defaults module although it does
+	// apply to any non-defaults module that uses it. To set the visibility of a
+	// defaults module, use the `defaults_visibility` property on the defaults module;
+	// not to be confused with the `default_visibility` property on the package module.
+	//
 	// See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for
 	// more details.
 	Visibility []string
diff --git a/android/visibility_test.go b/android/visibility_test.go
index af6acf4..c44dc9e 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -658,6 +658,40 @@
 				` visible to this module`,
 		},
 	},
+
+	// Defaults module's defaults_visibility tests
+	{
+		name: "defaults_visibility invalid",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				mock_defaults {
+					name: "top_defaults",
+					defaults_visibility: ["//visibility:invalid"],
+				}`),
+		},
+		expectedErrors: []string{
+			`defaults_visibility: unrecognized visibility rule "//visibility:invalid"`,
+		},
+	},
+	{
+		name: "defaults_visibility overrides package default",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:private"],
+				}
+				mock_defaults {
+					name: "top_defaults",
+					defaults_visibility: ["//visibility:public"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					defaults: ["top_defaults"],
+				}`),
+		},
+	},
+
 	// Package default_visibility tests
 	{
 		name: "package default_visibility property is checked",