1// Copyright 2020 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 "path/filepath" 20 "reflect" 21 "strings" 22 "sync" 23 24 "github.com/google/blueprint" 25) 26 27// Adds cross-cutting licenses dependency to propagate license metadata through the build system. 28// 29// Stage 1 - bottom-up records package-level default_applicable_licenses property mapped by package name. 30// Stage 2 - bottom-up converts licenses property or package default_applicable_licenses to dependencies. 31// Stage 3 - bottom-up type-checks every added applicable license dependency and license_kind dependency. 32// Stage 4 - GenerateBuildActions calculates properties for the union of license kinds, conditions and texts. 33 34type licensesDependencyTag struct { 35 blueprint.BaseDependencyTag 36} 37 38func (l licensesDependencyTag) SdkMemberType(Module) SdkMemberType { 39 // Add the supplied module to the sdk as a license module. 40 return LicenseModuleSdkMemberType 41} 42 43func (l licensesDependencyTag) ExportMember() bool { 44 // The license module will only every be referenced from within the sdk. This will ensure that it 45 // gets a unique name and so avoid clashing with the original license module. 46 return false 47} 48 49var ( 50 licensesTag = licensesDependencyTag{} 51 52 // License modules, i.e. modules depended upon via a licensesTag, must be automatically added to 53 // any sdk/module_exports to which their referencing module is a member. 54 _ SdkMemberDependencyTag = licensesTag 55) 56 57// Describes the property provided by a module to reference applicable licenses. 58type applicableLicensesProperty interface { 59 // The name of the property. e.g. default_applicable_licenses or licenses 60 getName() string 61 // The values assigned to the property. (Must reference license modules.) 62 getStrings() []string 63} 64 65type applicableLicensesPropertyImpl struct { 66 name string 67 licensesProperty *[]string 68} 69 70func newApplicableLicensesProperty(name string, licensesProperty *[]string) applicableLicensesProperty { 71 return applicableLicensesPropertyImpl{ 72 name: name, 73 licensesProperty: licensesProperty, 74 } 75} 76 77func (p applicableLicensesPropertyImpl) getName() string { 78 return p.name 79} 80 81func (p applicableLicensesPropertyImpl) getStrings() []string { 82 return *p.licensesProperty 83} 84 85// Set the primary applicable licenses property for a module. 86func setPrimaryLicensesProperty(module Module, name string, licensesProperty *[]string) { 87 module.base().primaryLicensesProperty = newApplicableLicensesProperty(name, licensesProperty) 88} 89 90// Storage blob for a package's default_applicable_licenses mapped by package directory. 91type licensesContainer struct { 92 licenses []string 93} 94 95func (r licensesContainer) getLicenses() []string { 96 return r.licenses 97} 98 99var packageDefaultLicensesMap = NewOnceKey("packageDefaultLicensesMap") 100 101// The map from package dir name to default applicable licenses as a licensesContainer. 102func moduleToPackageDefaultLicensesMap(config Config) *sync.Map { 103 return config.Once(packageDefaultLicensesMap, func() interface{} { 104 return &sync.Map{} 105 }).(*sync.Map) 106} 107 108// Registers the function that maps each package to its default_applicable_licenses. 109// 110// This goes before defaults expansion so the defaults can pick up the package default. 111func RegisterLicensesPackageMapper(ctx RegisterMutatorsContext) { 112 ctx.BottomUp("licensesPackageMapper", licensesPackageMapper) 113} 114 115// Registers the function that gathers the license dependencies for each module. 116// 117// This goes after defaults expansion so that it can pick up default licenses and before visibility enforcement. 118func RegisterLicensesPropertyGatherer(ctx RegisterMutatorsContext) { 119 ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer) 120} 121 122// Registers the function that verifies the licenses and license_kinds dependency types for each module. 123func RegisterLicensesDependencyChecker(ctx RegisterMutatorsContext) { 124 ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker) 125} 126 127// Maps each package to its default applicable licenses. 128func licensesPackageMapper(ctx BottomUpMutatorContext) { 129 p, ok := ctx.Module().(*packageModule) 130 if !ok { 131 return 132 } 133 134 licenses := getLicenses(ctx, p) 135 136 dir := ctx.ModuleDir() 137 c := makeLicensesContainer(licenses) 138 moduleToPackageDefaultLicensesMap(ctx.Config()).Store(dir, c) 139} 140 141// Copies the default_applicable_licenses property values for mapping by package directory. 142func makeLicensesContainer(propVals []string) licensesContainer { 143 licenses := make([]string, 0, len(propVals)) 144 licenses = append(licenses, propVals...) 145 146 return licensesContainer{licenses} 147} 148 149// Gathers the applicable licenses into dependency references after defaults expansion. 150func licensesPropertyGatherer(ctx BottomUpMutatorContext) { 151 m, ok := ctx.Module().(Module) 152 if !ok { 153 return 154 } 155 156 if exemptFromRequiredApplicableLicensesProperty(m) { 157 return 158 } 159 160 licenses := getLicenses(ctx, m) 161 162 var fullyQualifiedLicenseNames []string 163 for _, license := range licenses { 164 fullyQualifiedLicenseName := license 165 if !strings.HasPrefix(license, "//") { 166 licenseModuleDir := ctx.OtherModuleDir(m) 167 for licenseModuleDir != "." && !ctx.OtherModuleExists(fmt.Sprintf("//%s:%s", licenseModuleDir, license)) { 168 licenseModuleDir = filepath.Dir(licenseModuleDir) 169 } 170 if licenseModuleDir == "." { 171 fullyQualifiedLicenseName = license 172 } else { 173 fullyQualifiedLicenseName = fmt.Sprintf("//%s:%s", licenseModuleDir, license) 174 } 175 } 176 fullyQualifiedLicenseNames = append(fullyQualifiedLicenseNames, fullyQualifiedLicenseName) 177 } 178 179 ctx.AddVariationDependencies(nil, licensesTag, fullyQualifiedLicenseNames...) 180} 181 182// Verifies the license and license_kind dependencies are each the correct kind of module. 183func licensesDependencyChecker(ctx BottomUpMutatorContext) { 184 m, ok := ctx.Module().(Module) 185 if !ok { 186 return 187 } 188 189 // license modules have no licenses, but license_kinds must refer to license_kind modules 190 if _, ok := m.(*licenseModule); ok { 191 for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) { 192 if _, ok := module.(*licenseKindModule); !ok { 193 ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module)) 194 } 195 } 196 return 197 } 198 199 if exemptFromRequiredApplicableLicensesProperty(m) { 200 return 201 } 202 203 for _, module := range ctx.GetDirectDepsWithTag(licensesTag) { 204 if _, ok := module.(*licenseModule); !ok { 205 propertyName := "licenses" 206 primaryProperty := m.base().primaryLicensesProperty 207 if primaryProperty != nil { 208 propertyName = primaryProperty.getName() 209 } 210 ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module)) 211 } 212 } 213} 214 215// Flattens license and license_kind dependencies into calculated properties. 216// 217// Re-validates applicable licenses properties refer only to license modules and license_kinds properties refer 218// only to license_kind modules. 219func licensesPropertyFlattener(ctx ModuleContext) { 220 m, ok := ctx.Module().(Module) 221 if !ok { 222 return 223 } 224 225 if exemptFromRequiredApplicableLicensesProperty(m) { 226 return 227 } 228 229 var licenses []string 230 for _, module := range ctx.GetDirectDepsWithTag(licensesTag) { 231 if l, ok := module.(*licenseModule); ok { 232 licenses = append(licenses, ctx.OtherModuleName(module)) 233 if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil { 234 m.base().commonProperties.Effective_package_name = l.properties.Package_name 235 } 236 mergeStringProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...) 237 mergeNamedPathProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...) 238 mergeStringProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...) 239 mergeStringProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...) 240 } else { 241 propertyName := "licenses" 242 primaryProperty := m.base().primaryLicensesProperty 243 if primaryProperty != nil { 244 propertyName = primaryProperty.getName() 245 } 246 ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module)) 247 } 248 } 249 250 // Make the license information available for other modules. 251 licenseInfo := LicenseInfo{ 252 Licenses: licenses, 253 } 254 SetProvider(ctx, LicenseInfoProvider, licenseInfo) 255} 256 257// Update a property string array with a distinct union of its values and a list of new values. 258func mergeStringProps(prop *[]string, values ...string) { 259 *prop = append(*prop, values...) 260 *prop = SortedUniqueStrings(*prop) 261} 262 263// Update a property NamedPath array with a distinct union of its values and a list of new values. 264func namePathProps(prop *NamedPaths, name *string, values ...Path) { 265 if name == nil { 266 for _, value := range values { 267 *prop = append(*prop, NamedPath{value, ""}) 268 } 269 } else { 270 for _, value := range values { 271 *prop = append(*prop, NamedPath{value, *name}) 272 } 273 } 274 *prop = SortedUniqueNamedPaths(*prop) 275} 276 277// Update a property NamedPath array with a distinct union of its values and a list of new values. 278func mergeNamedPathProps(prop *NamedPaths, values ...NamedPath) { 279 *prop = append(*prop, values...) 280 *prop = SortedUniqueNamedPaths(*prop) 281} 282 283// Get the licenses property falling back to the package default. 284func getLicenses(ctx BaseModuleContext, module Module) []string { 285 if exemptFromRequiredApplicableLicensesProperty(module) { 286 return nil 287 } 288 289 primaryProperty := module.base().primaryLicensesProperty 290 if primaryProperty == nil { 291 if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") { 292 ctx.ModuleErrorf("module type %q must have an applicable licenses property", ctx.OtherModuleType(module)) 293 } 294 return nil 295 } 296 297 licenses := primaryProperty.getStrings() 298 if len(licenses) > 0 { 299 s := make(map[string]bool) 300 for _, l := range licenses { 301 if _, ok := s[l]; ok { 302 ctx.ModuleErrorf("duplicate %q %s", l, primaryProperty.getName()) 303 } 304 s[l] = true 305 } 306 return licenses 307 } 308 309 dir := ctx.OtherModuleDir(module) 310 311 moduleToApplicableLicenses := moduleToPackageDefaultLicensesMap(ctx.Config()) 312 value, ok := moduleToApplicableLicenses.Load(dir) 313 var c licensesContainer 314 if ok { 315 c = value.(licensesContainer) 316 } else { 317 c = licensesContainer{} 318 } 319 return c.getLicenses() 320} 321 322// Returns whether a module is an allowed list of modules that do not have or need applicable licenses. 323func exemptFromRequiredApplicableLicensesProperty(module Module) bool { 324 switch reflect.TypeOf(module).String() { 325 case "*android.licenseModule": // is a license, doesn't need one 326 case "*android.licenseKindModule": // is a license, doesn't need one 327 case "*android.genNoticeModule": // contains license texts as data 328 case "*android.NamespaceModule": // just partitions things, doesn't add anything 329 case "*android.soongConfigModuleTypeModule": // creates aliases for modules with licenses 330 case "*android.soongConfigModuleTypeImport": // creates aliases for modules with licenses 331 case "*android.soongConfigStringVariableDummyModule": // used for creating aliases 332 case "*android.soongConfigBoolVariableDummyModule": // used for creating aliases 333 default: 334 return false 335 } 336 return true 337} 338 339// LicenseInfo contains information about licenses for a specific module. 340type LicenseInfo struct { 341 // The list of license modules this depends upon, either explicitly or through default package 342 // configuration. 343 Licenses []string 344} 345 346var LicenseInfoProvider = blueprint.NewProvider[LicenseInfo]() 347 348func init() { 349 RegisterMakeVarsProvider(pctx, licensesMakeVarsProvider) 350} 351 352func licensesMakeVarsProvider(ctx MakeVarsContext) { 353 ctx.Strict("BUILD_LICENSE_METADATA", 354 ctx.Config().HostToolPath(ctx, "build_license_metadata").String()) 355 ctx.Strict("COPY_LICENSE_METADATA", 356 ctx.Config().HostToolPath(ctx, "copy_license_metadata").String()) 357 ctx.Strict("HTMLNOTICE", ctx.Config().HostToolPath(ctx, "htmlnotice").String()) 358 ctx.Strict("XMLNOTICE", ctx.Config().HostToolPath(ctx, "xmlnotice").String()) 359 ctx.Strict("TEXTNOTICE", ctx.Config().HostToolPath(ctx, "textnotice").String()) 360 ctx.Strict("COMPLIANCENOTICE_BOM", ctx.Config().HostToolPath(ctx, "compliancenotice_bom").String()) 361 ctx.Strict("COMPLIANCENOTICE_SHIPPEDLIBS", ctx.Config().HostToolPath(ctx, "compliancenotice_shippedlibs").String()) 362 ctx.Strict("COMPLIANCE_LISTSHARE", ctx.Config().HostToolPath(ctx, "compliance_listshare").String()) 363 ctx.Strict("COMPLIANCE_CHECKSHARE", ctx.Config().HostToolPath(ctx, "compliance_checkshare").String()) 364 ctx.Strict("COMPLIANCE_SBOM", ctx.Config().HostToolPath(ctx, "compliance_sbom").String()) 365} 366