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 module Module 63} 64 65func createVisibilityModuleReference(name, dir string, module Module) visibilityModuleReference { 66 return visibilityModuleReference{ 67 name: createQualifiedModuleName(name, dir), 68 module: module, 69 } 70} 71 72// A visibility rule is associated with a module and determines which other modules it is visible 73// to, i.e. which other modules can depend on the rule's module. 74type visibilityRule interface { 75 // Check to see whether this rules matches m. 76 // Returns true if it does, false otherwise. 77 matches(m visibilityModuleReference) bool 78 79 String() string 80} 81 82// Describes the properties provided by a module that contain visibility rules. 83type visibilityPropertyImpl struct { 84 name string 85 stringsProperty *[]string 86} 87 88type visibilityProperty interface { 89 getName() string 90 getStrings() []string 91} 92 93func newVisibilityProperty(name string, stringsProperty *[]string) visibilityProperty { 94 return visibilityPropertyImpl{ 95 name: name, 96 stringsProperty: stringsProperty, 97 } 98} 99 100func (p visibilityPropertyImpl) getName() string { 101 return p.name 102} 103 104func (p visibilityPropertyImpl) getStrings() []string { 105 return *p.stringsProperty 106} 107 108// A compositeRule is a visibility rule composed from a list of atomic visibility rules. 109// 110// The list corresponds to the list of strings in the visibility property after defaults expansion. 111// Even though //visibility:public is not allowed together with other rules in the visibility list 112// of a single module, it is allowed here to permit a module to override an inherited visibility 113// spec with public visibility. 114// 115// //visibility:private is not allowed in the same way, since we'd need to check for it during the 116// defaults expansion to make that work. No non-private visibility rules are allowed in a 117// compositeRule containing a privateRule. 118// 119// This array will only be [] if all the rules are invalid and will behave as if visibility was 120// ["//visibility:private"]. 121type compositeRule []visibilityRule 122 123var _ visibilityRule = compositeRule{} 124 125// A compositeRule matches if and only if any of its rules matches. 126func (c compositeRule) matches(m visibilityModuleReference) bool { 127 for _, r := range c { 128 if r.matches(m) { 129 return true 130 } 131 } 132 return false 133} 134 135func (c compositeRule) String() string { 136 return "[" + strings.Join(c.Strings(), ", ") + "]" 137} 138 139func (c compositeRule) Strings() []string { 140 s := make([]string, 0, len(c)) 141 for _, r := range c { 142 s = append(s, r.String()) 143 } 144 return s 145} 146 147// A packageRule is a visibility rule that matches modules in a specific package (i.e. directory). 148type packageRule struct { 149 pkg string 150} 151 152var _ visibilityRule = packageRule{} 153 154func (r packageRule) matches(m visibilityModuleReference) bool { 155 return m.name.pkg == r.pkg 156} 157 158func (r packageRule) String() string { 159 return fmt.Sprintf("//%s", r.pkg) // :__pkg__ is the default, so skip it. 160} 161 162// A subpackagesRule is a visibility rule that matches modules in a specific package (i.e. 163// directory) or any of its subpackages (i.e. subdirectories). 164type subpackagesRule struct { 165 pkgPrefix string 166} 167 168var _ visibilityRule = subpackagesRule{} 169 170func (r subpackagesRule) matches(m visibilityModuleReference) bool { 171 return isAncestor(r.pkgPrefix, m.name.pkg) 172} 173 174func isAncestor(p1 string, p2 string) bool { 175 // Equivalent to strings.HasPrefix(p2+"/", p1+"/"), but without the string copies 176 // The check for a trailing slash is so that we don't consider sibling 177 // directories with common prefixes to be ancestors, e.g. "fooo/bar" should not be 178 // a descendant of "foo". 179 return strings.HasPrefix(p2, p1) && (len(p2) == len(p1) || p2[len(p1)] == '/') 180} 181 182func (r subpackagesRule) String() string { 183 return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix) 184} 185 186// visibilityRule for //visibility:public 187type publicRule struct{} 188 189var _ visibilityRule = publicRule{} 190 191func (r publicRule) matches(_ visibilityModuleReference) bool { 192 return true 193} 194 195func (r publicRule) String() string { 196 return "//visibility:public" 197} 198 199// visibilityRule for //visibility:private 200type privateRule struct{} 201 202var _ visibilityRule = privateRule{} 203 204func (r privateRule) matches(_ visibilityModuleReference) bool { 205 return false 206} 207 208func (r privateRule) String() string { 209 return "//visibility:private" 210} 211 212var anyPartitionRegex = regexp.MustCompile("^any_(system|system_ext|vendor|product|data|odm)_partition$") 213 214// visibilityRule for //visibility:any_partition 215type anyPartitionRule struct { 216 partitionType string 217} 218 219var _ visibilityRule = anyPartitionRule{} 220 221type PartitionTypeInterface interface { 222 PartitionType() string 223} 224 225func (r anyPartitionRule) matches(m visibilityModuleReference) bool { 226 if m2, ok := m.module.(PartitionTypeInterface); ok { 227 return m2.PartitionType() == r.partitionType 228 } 229 return false 230} 231 232func (r anyPartitionRule) String() string { 233 return "//visibility:any_" + r.partitionType + "_partition" 234} 235 236var visibilityRuleMap = NewOnceKey("visibilityRuleMap") 237 238type visibilityRulesForModule struct { 239 rule compositeRule 240 implicitPartitionRules compositeRule 241} 242 243// The map from qualifiedModuleName to visibilityRule. 244func moduleToVisibilityRuleMap(config Config) *sync.Map { 245 return config.Once(visibilityRuleMap, func() interface{} { 246 return &sync.Map{} 247 }).(*sync.Map) 248} 249 250// Marker interface that identifies dependencies that are excluded from visibility 251// enforcement. 252type ExcludeFromVisibilityEnforcementTag interface { 253 blueprint.DependencyTag 254 255 // Method that differentiates this interface from others. 256 ExcludeFromVisibilityEnforcement() 257} 258 259// The visibility mutators. 260var PrepareForTestWithVisibility = FixtureRegisterWithContext(registerVisibilityMutators) 261 262func registerVisibilityMutators(ctx RegistrationContext) { 263 ctx.PreArchMutators(RegisterVisibilityRuleChecker) 264 ctx.PreArchMutators(RegisterVisibilityRuleGatherer) 265 ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer) 266} 267 268// The rule checker needs to be registered before defaults expansion to correctly check that 269// //visibility:xxx isn't combined with other packages in the same list in any one module. 270func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) { 271 ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel() 272} 273 274// Registers the function that gathers the visibility rules for each module. 275// 276// Visibility is not dependent on arch so this must be registered before the arch phase to avoid 277// having to process multiple variants for each module. This goes after defaults expansion to gather 278// the complete visibility lists from flat lists and after the package info is gathered to ensure 279// that default_visibility is available. 280func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) { 281 ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel() 282} 283 284// This must be registered after the deps have been resolved. 285func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) { 286 ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel() 287} 288 289// Checks the per-module visibility rule lists before defaults expansion. 290func visibilityRuleChecker(ctx BottomUpMutatorContext) { 291 visibilityProperties := ctx.Module().visibilityProperties() 292 for _, p := range visibilityProperties { 293 if visibility := p.getStrings(); visibility != nil { 294 checkRules(ctx, ctx.ModuleDir(), p.getName(), visibility) 295 } 296 } 297} 298 299func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) { 300 ruleCount := len(visibility) 301 if ruleCount == 0 { 302 // This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and 303 // it could mean public visibility. Requiring at least one rule makes the owner's intent 304 // clearer. 305 ctx.PropertyErrorf(property, "must contain at least one visibility rule") 306 return 307 } 308 309 for i, v := range visibility { 310 ok, pkg, name := splitRule(ctx, v, currentPkg, property) 311 if !ok { 312 continue 313 } 314 315 if pkg == "visibility" { 316 switch name { 317 case "private", "public": 318 case "legacy_public": 319 ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used") 320 continue 321 case "override": 322 // This keyword does not create a rule so pretend it does not exist. 323 ruleCount -= 1 324 default: 325 if anyPartitionRegex.MatchString(name) { 326 // any_*_partition can be used with another visibility fields 327 continue 328 } 329 ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v) 330 continue 331 } 332 if name == "override" { 333 if i != 0 { 334 ctx.PropertyErrorf(property, `"%v" may only be used at the start of the visibility rules`, v) 335 } 336 } else if ruleCount != 1 { 337 ctx.PropertyErrorf(property, "cannot mix %q with any other visibility rules", v) 338 continue 339 } 340 } 341 342 // If the current directory is not in the vendor tree then there are some additional 343 // restrictions on the rules. 344 if !isAncestor("vendor", currentPkg) { 345 if !isAllowedFromOutsideVendor(pkg, name) { 346 ctx.PropertyErrorf(property, 347 "%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+ 348 " targets within //vendor, they can only use //vendor:__subpackages__.", v) 349 continue 350 } 351 } 352 } 353} 354 355// Gathers the flattened visibility rules after defaults expansion, parses the visibility 356// properties, stores them in a map by qualifiedModuleName for retrieval during enforcement. 357// 358// See ../README.md#Visibility for information on the format of the visibility rules. 359func visibilityRuleGatherer(ctx BottomUpMutatorContext) { 360 m := ctx.Module() 361 362 qualifiedModuleId := m.qualifiedModuleId(ctx) 363 currentPkg := qualifiedModuleId.pkg 364 365 // Parse the visibility rules that control access to the module and store them by id 366 // for use when enforcing the rules. 367 var rule compositeRule 368 primaryProperty := m.base().primaryVisibilityProperty 369 if primaryProperty != nil { 370 if visibility := primaryProperty.getStrings(); visibility != nil { 371 rule = parseRules(ctx, currentPkg, primaryProperty.getName(), visibility) 372 } 373 } 374 ipr := implicitPartitionRules(ctx) 375 if rule != nil || ipr != nil { 376 moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, visibilityRulesForModule{ 377 rule: rule, 378 implicitPartitionRules: ipr, 379 }) 380 } 381} 382 383func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule { 384 rules := make(compositeRule, 0, len(visibility)) 385 hasPrivateRule := false 386 hasPublicRule := false 387 hasNonPrivateRule := false 388 for _, v := range visibility { 389 ok, pkg, name := splitRule(ctx, v, currentPkg, property) 390 if !ok { 391 continue 392 } 393 394 var r visibilityRule 395 isPrivateRule := false 396 if pkg == "visibility" { 397 switch name { 398 case "private": 399 r = privateRule{} 400 isPrivateRule = true 401 case "public": 402 r = publicRule{} 403 hasPublicRule = true 404 case "override": 405 // Discard all preceding rules and any state based on them. 406 rules = nil 407 hasPrivateRule = false 408 hasPublicRule = false 409 hasNonPrivateRule = false 410 // This does not actually create a rule so continue onto the next rule. 411 continue 412 default: 413 match := anyPartitionRegex.FindStringSubmatch(name) 414 if match != nil { 415 r = anyPartitionRule{ 416 partitionType: match[1], 417 } 418 } 419 } 420 } else { 421 switch name { 422 case "__pkg__": 423 r = packageRule{pkg} 424 case "__subpackages__": 425 r = subpackagesRule{pkg} 426 default: 427 ctx.PropertyErrorf(property, "invalid visibility pattern %q. Must match "+ 428 " //<package>:<scope>, //<package> or :<scope> "+ 429 "where <scope> is one of \"__pkg__\", \"__subpackages__\"", 430 v) 431 } 432 } 433 434 if isPrivateRule { 435 hasPrivateRule = true 436 } else { 437 hasNonPrivateRule = true 438 } 439 440 rules = append(rules, r) 441 } 442 443 if hasPrivateRule && hasNonPrivateRule { 444 ctx.PropertyErrorf("visibility", 445 "cannot mix \"//visibility:private\" with any other visibility rules") 446 return compositeRule{privateRule{}} 447 } 448 449 if hasPublicRule { 450 // Public overrides all other rules so just return it. 451 return compositeRule{publicRule{}} 452 } 453 454 return rules 455} 456 457func implicitPartitionRules(ctx BaseModuleContext) compositeRule { 458 var result compositeRule 459 if ctx.SocSpecific() { 460 result = append(result, anyPartitionRule{partitionType: "vendor"}) 461 } else if ctx.ProductSpecific() { 462 result = append(result, anyPartitionRule{partitionType: "product"}) 463 } else if ctx.Module().InstallInData() { 464 result = append(result, anyPartitionRule{partitionType: "data"}) 465 } else if ctx.SystemExtSpecific() { 466 result = append(result, anyPartitionRule{partitionType: "system_ext"}) 467 } else if ctx.DeviceSpecific() { 468 result = append(result, anyPartitionRule{partitionType: "odm"}) 469 } 470 return result 471} 472 473func isAllowedFromOutsideVendor(pkg string, name string) bool { 474 if pkg == "vendor" { 475 return name == "__subpackages__" 476 } 477 478 return !isAncestor("vendor", pkg) 479} 480 481func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, property string) (bool, string, string) { 482 // Make sure that the rule is of the correct format. 483 matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression) 484 if ruleExpression == "" || matches == nil { 485 // Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to 486 // ensure all the rules on this module are checked. 487 ctx.PropertyErrorf(property, 488 "invalid visibility pattern %q must match"+ 489 " //<package>:<scope>, //<package> or :<scope> "+ 490 "where <scope> is one of \"__pkg__\", \"__subpackages__\"", 491 ruleExpression) 492 return false, "", "" 493 } 494 495 // Extract the package and name. 496 pkg := matches[1] 497 name := matches[2] 498 499 // Normalize the short hands 500 if pkg == "" { 501 pkg = currentPkg 502 } 503 if name == "" { 504 name = "__pkg__" 505 } 506 507 return true, pkg, name 508} 509 510func visibilityRuleEnforcer(ctx TopDownMutatorContext) { 511 qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module()) 512 513 // Visit all the dependencies making sure that this module has access to them all. 514 ctx.VisitDirectDeps(func(dep Module) { 515 // Ignore dependencies that have an ExcludeFromVisibilityEnforcementTag 516 tag := ctx.OtherModuleDependencyTag(dep) 517 if _, ok := tag.(ExcludeFromVisibilityEnforcementTag); ok { 518 return 519 } 520 521 depName := ctx.OtherModuleName(dep) 522 depDir := ctx.OtherModuleDir(dep) 523 depQualified := qualifiedModuleName{depDir, depName} 524 525 // Targets are always visible to other targets in their own package. 526 if depQualified.pkg == qualified.name.pkg { 527 return 528 } 529 530 rule := effectiveVisibilityRules(ctx.Config(), depQualified) 531 if !rule.matches(qualified) { 532 ctx.ModuleErrorf("depends on %s which is not visible to this module\nYou may need to add %q to its visibility", depQualified, "//"+ctx.ModuleDir()) 533 } 534 }) 535} 536 537// Default visibility is public. 538var defaultVisibility = compositeRule{publicRule{}} 539 540// Return the effective visibility rules. 541// 542// If no rules have been specified this will return the default visibility rule 543// which is currently //visibility:public. 544func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule { 545 moduleToVisibilityRule := moduleToVisibilityRuleMap(config) 546 value := visibilityRulesForModule{} 547 if valueRaw, ok := moduleToVisibilityRule.Load(qualified); ok { 548 value = valueRaw.(visibilityRulesForModule) 549 } 550 var rule compositeRule 551 if value.rule != nil { 552 rule = value.rule 553 } else { 554 rule = packageDefaultVisibility(moduleToVisibilityRule, qualified) 555 } 556 557 // If no rule is specified then return the default visibility rule to avoid 558 // every caller having to treat nil as public. 559 if rule == nil { 560 rule = defaultVisibility 561 } 562 563 // If a partition rule wasn't specified, add implicit partition visibility 564 // rules based on the partition properties like vendor: true. 565 foundPartitionRule := false 566 for _, r := range rule { 567 if _, ok := r.(anyPartitionRule); ok { 568 foundPartitionRule = true 569 break 570 } 571 } 572 if !foundPartitionRule { 573 rule = append(rule, value.implicitPartitionRules...) 574 } 575 576 return rule 577} 578 579func createQualifiedModuleName(moduleName, dir string) qualifiedModuleName { 580 qualified := qualifiedModuleName{dir, moduleName} 581 return qualified 582} 583 584func packageDefaultVisibility(moduleToVisibilityRule *sync.Map, moduleId qualifiedModuleName) compositeRule { 585 packageQualifiedId := moduleId.getContainingPackageId() 586 for { 587 value, ok := moduleToVisibilityRule.Load(packageQualifiedId) 588 if ok { 589 return value.(visibilityRulesForModule).rule 590 } 591 592 if packageQualifiedId.isRootPackage() { 593 return nil 594 } 595 596 packageQualifiedId = packageQualifiedId.getContainingPackageId() 597 } 598} 599 600type VisibilityRuleSet interface { 601 // Widen the visibility with some extra rules. 602 Widen(extra []string) error 603 604 Strings() []string 605} 606 607type visibilityRuleSet struct { 608 rules []string 609} 610 611var _ VisibilityRuleSet = (*visibilityRuleSet)(nil) 612 613func (v *visibilityRuleSet) Widen(extra []string) error { 614 // Check the extra rules first just in case they are invalid. Otherwise, if 615 // the current visibility is public then the extra rules will just be ignored. 616 if len(extra) == 1 { 617 singularRule := extra[0] 618 switch singularRule { 619 case "//visibility:public": 620 // Public overrides everything so just discard any existing rules. 621 v.rules = extra 622 return nil 623 case "//visibility:private": 624 // Extending rule with private is an error. 625 return fmt.Errorf("%q does not widen the visibility", singularRule) 626 } 627 } 628 629 if len(v.rules) == 1 { 630 switch v.rules[0] { 631 case "//visibility:public": 632 // No point in adding rules to something which is already public. 633 return nil 634 case "//visibility:private": 635 // Adding any rules to private means it is no longer private so the 636 // private can be discarded. 637 v.rules = nil 638 } 639 } 640 641 v.rules = FirstUniqueStrings(append(v.rules, extra...)) 642 sort.Strings(v.rules) 643 return nil 644} 645 646func (v *visibilityRuleSet) Strings() []string { 647 return v.rules 648} 649 650// Get the effective visibility rules, i.e. the actual rules that affect the visibility of the 651// property irrespective of where they are defined. 652// 653// Includes visibility rules specified by package default_visibility and/or on defaults. 654// Short hand forms, e.g. //:__subpackages__ are replaced with their full form, e.g. 655// //package/containing/rule:__subpackages__. 656func EffectiveVisibilityRules(ctx BaseModuleContext, module Module) VisibilityRuleSet { 657 moduleName := ctx.OtherModuleName(module) 658 dir := ctx.OtherModuleDir(module) 659 qualified := qualifiedModuleName{dir, moduleName} 660 661 rule := effectiveVisibilityRules(ctx.Config(), qualified) 662 663 currentModule := createVisibilityModuleReference(moduleName, dir, module) 664 665 // Modules are implicitly visible to other modules in the same package, 666 // without checking the visibility rules. Here we need to add that visibility 667 // explicitly. 668 if !rule.matches(currentModule) { 669 if len(rule) == 1 { 670 if _, ok := rule[0].(privateRule); ok { 671 // If the rule is //visibility:private we can't append another 672 // visibility to it. Semantically we need to convert it to a package 673 // visibility rule for the location where the result is used, but since 674 // modules are implicitly visible within the package we get the same 675 // result without any rule at all, so just make it an empty list to be 676 // appended below. 677 rule = nil 678 } 679 } 680 rule = append(rule, packageRule{dir}) 681 } 682 683 return &visibilityRuleSet{rule.Strings()} 684} 685 686// Clear the default visibility properties so they can be replaced. 687func clearVisibilityProperties(module Module) { 688 module.base().visibilityPropertyInfo = nil 689} 690 691// Add a property that contains visibility rules so that they are checked for 692// correctness. 693func AddVisibilityProperty(module Module, name string, stringsProperty *[]string) { 694 addVisibilityProperty(module, name, stringsProperty) 695} 696 697func addVisibilityProperty(module Module, name string, stringsProperty *[]string) visibilityProperty { 698 base := module.base() 699 property := newVisibilityProperty(name, stringsProperty) 700 base.visibilityPropertyInfo = append(base.visibilityPropertyInfo, property) 701 return property 702} 703 704// Set the primary visibility property. 705// 706// Also adds the property to the list of properties to be validated. 707func setPrimaryVisibilityProperty(module Module, name string, stringsProperty *[]string) { 708 module.base().primaryVisibilityProperty = addVisibilityProperty(module, name, stringsProperty) 709} 710