• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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"
20	"sort"
21	"strings"
22	"sync"
23
24	"github.com/google/blueprint"
25)
26
27// Enforces visibility rules between modules.
28//
29// 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,
37//   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
40//   and so can be run in parallel. If a module has no visibility specified then it uses the
41//   default package visibility if specified.
42//
43// * Fourth stage works top down and iterates over all the deps for each module. If the dep is in
44//   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.
50
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
60type visibilityModuleReference struct {
61	name          qualifiedModuleName
62	partitionType *string
63}
64
65func createVisibilityModuleReference(name, dir string, module Module) visibilityModuleReference {
66	vis := visibilityModuleReference{
67		name: createQualifiedModuleName(name, dir),
68	}
69	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
84}
85
86// 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.
91	matches(m visibilityModuleReference) bool
92
93	String() string
94}
95
96// Describes the properties provided by a module that contain visibility rules.
97type visibilityPropertyImpl struct {
98	name            string
99	stringsProperty *[]string
100}
101
102type visibilityProperty interface {
103	getName() string
104	getStrings() []string
105}
106
107func newVisibilityProperty(name string, stringsProperty *[]string) visibilityProperty {
108	return visibilityPropertyImpl{
109		name:            name,
110		stringsProperty: stringsProperty,
111	}
112}
113
114func (p visibilityPropertyImpl) getName() string {
115	return p.name
116}
117
118func (p visibilityPropertyImpl) getStrings() []string {
119	return *p.stringsProperty
120}
121
122// 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//
133// 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
137var _ visibilityRule = compositeRule{}
138
139// A compositeRule matches if and only if any of its rules matches.
140func (c compositeRule) matches(m visibilityModuleReference) bool {
141	for _, r := range c {
142		if r.matches(m) {
143			return true
144		}
145	}
146	return false
147}
148
149func (c compositeRule) String() string {
150	return "[" + strings.Join(c.Strings(), ", ") + "]"
151}
152
153func (c compositeRule) Strings() []string {
154	s := make([]string, 0, len(c))
155	for _, r := range c {
156		s = append(s, r.String())
157	}
158	return s
159}
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
166var _ visibilityRule = packageRule{}
167
168func (r packageRule) matches(m visibilityModuleReference) bool {
169	return m.name.pkg == r.pkg
170}
171
172func (r packageRule) String() string {
173	return fmt.Sprintf("//%s", r.pkg) // :__pkg__ is the default, so skip it.
174}
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
182var _ visibilityRule = subpackagesRule{}
183
184func (r subpackagesRule) matches(m visibilityModuleReference) bool {
185	return isAncestor(r.pkgPrefix, m.name.pkg)
186}
187
188func isAncestor(p1 string, p2 string) bool {
189	// 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)] == '/')
194}
195
196func (r subpackagesRule) String() string {
197	return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
198}
199
200// visibilityRule for //visibility:public
201type publicRule struct{}
202
203var _ visibilityRule = publicRule{}
204
205func (r publicRule) matches(_ visibilityModuleReference) bool {
206	return true
207}
208
209func (r publicRule) String() string {
210	return "//visibility:public"
211}
212
213// visibilityRule for //visibility:private
214type privateRule struct{}
215
216var _ visibilityRule = privateRule{}
217
218func (r privateRule) matches(_ visibilityModuleReference) bool {
219	return false
220}
221
222func (r privateRule) String() string {
223	return "//visibility:private"
224}
225
226var anyPartitionRegex = regexp.MustCompile("^any_(system|system_ext|vendor|product|data|odm)_partition$")
227
228// visibilityRule for //visibility:any_partition
229type anyPartitionRule struct {
230	partitionType string
231}
232
233var _ visibilityRule = anyPartitionRule{}
234
235type PartitionTypeInterface interface {
236	PartitionType() string
237}
238
239type 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
247func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
248	if m.partitionType != nil {
249		return *m.partitionType == r.partitionType
250	}
251	return false
252}
253
254func (r anyPartitionRule) String() string {
255	return "//visibility:any_" + r.partitionType + "_partition"
256}
257
258var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
259
260type visibilityRulesForModule struct {
261	rule                   compositeRule
262	implicitPartitionRules compositeRule
263}
264
265// The map from qualifiedModuleName to visibilityRule.
266func moduleToVisibilityRuleMap(config Config) *sync.Map {
267	return config.Once(visibilityRuleMap, func() interface{} {
268		return &sync.Map{}
269	}).(*sync.Map)
270}
271
272// 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
281// The visibility mutators.
282var PrepareForTestWithVisibility = FixtureRegisterWithContext(registerVisibilityMutators)
283
284func registerVisibilityMutators(ctx RegistrationContext) {
285	ctx.PreArchMutators(RegisterVisibilityRuleChecker)
286	ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
287	ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
288}
289
290// 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.
292func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) {
293	ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker)
294}
295
296// Registers the function that gathers the visibility rules for each module.
297//
298// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
299// having to process multiple variants for each module. This goes after defaults expansion to gather
300// the complete visibility lists from flat lists and after the package info is gathered to ensure
301// that default_visibility is available.
302func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
303	ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer)
304}
305
306// This must be registered after the deps have been resolved.
307func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
308	ctx.BottomUp("visibilityRuleEnforcer", visibilityRuleEnforcer)
309}
310
311// Checks the per-module visibility rule lists before defaults expansion.
312func visibilityRuleChecker(ctx BottomUpMutatorContext) {
313	visibilityProperties := ctx.Module().visibilityProperties()
314	for _, p := range visibilityProperties {
315		if visibility := p.getStrings(); visibility != nil {
316			checkRules(ctx, ctx.ModuleDir(), p.getName(), visibility)
317		}
318	}
319}
320
321func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) {
322	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.
327		ctx.PropertyErrorf(property, "must contain at least one visibility rule")
328		return
329	}
330
331	for i, v := range visibility {
332		ok, pkg, name := splitRule(ctx, v, currentPkg, property)
333		if !ok {
334			continue
335		}
336
337		if pkg == "visibility" {
338			switch name {
339			case "private", "public":
340			case "legacy_public":
341				ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
342				continue
343			case "override":
344				// This keyword does not create a rule so pretend it does not exist.
345				ruleCount -= 1
346			default:
347				if anyPartitionRegex.MatchString(name) {
348					// any_*_partition can be used with another visibility fields
349					continue
350				}
351				ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v)
352				continue
353			}
354			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 {
359				ctx.PropertyErrorf(property, "cannot mix %q with any other visibility rules", v)
360				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) {
368				ctx.PropertyErrorf(property,
369					"%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.
379//
380// See ../README.md#Visibility for information on the format of the visibility rules.
381func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
382	m := ctx.Module()
383
384	qualifiedModuleId := m.qualifiedModuleId(ctx)
385	currentPkg := qualifiedModuleId.pkg
386
387	// Parse the visibility rules that control access to the module and store them by id
388	// for use when enforcing the rules.
389	var rule compositeRule
390	primaryProperty := m.base().primaryVisibilityProperty
391	if primaryProperty != nil {
392		if visibility := primaryProperty.getStrings(); visibility != nil {
393			rule = parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
394		}
395	}
396	ipr := implicitPartitionRules(ctx)
397	if rule != nil || ipr != nil {
398		moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, visibilityRulesForModule{
399			rule:                   rule,
400			implicitPartitionRules: ipr,
401		})
402	}
403}
404
405func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule {
406	rules := make(compositeRule, 0, len(visibility))
407	hasPrivateRule := false
408	hasPublicRule := false
409	hasNonPrivateRule := false
410	for _, v := range visibility {
411		ok, pkg, name := splitRule(ctx, v, currentPkg, property)
412		if !ok {
413			continue
414		}
415
416		var r visibilityRule
417		isPrivateRule := false
418		if pkg == "visibility" {
419			switch name {
420			case "private":
421				r = privateRule{}
422				isPrivateRule = true
423			case "public":
424				r = publicRule{}
425				hasPublicRule = true
426			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
434			default:
435				match := anyPartitionRegex.FindStringSubmatch(name)
436				if match != nil {
437					r = anyPartitionRule{
438						partitionType: match[1],
439					}
440				}
441			}
442		} else {
443			switch name {
444			case "__pkg__":
445				r = packageRule{pkg}
446			case "__subpackages__":
447				r = subpackagesRule{pkg}
448			default:
449				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)
453			}
454		}
455
456		if isPrivateRule {
457			hasPrivateRule = true
458		} else {
459			hasNonPrivateRule = true
460		}
461
462		rules = append(rules, r)
463	}
464
465	if hasPrivateRule && hasNonPrivateRule {
466		ctx.PropertyErrorf("visibility",
467			"cannot mix \"//visibility:private\" with any other visibility rules")
468		return compositeRule{privateRule{}}
469	}
470
471	if hasPublicRule {
472		// Public overrides all other rules so just return it.
473		return compositeRule{publicRule{}}
474	}
475
476	return rules
477}
478
479func 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
495func isAllowedFromOutsideVendor(pkg string, name string) bool {
496	if pkg == "vendor" {
497		return name == "__subpackages__"
498	}
499
500	return !isAncestor("vendor", pkg)
501}
502
503func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, property string) (bool, string, string) {
504	// Make sure that the rule is of the correct format.
505	matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression)
506	if ruleExpression == "" || matches == nil {
507		// 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"+
511				" //<package>:<scope>, //<package> or :<scope> "+
512				"where <scope> is one of \"__pkg__\", \"__subpackages__\"",
513			ruleExpression)
514		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
532func visibilityRuleEnforcer(ctx BottomUpMutatorContext) {
533	qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module())
534
535	// Visit all the dependencies making sure that this module has access to them all.
536	ctx.VisitDirectDeps(func(dep Module) {
537		// Ignore dependencies that have an ExcludeFromVisibilityEnforcementTag
538		tag := ctx.OtherModuleDependencyTag(dep)
539		if _, ok := tag.(ExcludeFromVisibilityEnforcementTag); ok {
540			return
541		}
542
543		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.
548		if depQualified.pkg == qualified.name.pkg {
549			return
550		}
551
552		rule := effectiveVisibilityRules(ctx.Config(), depQualified)
553		if !rule.matches(qualified) {
554			ctx.ModuleErrorf("depends on %s which is not visible to this module\nYou may need to add %q to its visibility", depQualified, "//"+ctx.ModuleDir())
555		}
556	})
557}
558
559// 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.
566func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
567	moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
568	value := visibilityRulesForModule{}
569	if valueRaw, ok := moduleToVisibilityRule.Load(qualified); ok {
570		value = valueRaw.(visibilityRulesForModule)
571	}
572	var rule compositeRule
573	if value.rule != nil {
574		rule = value.rule
575	} else {
576		rule = packageDefaultVisibility(moduleToVisibilityRule, qualified)
577	}
578
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	}
584
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
598	return rule
599}
600
601func createQualifiedModuleName(moduleName, dir string) qualifiedModuleName {
602	qualified := qualifiedModuleName{dir, moduleName}
603	return qualified
604}
605
606func packageDefaultVisibility(moduleToVisibilityRule *sync.Map, moduleId qualifiedModuleName) compositeRule {
607	packageQualifiedId := moduleId.getContainingPackageId()
608	for {
609		value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
610		if ok {
611			return value.(visibilityRulesForModule).rule
612		}
613
614		if packageQualifiedId.isRootPackage() {
615			return nil
616		}
617
618		packageQualifiedId = packageQualifiedId.getContainingPackageId()
619	}
620}
621
622type 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
672// 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}
696