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 "strings" 21 "sync" 22 23 "github.com/google/blueprint" 24) 25 26// Enforces visibility rules between modules. 27// 28// Multi stage process: 29// * First stage works bottom up, before defaults expansion, to check the syntax of the visibility 30// rules that have been specified. 31// 32// * Second stage works bottom up to extract the package info for each package and store them in a 33// map by package name. See package.go for functionality for this. 34// 35// * Third stage works bottom up to extract visibility information from the modules, parse it, 36// create visibilityRule structures and store them in a map keyed by the module's 37// qualifiedModuleName instance, i.e. //<pkg>:<name>. The map is stored in the context rather 38// than a global variable for testing. Each test has its own Config so they do not share a map 39// and so can be run in parallel. If a module has no visibility specified then it uses the 40// default package visibility if specified. 41// 42// * Fourth stage works top down and iterates over all the deps for each module. If the dep is in 43// the same package then it is automatically visible. Otherwise, for each dep it first extracts 44// its visibilityRule from the config map. If one could not be found then it assumes that it is 45// publicly visible. Otherwise, it calls the visibility rule to check that the module can see 46// the dependency. If it cannot then an error is reported. 47// 48// TODO(b/130631145) - Make visibility work properly with prebuilts. 49// TODO(b/130796911) - Make visibility work properly with defaults. 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 return strings.HasPrefix(p2+"/", p1+"/") 158} 159 160func (r subpackagesRule) String() string { 161 return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix) 162} 163 164// visibilityRule for //visibility:public 165type publicRule struct{} 166 167func (r publicRule) matches(_ qualifiedModuleName) bool { 168 return true 169} 170 171func (r publicRule) String() string { 172 return "//visibility:public" 173} 174 175// visibilityRule for //visibility:private 176type privateRule struct{} 177 178func (r privateRule) matches(_ qualifiedModuleName) bool { 179 return false 180} 181 182func (r privateRule) String() string { 183 return "//visibility:private" 184} 185 186var visibilityRuleMap = NewOnceKey("visibilityRuleMap") 187 188// The map from qualifiedModuleName to visibilityRule. 189func moduleToVisibilityRuleMap(config Config) *sync.Map { 190 return config.Once(visibilityRuleMap, func() interface{} { 191 return &sync.Map{} 192 }).(*sync.Map) 193} 194 195// Marker interface that identifies dependencies that are excluded from visibility 196// enforcement. 197type ExcludeFromVisibilityEnforcementTag interface { 198 blueprint.DependencyTag 199 200 // Method that differentiates this interface from others. 201 ExcludeFromVisibilityEnforcement() 202} 203 204// The rule checker needs to be registered before defaults expansion to correctly check that 205// //visibility:xxx isn't combined with other packages in the same list in any one module. 206func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) { 207 ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel() 208} 209 210// Registers the function that gathers the visibility rules for each module. 211// 212// Visibility is not dependent on arch so this must be registered before the arch phase to avoid 213// having to process multiple variants for each module. This goes after defaults expansion to gather 214// the complete visibility lists from flat lists and after the package info is gathered to ensure 215// that default_visibility is available. 216func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) { 217 ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel() 218} 219 220// This must be registered after the deps have been resolved. 221func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) { 222 ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel() 223} 224 225// Checks the per-module visibility rule lists before defaults expansion. 226func visibilityRuleChecker(ctx BottomUpMutatorContext) { 227 qualified := createQualifiedModuleName(ctx) 228 if m, ok := ctx.Module().(Module); ok { 229 visibilityProperties := m.visibilityProperties() 230 for _, p := range visibilityProperties { 231 if visibility := p.getStrings(); visibility != nil { 232 checkRules(ctx, qualified.pkg, p.getName(), visibility) 233 } 234 } 235 } 236} 237 238func checkRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) { 239 ruleCount := len(visibility) 240 if ruleCount == 0 { 241 // This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and 242 // it could mean public visibility. Requiring at least one rule makes the owner's intent 243 // clearer. 244 ctx.PropertyErrorf(property, "must contain at least one visibility rule") 245 return 246 } 247 248 for i, v := range visibility { 249 ok, pkg, name := splitRule(ctx, v, currentPkg, property) 250 if !ok { 251 continue 252 } 253 254 if pkg == "visibility" { 255 switch name { 256 case "private", "public": 257 case "legacy_public": 258 ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used") 259 continue 260 case "override": 261 // This keyword does not create a rule so pretend it does not exist. 262 ruleCount -= 1 263 default: 264 ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v) 265 continue 266 } 267 if name == "override" { 268 if i != 0 { 269 ctx.PropertyErrorf(property, `"%v" may only be used at the start of the visibility rules`, v) 270 } 271 } else if ruleCount != 1 { 272 ctx.PropertyErrorf(property, "cannot mix %q with any other visibility rules", v) 273 continue 274 } 275 } 276 277 // If the current directory is not in the vendor tree then there are some additional 278 // restrictions on the rules. 279 if !isAncestor("vendor", currentPkg) { 280 if !isAllowedFromOutsideVendor(pkg, name) { 281 ctx.PropertyErrorf(property, 282 "%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+ 283 " targets within //vendor, they can only use //vendor:__subpackages__.", v) 284 continue 285 } 286 } 287 } 288} 289 290// Gathers the flattened visibility rules after defaults expansion, parses the visibility 291// properties, stores them in a map by qualifiedModuleName for retrieval during enforcement. 292// 293// See ../README.md#Visibility for information on the format of the visibility rules. 294func visibilityRuleGatherer(ctx BottomUpMutatorContext) { 295 m, ok := ctx.Module().(Module) 296 if !ok { 297 return 298 } 299 300 qualifiedModuleId := m.qualifiedModuleId(ctx) 301 currentPkg := qualifiedModuleId.pkg 302 303 // Parse the visibility rules that control access to the module and store them by id 304 // for use when enforcing the rules. 305 primaryProperty := m.base().primaryVisibilityProperty 306 if primaryProperty != nil { 307 if visibility := primaryProperty.getStrings(); visibility != nil { 308 rule := parseRules(ctx, currentPkg, primaryProperty.getName(), visibility) 309 if rule != nil { 310 moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule) 311 } 312 } 313 } 314} 315 316func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule { 317 rules := make(compositeRule, 0, len(visibility)) 318 hasPrivateRule := false 319 hasPublicRule := false 320 hasNonPrivateRule := false 321 for _, v := range visibility { 322 ok, pkg, name := splitRule(ctx, v, currentPkg, property) 323 if !ok { 324 continue 325 } 326 327 var r visibilityRule 328 isPrivateRule := false 329 if pkg == "visibility" { 330 switch name { 331 case "private": 332 r = privateRule{} 333 isPrivateRule = true 334 case "public": 335 r = publicRule{} 336 hasPublicRule = true 337 case "override": 338 // Discard all preceding rules and any state based on them. 339 rules = nil 340 hasPrivateRule = false 341 hasPublicRule = false 342 hasNonPrivateRule = false 343 // This does not actually create a rule so continue onto the next rule. 344 continue 345 } 346 } else { 347 switch name { 348 case "__pkg__": 349 r = packageRule{pkg} 350 case "__subpackages__": 351 r = subpackagesRule{pkg} 352 default: 353 continue 354 } 355 } 356 357 if isPrivateRule { 358 hasPrivateRule = true 359 } else { 360 hasNonPrivateRule = true 361 } 362 363 rules = append(rules, r) 364 } 365 366 if hasPrivateRule && hasNonPrivateRule { 367 ctx.PropertyErrorf("visibility", 368 "cannot mix \"//visibility:private\" with any other visibility rules") 369 return compositeRule{privateRule{}} 370 } 371 372 if hasPublicRule { 373 // Public overrides all other rules so just return it. 374 return compositeRule{publicRule{}} 375 } 376 377 return rules 378} 379 380func isAllowedFromOutsideVendor(pkg string, name string) bool { 381 if pkg == "vendor" { 382 if name == "__subpackages__" { 383 return true 384 } 385 return false 386 } 387 388 return !isAncestor("vendor", pkg) 389} 390 391func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg, property string) (bool, string, string) { 392 // Make sure that the rule is of the correct format. 393 matches := visibilityRuleRegexp.FindStringSubmatch(ruleExpression) 394 if ruleExpression == "" || matches == nil { 395 // Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to 396 // ensure all the rules on this module are checked. 397 ctx.PropertyErrorf(property, 398 "invalid visibility pattern %q must match"+ 399 " //<package>:<module>, //<package> or :<module>", 400 ruleExpression) 401 return false, "", "" 402 } 403 404 // Extract the package and name. 405 pkg := matches[1] 406 name := matches[2] 407 408 // Normalize the short hands 409 if pkg == "" { 410 pkg = currentPkg 411 } 412 if name == "" { 413 name = "__pkg__" 414 } 415 416 return true, pkg, name 417} 418 419func visibilityRuleEnforcer(ctx TopDownMutatorContext) { 420 if _, ok := ctx.Module().(Module); !ok { 421 return 422 } 423 424 qualified := createQualifiedModuleName(ctx) 425 426 // Visit all the dependencies making sure that this module has access to them all. 427 ctx.VisitDirectDeps(func(dep Module) { 428 // Ignore dependencies that have an ExcludeFromVisibilityEnforcementTag 429 tag := ctx.OtherModuleDependencyTag(dep) 430 if _, ok := tag.(ExcludeFromVisibilityEnforcementTag); ok { 431 return 432 } 433 434 depName := ctx.OtherModuleName(dep) 435 depDir := ctx.OtherModuleDir(dep) 436 depQualified := qualifiedModuleName{depDir, depName} 437 438 // Targets are always visible to other targets in their own package. 439 if depQualified.pkg == qualified.pkg { 440 return 441 } 442 443 rule := effectiveVisibilityRules(ctx.Config(), depQualified) 444 if rule != nil && !rule.matches(qualified) { 445 ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified) 446 } 447 }) 448} 449 450func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule { 451 moduleToVisibilityRule := moduleToVisibilityRuleMap(config) 452 value, ok := moduleToVisibilityRule.Load(qualified) 453 var rule compositeRule 454 if ok { 455 rule = value.(compositeRule) 456 } else { 457 rule = packageDefaultVisibility(config, qualified) 458 } 459 return rule 460} 461 462func createQualifiedModuleName(ctx BaseModuleContext) qualifiedModuleName { 463 moduleName := ctx.ModuleName() 464 dir := ctx.ModuleDir() 465 qualified := qualifiedModuleName{dir, moduleName} 466 return qualified 467} 468 469func packageDefaultVisibility(config Config, moduleId qualifiedModuleName) compositeRule { 470 moduleToVisibilityRule := moduleToVisibilityRuleMap(config) 471 packageQualifiedId := moduleId.getContainingPackageId() 472 for { 473 value, ok := moduleToVisibilityRule.Load(packageQualifiedId) 474 if ok { 475 return value.(compositeRule) 476 } 477 478 if packageQualifiedId.isRootPackage() { 479 return nil 480 } 481 482 packageQualifiedId = packageQualifiedId.getContainingPackageId() 483 } 484} 485 486// Get the effective visibility rules, i.e. the actual rules that affect the visibility of the 487// property irrespective of where they are defined. 488// 489// Includes visibility rules specified by package default_visibility and/or on defaults. 490// Short hand forms, e.g. //:__subpackages__ are replaced with their full form, e.g. 491// //package/containing/rule:__subpackages__. 492func EffectiveVisibilityRules(ctx BaseModuleContext, module Module) []string { 493 moduleName := ctx.OtherModuleName(module) 494 dir := ctx.OtherModuleDir(module) 495 qualified := qualifiedModuleName{dir, moduleName} 496 497 rule := effectiveVisibilityRules(ctx.Config(), qualified) 498 499 // Modules are implicitly visible to other modules in the same package, 500 // without checking the visibility rules. Here we need to add that visibility 501 // explicitly. 502 if rule != nil && !rule.matches(qualified) { 503 if len(rule) == 1 { 504 if _, ok := rule[0].(privateRule); ok { 505 // If the rule is //visibility:private we can't append another 506 // visibility to it. Semantically we need to convert it to a package 507 // visibility rule for the location where the result is used, but since 508 // modules are implicitly visible within the package we get the same 509 // result without any rule at all, so just make it an empty list to be 510 // appended below. 511 rule = compositeRule{} 512 } 513 } 514 rule = append(rule, packageRule{dir}) 515 } 516 517 return rule.Strings() 518} 519 520// Clear the default visibility properties so they can be replaced. 521func clearVisibilityProperties(module Module) { 522 module.base().visibilityPropertyInfo = nil 523} 524 525// Add a property that contains visibility rules so that they are checked for 526// correctness. 527func AddVisibilityProperty(module Module, name string, stringsProperty *[]string) { 528 addVisibilityProperty(module, name, stringsProperty) 529} 530 531func addVisibilityProperty(module Module, name string, stringsProperty *[]string) visibilityProperty { 532 base := module.base() 533 property := newVisibilityProperty(name, stringsProperty) 534 base.visibilityPropertyInfo = append(base.visibilityPropertyInfo, property) 535 return property 536} 537 538// Set the primary visibility property. 539// 540// Also adds the property to the list of properties to be validated. 541func setPrimaryVisibilityProperty(module Module, name string, stringsProperty *[]string) { 542 module.base().primaryVisibilityProperty = addVisibilityProperty(module, name, stringsProperty) 543} 544