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