Inherit default_visibility from parent package

Enhances the visibility mechanism to use the default_visibility
property of the closest ancestor package that has the property
specified.

Bug: 133290645
Test: m droid
Change-Id: I7248e9034a73894ac8d514f913316438c4d7c079
diff --git a/android/module.go b/android/module.go
index b912726..43b8763 100644
--- a/android/module.go
+++ b/android/module.go
@@ -226,11 +226,24 @@
 	return "//" + q.pkg + ":" + q.name
 }
 
+func (q qualifiedModuleName) isRootPackage() bool {
+	return q.pkg == "" && q.name == ""
+}
+
 // Get the id for the package containing this module.
 func (q qualifiedModuleName) getContainingPackageId() qualifiedModuleName {
 	pkg := q.pkg
 	if q.name == "" {
-		panic(fmt.Errorf("Cannot get containing package id of package module %s", pkg))
+		if pkg == "" {
+			panic(fmt.Errorf("Cannot get containing package id of root package"))
+		}
+
+		index := strings.LastIndex(pkg, "/")
+		if index == -1 {
+			pkg = ""
+		} else {
+			pkg = pkg[:index]
+		}
 	}
 	return newPackageId(pkg)
 }
@@ -276,8 +289,15 @@
 	// If a module does not specify the `visibility` property then it uses the
 	// `default_visibility` property of the `package` module in the module's package.
 	//
+	// If a module does not specify the `visibility` property then it uses the
+	// `default_visibility` property of the `package` module in the module's package.
+	//
 	// If the `default_visibility` property is not set for the module's package then
-	// the module uses `//visibility:legacy_public`.
+	// it will use the `default_visibility` of its closest ancestor package for which
+	// a `default_visibility` property is specified.
+	//
+	// If no `default_visibility` property can be found then the module uses the
+	// global default of `//visibility:legacy_public`.
 	//
 	// See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for
 	// more details.
diff --git a/android/visibility.go b/android/visibility.go
index 2e01ff6..94af343 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -413,11 +413,7 @@
 		if ok {
 			rule = value.(compositeRule)
 		} else {
-			packageQualifiedId := depQualified.getContainingPackageId()
-			value, ok = moduleToVisibilityRule.Load(packageQualifiedId)
-			if ok {
-				rule = value.(compositeRule)
-			}
+			rule = packageDefaultVisibility(ctx, depQualified)
 		}
 		if rule != nil && !rule.matches(qualified) {
 			ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
@@ -431,3 +427,20 @@
 	qualified := qualifiedModuleName{dir, moduleName}
 	return qualified
 }
+
+func packageDefaultVisibility(ctx BaseModuleContext, moduleId qualifiedModuleName) compositeRule {
+	moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+	packageQualifiedId := moduleId.getContainingPackageId()
+	for {
+		value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
+		if ok {
+			return value.(compositeRule)
+		}
+
+		if packageQualifiedId.isRootPackage() {
+			return nil
+		}
+
+		packageQualifiedId = packageQualifiedId.getContainingPackageId()
+	}
+}
diff --git a/android/visibility_test.go b/android/visibility_test.go
index 9a3e6aa..af6acf4 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -761,6 +761,64 @@
 				` visible to this module`,
 		},
 	},
+	{
+		name: "package default_visibility inherited to subpackages",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//outsider"],
+				}
+
+				mock_library {
+					name: "libexample",
+          visibility: [":__subpackages__"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				mock_library {
+					name: "libnested",
+					deps: ["libexample"],
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libexample", "libnested"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
+				` visible to this module`,
+		},
+	},
+	{
+		name: "package default_visibility inherited to subpackages",
+		fs: map[string][]byte{
+			"top/Blueprints": []byte(`
+				package {
+					default_visibility: ["//visibility:private"],
+				}`),
+			"top/nested/Blueprints": []byte(`
+				package {
+					default_visibility: ["//outsider"],
+				}
+
+				mock_library {
+					name: "libnested",
+				}`),
+			"top/other/Blueprints": []byte(`
+				mock_library {
+					name: "libother",
+				}`),
+			"outsider/Blueprints": []byte(`
+				mock_library {
+					name: "liboutsider",
+					deps: ["libother", "libnested"],
+				}`),
+		},
+		expectedErrors: []string{
+			`module "liboutsider" variant "android_common": depends on //top/other:libother which is` +
+				` not visible to this module`,
+		},
+	},
 }
 
 func TestVisibility(t *testing.T) {