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