blob: 416a3f15f20bac4fd46c0e5e5110ac499f415caa [file] [log] [blame]
Paul Duffin2e61fa62019-03-28 14:10:57 +00001// Copyright 2019 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18 "fmt"
19 "regexp"
Paul Duffin157f40f2020-09-29 16:01:08 +010020 "sort"
Paul Duffin2e61fa62019-03-28 14:10:57 +000021 "strings"
22 "sync"
Paul Duffin78ac5b92020-01-14 12:42:08 +000023
24 "github.com/google/blueprint"
Paul Duffin2e61fa62019-03-28 14:10:57 +000025)
26
27// Enforces visibility rules between modules.
28//
Paul Duffine2453c72019-05-31 14:00:04 +010029// Multi stage process:
30// * First stage works bottom up, before defaults expansion, to check the syntax of the visibility
31// rules that have been specified.
32//
33// * Second stage works bottom up to extract the package info for each package and store them in a
34// map by package name. See package.go for functionality for this.
35//
36// * Third stage works bottom up to extract visibility information from the modules, parse it,
Paul Duffin2e61fa62019-03-28 14:10:57 +000037// create visibilityRule structures and store them in a map keyed by the module's
38// qualifiedModuleName instance, i.e. //<pkg>:<name>. The map is stored in the context rather
39// than a global variable for testing. Each test has its own Config so they do not share a map
Paul Duffine2453c72019-05-31 14:00:04 +010040// and so can be run in parallel. If a module has no visibility specified then it uses the
41// default package visibility if specified.
Paul Duffin2e61fa62019-03-28 14:10:57 +000042//
Paul Duffine2453c72019-05-31 14:00:04 +010043// * Fourth stage works top down and iterates over all the deps for each module. If the dep is in
Paul Duffin2e61fa62019-03-28 14:10:57 +000044// the same package then it is automatically visible. Otherwise, for each dep it first extracts
45// its visibilityRule from the config map. If one could not be found then it assumes that it is
46// publicly visible. Otherwise, it calls the visibility rule to check that the module can see
47// the dependency. If it cannot then an error is reported.
48//
49// TODO(b/130631145) - Make visibility work properly with prebuilts.
Paul Duffin2e61fa62019-03-28 14:10:57 +000050
51// Patterns for the values that can be specified in visibility property.
52const (
53 packagePattern = `//([^/:]+(?:/[^/:]+)*)`
54 namePattern = `:([^/:]+)`
55 visibilityRulePattern = `^(?:` + packagePattern + `)?(?:` + namePattern + `)?$`
56)
57
58var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
59
Cole Faust894bb3b2024-02-07 11:28:26 -080060type visibilityModuleReference struct {
Yu Liu71f1ea32025-02-26 23:39:20 +000061 name qualifiedModuleName
62 partitionType *string
Cole Faust894bb3b2024-02-07 11:28:26 -080063}
64
Cole Faust9a24d902024-03-18 15:38:12 -070065func createVisibilityModuleReference(name, dir string, module Module) visibilityModuleReference {
Yu Liu71f1ea32025-02-26 23:39:20 +000066 vis := visibilityModuleReference{
67 name: createQualifiedModuleName(name, dir),
Cole Faust894bb3b2024-02-07 11:28:26 -080068 }
Yu Liu71f1ea32025-02-26 23:39:20 +000069 if m, ok := module.(PartitionTypeInterface); ok {
70 pt := m.PartitionType()
71 vis.partitionType = &pt
72 }
73 return vis
74}
75
76func createVisibilityModuleProxyReference(ctx OtherModuleProviderContext, name, dir string, module ModuleProxy) visibilityModuleReference {
77 vis := visibilityModuleReference{
78 name: createQualifiedModuleName(name, dir),
79 }
80 if m, ok := OtherModuleProvider(ctx, module, PartitionTypeInfoProvider); ok {
81 vis.partitionType = &m.PartitionType
82 }
83 return vis
Cole Faust894bb3b2024-02-07 11:28:26 -080084}
85
Paul Duffin2e61fa62019-03-28 14:10:57 +000086// A visibility rule is associated with a module and determines which other modules it is visible
87// to, i.e. which other modules can depend on the rule's module.
88type visibilityRule interface {
89 // Check to see whether this rules matches m.
90 // Returns true if it does, false otherwise.
Cole Faust894bb3b2024-02-07 11:28:26 -080091 matches(m visibilityModuleReference) bool
Paul Duffin2e61fa62019-03-28 14:10:57 +000092
93 String() string
94}
95
Paul Duffine2453c72019-05-31 14:00:04 +010096// Describes the properties provided by a module that contain visibility rules.
97type visibilityPropertyImpl struct {
Paul Duffin63c6e182019-07-24 14:24:38 +010098 name string
99 stringsProperty *[]string
Paul Duffine2453c72019-05-31 14:00:04 +0100100}
101
102type visibilityProperty interface {
103 getName() string
104 getStrings() []string
105}
106
Paul Duffin63c6e182019-07-24 14:24:38 +0100107func newVisibilityProperty(name string, stringsProperty *[]string) visibilityProperty {
Paul Duffine2453c72019-05-31 14:00:04 +0100108 return visibilityPropertyImpl{
Paul Duffin63c6e182019-07-24 14:24:38 +0100109 name: name,
110 stringsProperty: stringsProperty,
Paul Duffine2453c72019-05-31 14:00:04 +0100111 }
112}
113
114func (p visibilityPropertyImpl) getName() string {
115 return p.name
116}
117
118func (p visibilityPropertyImpl) getStrings() []string {
Paul Duffin63c6e182019-07-24 14:24:38 +0100119 return *p.stringsProperty
Paul Duffine2453c72019-05-31 14:00:04 +0100120}
121
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100122// A compositeRule is a visibility rule composed from a list of atomic visibility rules.
123//
124// The list corresponds to the list of strings in the visibility property after defaults expansion.
125// Even though //visibility:public is not allowed together with other rules in the visibility list
126// of a single module, it is allowed here to permit a module to override an inherited visibility
127// spec with public visibility.
128//
129// //visibility:private is not allowed in the same way, since we'd need to check for it during the
130// defaults expansion to make that work. No non-private visibility rules are allowed in a
131// compositeRule containing a privateRule.
132//
Paul Duffin2e61fa62019-03-28 14:10:57 +0000133// This array will only be [] if all the rules are invalid and will behave as if visibility was
134// ["//visibility:private"].
135type compositeRule []visibilityRule
136
Cole Faust894bb3b2024-02-07 11:28:26 -0800137var _ visibilityRule = compositeRule{}
138
Paul Duffin2e61fa62019-03-28 14:10:57 +0000139// A compositeRule matches if and only if any of its rules matches.
Cole Faust894bb3b2024-02-07 11:28:26 -0800140func (c compositeRule) matches(m visibilityModuleReference) bool {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000141 for _, r := range c {
142 if r.matches(m) {
143 return true
144 }
145 }
146 return false
147}
148
Paul Duffine2453c72019-05-31 14:00:04 +0100149func (c compositeRule) String() string {
Paul Duffin593b3c92019-12-05 14:31:48 +0000150 return "[" + strings.Join(c.Strings(), ", ") + "]"
151}
152
153func (c compositeRule) Strings() []string {
Paul Duffine2453c72019-05-31 14:00:04 +0100154 s := make([]string, 0, len(c))
155 for _, r := range c {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000156 s = append(s, r.String())
157 }
Paul Duffin593b3c92019-12-05 14:31:48 +0000158 return s
Paul Duffin2e61fa62019-03-28 14:10:57 +0000159}
160
161// A packageRule is a visibility rule that matches modules in a specific package (i.e. directory).
162type packageRule struct {
163 pkg string
164}
165
Cole Faust894bb3b2024-02-07 11:28:26 -0800166var _ visibilityRule = packageRule{}
167
168func (r packageRule) matches(m visibilityModuleReference) bool {
169 return m.name.pkg == r.pkg
Paul Duffin2e61fa62019-03-28 14:10:57 +0000170}
171
172func (r packageRule) String() string {
Martin Stjernholm01407c52020-05-13 01:54:21 +0100173 return fmt.Sprintf("//%s", r.pkg) // :__pkg__ is the default, so skip it.
Paul Duffin2e61fa62019-03-28 14:10:57 +0000174}
175
176// A subpackagesRule is a visibility rule that matches modules in a specific package (i.e.
177// directory) or any of its subpackages (i.e. subdirectories).
178type subpackagesRule struct {
179 pkgPrefix string
180}
181
Cole Faust894bb3b2024-02-07 11:28:26 -0800182var _ visibilityRule = subpackagesRule{}
183
184func (r subpackagesRule) matches(m visibilityModuleReference) bool {
185 return isAncestor(r.pkgPrefix, m.name.pkg)
Paul Duffin2e61fa62019-03-28 14:10:57 +0000186}
187
188func isAncestor(p1 string, p2 string) bool {
Cole Faust3ac7db82023-01-12 10:36:17 -0800189 // Equivalent to strings.HasPrefix(p2+"/", p1+"/"), but without the string copies
190 // The check for a trailing slash is so that we don't consider sibling
191 // directories with common prefixes to be ancestors, e.g. "fooo/bar" should not be
192 // a descendant of "foo".
193 return strings.HasPrefix(p2, p1) && (len(p2) == len(p1) || p2[len(p1)] == '/')
Paul Duffin2e61fa62019-03-28 14:10:57 +0000194}
195
196func (r subpackagesRule) String() string {
197 return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
198}
199
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100200// visibilityRule for //visibility:public
201type publicRule struct{}
202
Cole Faust894bb3b2024-02-07 11:28:26 -0800203var _ visibilityRule = publicRule{}
204
205func (r publicRule) matches(_ visibilityModuleReference) bool {
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100206 return true
207}
208
209func (r publicRule) String() string {
210 return "//visibility:public"
211}
212
213// visibilityRule for //visibility:private
214type privateRule struct{}
215
Cole Faust894bb3b2024-02-07 11:28:26 -0800216var _ visibilityRule = privateRule{}
217
218func (r privateRule) matches(_ visibilityModuleReference) bool {
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100219 return false
220}
221
222func (r privateRule) String() string {
223 return "//visibility:private"
224}
225
Cole Faust9a24d902024-03-18 15:38:12 -0700226var anyPartitionRegex = regexp.MustCompile("^any_(system|system_ext|vendor|product|data|odm)_partition$")
227
Cole Faust894bb3b2024-02-07 11:28:26 -0800228// visibilityRule for //visibility:any_partition
Cole Faust9a24d902024-03-18 15:38:12 -0700229type anyPartitionRule struct {
230 partitionType string
231}
Cole Faust894bb3b2024-02-07 11:28:26 -0800232
233var _ visibilityRule = anyPartitionRule{}
234
Cole Faust9a24d902024-03-18 15:38:12 -0700235type PartitionTypeInterface interface {
236 PartitionType() string
237}
238
Yu Liu71f1ea32025-02-26 23:39:20 +0000239type PartitionTypeInfo struct {
240 // Identifies which partition this is for //visibility:any_system_image (and others) visibility
241 // checks, and will be used in the future for API surface checks.
242 PartitionType string
243}
244
245var PartitionTypeInfoProvider = blueprint.NewProvider[PartitionTypeInfo]()
246
Cole Faust894bb3b2024-02-07 11:28:26 -0800247func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
Yu Liu71f1ea32025-02-26 23:39:20 +0000248 if m.partitionType != nil {
249 return *m.partitionType == r.partitionType
Cole Faust9a24d902024-03-18 15:38:12 -0700250 }
251 return false
Cole Faust894bb3b2024-02-07 11:28:26 -0800252}
253
254func (r anyPartitionRule) String() string {
Cole Faust9a24d902024-03-18 15:38:12 -0700255 return "//visibility:any_" + r.partitionType + "_partition"
Cole Faust894bb3b2024-02-07 11:28:26 -0800256}
257
Paul Duffin2e61fa62019-03-28 14:10:57 +0000258var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
259
Cole Faust9a24d902024-03-18 15:38:12 -0700260type visibilityRulesForModule struct {
261 rule compositeRule
262 implicitPartitionRules compositeRule
263}
264
Paul Duffin2e61fa62019-03-28 14:10:57 +0000265// The map from qualifiedModuleName to visibilityRule.
Paul Duffin44885e22020-02-19 16:10:09 +0000266func moduleToVisibilityRuleMap(config Config) *sync.Map {
267 return config.Once(visibilityRuleMap, func() interface{} {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000268 return &sync.Map{}
269 }).(*sync.Map)
270}
271
Paul Duffin78ac5b92020-01-14 12:42:08 +0000272// Marker interface that identifies dependencies that are excluded from visibility
273// enforcement.
274type ExcludeFromVisibilityEnforcementTag interface {
275 blueprint.DependencyTag
276
277 // Method that differentiates this interface from others.
278 ExcludeFromVisibilityEnforcement()
279}
280
Paul Duffin530483c2021-03-07 13:20:38 +0000281// The visibility mutators.
282var PrepareForTestWithVisibility = FixtureRegisterWithContext(registerVisibilityMutators)
283
284func registerVisibilityMutators(ctx RegistrationContext) {
Paul Duffincfd33742021-02-27 11:59:02 +0000285 ctx.PreArchMutators(RegisterVisibilityRuleChecker)
Paul Duffincfd33742021-02-27 11:59:02 +0000286 ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
Paul Duffincfd33742021-02-27 11:59:02 +0000287 ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
Paul Duffin530483c2021-03-07 13:20:38 +0000288}
Paul Duffincfd33742021-02-27 11:59:02 +0000289
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100290// The rule checker needs to be registered before defaults expansion to correctly check that
291// //visibility:xxx isn't combined with other packages in the same list in any one module.
Paul Duffin593b3c92019-12-05 14:31:48 +0000292func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) {
Colin Cross8a962802024-10-09 15:29:27 -0700293 ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker)
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100294}
295
Paul Duffine2453c72019-05-31 14:00:04 +0100296// Registers the function that gathers the visibility rules for each module.
297//
Paul Duffin2e61fa62019-03-28 14:10:57 +0000298// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100299// having to process multiple variants for each module. This goes after defaults expansion to gather
Paul Duffine2453c72019-05-31 14:00:04 +0100300// the complete visibility lists from flat lists and after the package info is gathered to ensure
301// that default_visibility is available.
Paul Duffin593b3c92019-12-05 14:31:48 +0000302func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
Colin Cross8a962802024-10-09 15:29:27 -0700303 ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer)
Paul Duffin2e61fa62019-03-28 14:10:57 +0000304}
305
306// This must be registered after the deps have been resolved.
Paul Duffin593b3c92019-12-05 14:31:48 +0000307func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
Colin Cross8a962802024-10-09 15:29:27 -0700308 ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer)
Paul Duffin2e61fa62019-03-28 14:10:57 +0000309}
310
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100311// Checks the per-module visibility rule lists before defaults expansion.
312func visibilityRuleChecker(ctx BottomUpMutatorContext) {
Cole Faust894bb3b2024-02-07 11:28:26 -0800313 visibilityProperties := ctx.Module().visibilityProperties()
314 for _, p := range visibilityProperties {
315 if visibility := p.getStrings(); visibility != nil {
316 checkRules(ctx, ctx.ModuleDir(), p.getName(), visibility)
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100317 }
318 }
319}
320
Paul Duffine2453c72019-05-31 14:00:04 +0100321func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) {
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100322 ruleCount := len(visibility)
323 if ruleCount == 0 {
324 // This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
325 // it could mean public visibility. Requiring at least one rule makes the owner's intent
326 // clearer.
Paul Duffine2453c72019-05-31 14:00:04 +0100327 ctx.PropertyErrorf(property, "must contain at least one visibility rule")
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100328 return
329 }
330
Paul Duffin51084ff2020-05-05 19:19:22 +0100331 for i, v := range visibility {
Paul Duffin0c83aba2020-05-01 18:13:36 +0100332 ok, pkg, name := splitRule(ctx, v, currentPkg, property)
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100333 if !ok {
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100334 continue
335 }
336
337 if pkg == "visibility" {
338 switch name {
Jeongik Cha31be3522024-03-12 19:34:29 +0900339 case "private", "public":
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100340 case "legacy_public":
Paul Duffine2453c72019-05-31 14:00:04 +0100341 ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100342 continue
Paul Duffin51084ff2020-05-05 19:19:22 +0100343 case "override":
344 // This keyword does not create a rule so pretend it does not exist.
345 ruleCount -= 1
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100346 default:
Cole Faust9a24d902024-03-18 15:38:12 -0700347 if anyPartitionRegex.MatchString(name) {
348 // any_*_partition can be used with another visibility fields
349 continue
350 }
Paul Duffine2453c72019-05-31 14:00:04 +0100351 ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v)
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100352 continue
353 }
Paul Duffin51084ff2020-05-05 19:19:22 +0100354 if name == "override" {
355 if i != 0 {
356 ctx.PropertyErrorf(property, `"%v" may only be used at the start of the visibility rules`, v)
357 }
358 } else if ruleCount != 1 {
Paul Duffine2453c72019-05-31 14:00:04 +0100359 ctx.PropertyErrorf(property, "cannot mix %q with any other visibility rules", v)
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100360 continue
361 }
362 }
363
364 // If the current directory is not in the vendor tree then there are some additional
365 // restrictions on the rules.
366 if !isAncestor("vendor", currentPkg) {
367 if !isAllowedFromOutsideVendor(pkg, name) {
Paul Duffine2453c72019-05-31 14:00:04 +0100368 ctx.PropertyErrorf(property,
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100369 "%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
370 " targets within //vendor, they can only use //vendor:__subpackages__.", v)
371 continue
372 }
373 }
374 }
375}
376
377// Gathers the flattened visibility rules after defaults expansion, parses the visibility
378// properties, stores them in a map by qualifiedModuleName for retrieval during enforcement.
Paul Duffin2e61fa62019-03-28 14:10:57 +0000379//
380// See ../README.md#Visibility for information on the format of the visibility rules.
Paul Duffin2e61fa62019-03-28 14:10:57 +0000381func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
Cole Faust894bb3b2024-02-07 11:28:26 -0800382 m := ctx.Module()
Paul Duffin2e61fa62019-03-28 14:10:57 +0000383
Paul Duffine2453c72019-05-31 14:00:04 +0100384 qualifiedModuleId := m.qualifiedModuleId(ctx)
385 currentPkg := qualifiedModuleId.pkg
Paul Duffin2e61fa62019-03-28 14:10:57 +0000386
Paul Duffin63c6e182019-07-24 14:24:38 +0100387 // Parse the visibility rules that control access to the module and store them by id
388 // for use when enforcing the rules.
Cole Faust9a24d902024-03-18 15:38:12 -0700389 var rule compositeRule
Paul Duffin0c83aba2020-05-01 18:13:36 +0100390 primaryProperty := m.base().primaryVisibilityProperty
391 if primaryProperty != nil {
392 if visibility := primaryProperty.getStrings(); visibility != nil {
Cole Faust9a24d902024-03-18 15:38:12 -0700393 rule = parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
Paul Duffin2e61fa62019-03-28 14:10:57 +0000394 }
395 }
Cole Faust9a24d902024-03-18 15:38:12 -0700396 ipr := implicitPartitionRules(ctx)
397 if rule != nil || ipr != nil {
398 moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, visibilityRulesForModule{
399 rule: rule,
400 implicitPartitionRules: ipr,
401 })
402 }
Paul Duffin2e61fa62019-03-28 14:10:57 +0000403}
404
Paul Duffin0c83aba2020-05-01 18:13:36 +0100405func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule {
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100406 rules := make(compositeRule, 0, len(visibility))
407 hasPrivateRule := false
Paul Duffin44885e22020-02-19 16:10:09 +0000408 hasPublicRule := false
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100409 hasNonPrivateRule := false
Paul Duffin2e61fa62019-03-28 14:10:57 +0000410 for _, v := range visibility {
Paul Duffin0c83aba2020-05-01 18:13:36 +0100411 ok, pkg, name := splitRule(ctx, v, currentPkg, property)
Paul Duffin2e61fa62019-03-28 14:10:57 +0000412 if !ok {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000413 continue
414 }
415
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100416 var r visibilityRule
417 isPrivateRule := false
Paul Duffin2e61fa62019-03-28 14:10:57 +0000418 if pkg == "visibility" {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000419 switch name {
420 case "private":
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100421 r = privateRule{}
422 isPrivateRule = true
Paul Duffin2e61fa62019-03-28 14:10:57 +0000423 case "public":
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100424 r = publicRule{}
Paul Duffin44885e22020-02-19 16:10:09 +0000425 hasPublicRule = true
Paul Duffin51084ff2020-05-05 19:19:22 +0100426 case "override":
427 // Discard all preceding rules and any state based on them.
428 rules = nil
429 hasPrivateRule = false
430 hasPublicRule = false
431 hasNonPrivateRule = false
432 // This does not actually create a rule so continue onto the next rule.
433 continue
Cole Faust9a24d902024-03-18 15:38:12 -0700434 default:
435 match := anyPartitionRegex.FindStringSubmatch(name)
436 if match != nil {
437 r = anyPartitionRule{
438 partitionType: match[1],
439 }
440 }
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100441 }
442 } else {
443 switch name {
444 case "__pkg__":
445 r = packageRule{pkg}
446 case "__subpackages__":
447 r = subpackagesRule{pkg}
Paul Duffin2e61fa62019-03-28 14:10:57 +0000448 default:
Liz Kammer873f4b62020-10-15 08:42:01 -0700449 ctx.PropertyErrorf(property, "invalid visibility pattern %q. Must match "+
450 " //<package>:<scope>, //<package> or :<scope> "+
451 "where <scope> is one of \"__pkg__\", \"__subpackages__\"",
452 v)
Paul Duffin2e61fa62019-03-28 14:10:57 +0000453 }
454 }
455
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100456 if isPrivateRule {
457 hasPrivateRule = true
458 } else {
459 hasNonPrivateRule = true
Paul Duffin2e61fa62019-03-28 14:10:57 +0000460 }
461
462 rules = append(rules, r)
463 }
464
Martin Stjernholm226b20d2019-05-17 22:42:02 +0100465 if hasPrivateRule && hasNonPrivateRule {
466 ctx.PropertyErrorf("visibility",
467 "cannot mix \"//visibility:private\" with any other visibility rules")
468 return compositeRule{privateRule{}}
469 }
470
Paul Duffin44885e22020-02-19 16:10:09 +0000471 if hasPublicRule {
472 // Public overrides all other rules so just return it.
473 return compositeRule{publicRule{}}
474 }
475
Paul Duffin2e61fa62019-03-28 14:10:57 +0000476 return rules
477}
478
Cole Faust9a24d902024-03-18 15:38:12 -0700479func implicitPartitionRules(ctx BaseModuleContext) compositeRule {
480 var result compositeRule
481 if ctx.SocSpecific() {
482 result = append(result, anyPartitionRule{partitionType: "vendor"})
483 } else if ctx.ProductSpecific() {
484 result = append(result, anyPartitionRule{partitionType: "product"})
485 } else if ctx.Module().InstallInData() {
486 result = append(result, anyPartitionRule{partitionType: "data"})
487 } else if ctx.SystemExtSpecific() {
488 result = append(result, anyPartitionRule{partitionType: "system_ext"})
489 } else if ctx.DeviceSpecific() {
490 result = append(result, anyPartitionRule{partitionType: "odm"})
491 }
492 return result
493}
494
Paul Duffin2e61fa62019-03-28 14:10:57 +0000495func isAllowedFromOutsideVendor(pkg string, name string) bool {
496 if pkg == "vendor" {
Cole Faust894bb3b2024-02-07 11:28:26 -0800497 return name == "__subpackages__"
Paul Duffin2e61fa62019-03-28 14:10:57 +0000498 }
499
500 return !isAncestor("vendor", pkg)
501}
502
Paul Duffin0c83aba2020-05-01 18:13:36 +0100503func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, property string) (bool, string, string) {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000504 // Make sure that the rule is of the correct format.
505 matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression)
506 if ruleExpression == "" || matches == nil {
Paul Duffin0c83aba2020-05-01 18:13:36 +0100507 // Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
508 // ensure all the rules on this module are checked.
509 ctx.PropertyErrorf(property,
510 "invalid visibility pattern %q must match"+
Liz Kammer873f4b62020-10-15 08:42:01 -0700511 " //<package>:<scope>, //<package> or :<scope> "+
512 "where <scope> is one of \"__pkg__\", \"__subpackages__\"",
Paul Duffin0c83aba2020-05-01 18:13:36 +0100513 ruleExpression)
Paul Duffin2e61fa62019-03-28 14:10:57 +0000514 return false, "", ""
515 }
516
517 // Extract the package and name.
518 pkg := matches[1]
519 name := matches[2]
520
521 // Normalize the short hands
522 if pkg == "" {
523 pkg = currentPkg
524 }
525 if name == "" {
526 name = "__pkg__"
527 }
528
529 return true, pkg, name
530}
531
Colin Crossda279cf2024-09-17 14:25:45 -0700532func visibilityRuleEnforcer(ctx BottomUpMutatorContext) {
Cole Faust9a24d902024-03-18 15:38:12 -0700533 qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module())
Paul Duffin2e61fa62019-03-28 14:10:57 +0000534
Paul Duffin2e61fa62019-03-28 14:10:57 +0000535 // Visit all the dependencies making sure that this module has access to them all.
536 ctx.VisitDirectDeps(func(dep Module) {
Paul Duffin78ac5b92020-01-14 12:42:08 +0000537 // Ignore dependencies that have an ExcludeFromVisibilityEnforcementTag
538 tag := ctx.OtherModuleDependencyTag(dep)
539 if _, ok := tag.(ExcludeFromVisibilityEnforcementTag); ok {
540 return
541 }
542
Paul Duffin2e61fa62019-03-28 14:10:57 +0000543 depName := ctx.OtherModuleName(dep)
544 depDir := ctx.OtherModuleDir(dep)
545 depQualified := qualifiedModuleName{depDir, depName}
546
547 // Targets are always visible to other targets in their own package.
Cole Faust894bb3b2024-02-07 11:28:26 -0800548 if depQualified.pkg == qualified.name.pkg {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000549 return
550 }
551
Paul Duffin44885e22020-02-19 16:10:09 +0000552 rule := effectiveVisibilityRules(ctx.Config(), depQualified)
Paul Duffind99d9972020-09-29 16:00:55 +0100553 if !rule.matches(qualified) {
Colin Crossd8d8b852024-12-20 16:32:37 -0800554 ctx.ModuleErrorf("depends on %s which is not visible to this module\nYou may need to add %q to its visibility, %#v", depQualified, "//"+ctx.ModuleDir(), ctx.OtherModuleDependencyTag(dep))
Paul Duffine2453c72019-05-31 14:00:04 +0100555 }
Paul Duffin2e61fa62019-03-28 14:10:57 +0000556 })
557}
558
Paul Duffind99d9972020-09-29 16:00:55 +0100559// Default visibility is public.
560var defaultVisibility = compositeRule{publicRule{}}
561
562// Return the effective visibility rules.
563//
564// If no rules have been specified this will return the default visibility rule
565// which is currently //visibility:public.
Paul Duffin44885e22020-02-19 16:10:09 +0000566func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
567 moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
Cole Faust9a24d902024-03-18 15:38:12 -0700568 value := visibilityRulesForModule{}
569 if valueRaw, ok := moduleToVisibilityRule.Load(qualified); ok {
570 value = valueRaw.(visibilityRulesForModule)
571 }
Paul Duffin593b3c92019-12-05 14:31:48 +0000572 var rule compositeRule
Cole Faust9a24d902024-03-18 15:38:12 -0700573 if value.rule != nil {
574 rule = value.rule
Paul Duffin593b3c92019-12-05 14:31:48 +0000575 } else {
Cole Faust894bb3b2024-02-07 11:28:26 -0800576 rule = packageDefaultVisibility(moduleToVisibilityRule, qualified)
Paul Duffin593b3c92019-12-05 14:31:48 +0000577 }
Paul Duffind99d9972020-09-29 16:00:55 +0100578
579 // If no rule is specified then return the default visibility rule to avoid
580 // every caller having to treat nil as public.
581 if rule == nil {
582 rule = defaultVisibility
583 }
Cole Faust9a24d902024-03-18 15:38:12 -0700584
585 // If a partition rule wasn't specified, add implicit partition visibility
586 // rules based on the partition properties like vendor: true.
587 foundPartitionRule := false
588 for _, r := range rule {
589 if _, ok := r.(anyPartitionRule); ok {
590 foundPartitionRule = true
591 break
592 }
593 }
594 if !foundPartitionRule {
595 rule = append(rule, value.implicitPartitionRules...)
596 }
597
Paul Duffin593b3c92019-12-05 14:31:48 +0000598 return rule
599}
600
Bob Badoureef4c1c2022-05-16 12:20:04 -0700601func createQualifiedModuleName(moduleName, dir string) qualifiedModuleName {
Paul Duffin2e61fa62019-03-28 14:10:57 +0000602 qualified := qualifiedModuleName{dir, moduleName}
603 return qualified
604}
Paul Duffine484f472019-06-20 16:38:08 +0100605
Cole Faust894bb3b2024-02-07 11:28:26 -0800606func packageDefaultVisibility(moduleToVisibilityRule *sync.Map, moduleId qualifiedModuleName) compositeRule {
Paul Duffine484f472019-06-20 16:38:08 +0100607 packageQualifiedId := moduleId.getContainingPackageId()
608 for {
609 value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
610 if ok {
Cole Faust9a24d902024-03-18 15:38:12 -0700611 return value.(visibilityRulesForModule).rule
Paul Duffine484f472019-06-20 16:38:08 +0100612 }
613
614 if packageQualifiedId.isRootPackage() {
615 return nil
616 }
617
618 packageQualifiedId = packageQualifiedId.getContainingPackageId()
619 }
620}
Paul Duffin593b3c92019-12-05 14:31:48 +0000621
Paul Duffin157f40f2020-09-29 16:01:08 +0100622type VisibilityRuleSet interface {
623 // Widen the visibility with some extra rules.
624 Widen(extra []string) error
625
626 Strings() []string
627}
628
629type visibilityRuleSet struct {
630 rules []string
631}
632
633var _ VisibilityRuleSet = (*visibilityRuleSet)(nil)
634
635func (v *visibilityRuleSet) Widen(extra []string) error {
636 // Check the extra rules first just in case they are invalid. Otherwise, if
637 // the current visibility is public then the extra rules will just be ignored.
638 if len(extra) == 1 {
639 singularRule := extra[0]
640 switch singularRule {
641 case "//visibility:public":
642 // Public overrides everything so just discard any existing rules.
643 v.rules = extra
644 return nil
645 case "//visibility:private":
646 // Extending rule with private is an error.
647 return fmt.Errorf("%q does not widen the visibility", singularRule)
648 }
649 }
650
651 if len(v.rules) == 1 {
652 switch v.rules[0] {
653 case "//visibility:public":
654 // No point in adding rules to something which is already public.
655 return nil
656 case "//visibility:private":
657 // Adding any rules to private means it is no longer private so the
658 // private can be discarded.
659 v.rules = nil
660 }
661 }
662
663 v.rules = FirstUniqueStrings(append(v.rules, extra...))
664 sort.Strings(v.rules)
665 return nil
666}
667
668func (v *visibilityRuleSet) Strings() []string {
669 return v.rules
670}
671
Paul Duffin5ec73ec2020-05-01 17:52:01 +0100672// Clear the default visibility properties so they can be replaced.
673func clearVisibilityProperties(module Module) {
674 module.base().visibilityPropertyInfo = nil
675}
676
677// Add a property that contains visibility rules so that they are checked for
678// correctness.
679func AddVisibilityProperty(module Module, name string, stringsProperty *[]string) {
680 addVisibilityProperty(module, name, stringsProperty)
681}
682
683func addVisibilityProperty(module Module, name string, stringsProperty *[]string) visibilityProperty {
684 base := module.base()
685 property := newVisibilityProperty(name, stringsProperty)
686 base.visibilityPropertyInfo = append(base.visibilityPropertyInfo, property)
687 return property
688}
689
690// Set the primary visibility property.
691//
692// Also adds the property to the list of properties to be validated.
693func setPrimaryVisibilityProperty(module Module, name string, stringsProperty *[]string) {
694 module.base().primaryVisibilityProperty = addVisibilityProperty(module, name, stringsProperty)
695}