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