eef4c1c563
Refactor notices to support notices for multiple modules. Enforce visibility and handle missing dependencies. Bug: 213388645 Change-Id: Id6a81987f087419ad37d0cce57a71e8a7c4cd6e0
341 lines
12 KiB
Go
341 lines
12 KiB
Go
// Copyright 2020 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package android
|
|
|
|
import (
|
|
"reflect"
|
|
"sync"
|
|
|
|
"github.com/google/blueprint"
|
|
)
|
|
|
|
// Adds cross-cutting licenses dependency to propagate license metadata through the build system.
|
|
//
|
|
// Stage 1 - bottom-up records package-level default_applicable_licenses property mapped by package name.
|
|
// Stage 2 - bottom-up converts licenses property or package default_applicable_licenses to dependencies.
|
|
// Stage 3 - bottom-up type-checks every added applicable license dependency and license_kind dependency.
|
|
// Stage 4 - GenerateBuildActions calculates properties for the union of license kinds, conditions and texts.
|
|
|
|
type licensesDependencyTag struct {
|
|
blueprint.BaseDependencyTag
|
|
}
|
|
|
|
func (l licensesDependencyTag) SdkMemberType(Module) SdkMemberType {
|
|
// Add the supplied module to the sdk as a license module.
|
|
return LicenseModuleSdkMemberType
|
|
}
|
|
|
|
func (l licensesDependencyTag) ExportMember() bool {
|
|
// The license module will only every be referenced from within the sdk. This will ensure that it
|
|
// gets a unique name and so avoid clashing with the original license module.
|
|
return false
|
|
}
|
|
|
|
var (
|
|
licensesTag = licensesDependencyTag{}
|
|
|
|
// License modules, i.e. modules depended upon via a licensesTag, must be automatically added to
|
|
// any sdk/module_exports to which their referencing module is a member.
|
|
_ SdkMemberDependencyTag = licensesTag
|
|
)
|
|
|
|
// Describes the property provided by a module to reference applicable licenses.
|
|
type applicableLicensesProperty interface {
|
|
// The name of the property. e.g. default_applicable_licenses or licenses
|
|
getName() string
|
|
// The values assigned to the property. (Must reference license modules.)
|
|
getStrings() []string
|
|
}
|
|
|
|
type applicableLicensesPropertyImpl struct {
|
|
name string
|
|
licensesProperty *[]string
|
|
}
|
|
|
|
func newApplicableLicensesProperty(name string, licensesProperty *[]string) applicableLicensesProperty {
|
|
return applicableLicensesPropertyImpl{
|
|
name: name,
|
|
licensesProperty: licensesProperty,
|
|
}
|
|
}
|
|
|
|
func (p applicableLicensesPropertyImpl) getName() string {
|
|
return p.name
|
|
}
|
|
|
|
func (p applicableLicensesPropertyImpl) getStrings() []string {
|
|
return *p.licensesProperty
|
|
}
|
|
|
|
// Set the primary applicable licenses property for a module.
|
|
func setPrimaryLicensesProperty(module Module, name string, licensesProperty *[]string) {
|
|
module.base().primaryLicensesProperty = newApplicableLicensesProperty(name, licensesProperty)
|
|
}
|
|
|
|
// Storage blob for a package's default_applicable_licenses mapped by package directory.
|
|
type licensesContainer struct {
|
|
licenses []string
|
|
}
|
|
|
|
func (r licensesContainer) getLicenses() []string {
|
|
return r.licenses
|
|
}
|
|
|
|
var packageDefaultLicensesMap = NewOnceKey("packageDefaultLicensesMap")
|
|
|
|
// The map from package dir name to default applicable licenses as a licensesContainer.
|
|
func moduleToPackageDefaultLicensesMap(config Config) *sync.Map {
|
|
return config.Once(packageDefaultLicensesMap, func() interface{} {
|
|
return &sync.Map{}
|
|
}).(*sync.Map)
|
|
}
|
|
|
|
// Registers the function that maps each package to its default_applicable_licenses.
|
|
//
|
|
// This goes before defaults expansion so the defaults can pick up the package default.
|
|
func RegisterLicensesPackageMapper(ctx RegisterMutatorsContext) {
|
|
ctx.BottomUp("licensesPackageMapper", licensesPackageMapper).Parallel()
|
|
}
|
|
|
|
// Registers the function that gathers the license dependencies for each module.
|
|
//
|
|
// This goes after defaults expansion so that it can pick up default licenses and before visibility enforcement.
|
|
func RegisterLicensesPropertyGatherer(ctx RegisterMutatorsContext) {
|
|
ctx.BottomUp("licensesPropertyGatherer", licensesPropertyGatherer).Parallel()
|
|
}
|
|
|
|
// Registers the function that verifies the licenses and license_kinds dependency types for each module.
|
|
func RegisterLicensesDependencyChecker(ctx RegisterMutatorsContext) {
|
|
ctx.BottomUp("licensesPropertyChecker", licensesDependencyChecker).Parallel()
|
|
}
|
|
|
|
// Maps each package to its default applicable licenses.
|
|
func licensesPackageMapper(ctx BottomUpMutatorContext) {
|
|
p, ok := ctx.Module().(*packageModule)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
licenses := getLicenses(ctx, p)
|
|
|
|
dir := ctx.ModuleDir()
|
|
c := makeLicensesContainer(licenses)
|
|
moduleToPackageDefaultLicensesMap(ctx.Config()).Store(dir, c)
|
|
}
|
|
|
|
// Copies the default_applicable_licenses property values for mapping by package directory.
|
|
func makeLicensesContainer(propVals []string) licensesContainer {
|
|
licenses := make([]string, 0, len(propVals))
|
|
licenses = append(licenses, propVals...)
|
|
|
|
return licensesContainer{licenses}
|
|
}
|
|
|
|
// Gathers the applicable licenses into dependency references after defaults expansion.
|
|
func licensesPropertyGatherer(ctx BottomUpMutatorContext) {
|
|
m, ok := ctx.Module().(Module)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if exemptFromRequiredApplicableLicensesProperty(m) {
|
|
return
|
|
}
|
|
|
|
licenses := getLicenses(ctx, m)
|
|
ctx.AddVariationDependencies(nil, licensesTag, licenses...)
|
|
}
|
|
|
|
// Verifies the license and license_kind dependencies are each the correct kind of module.
|
|
func licensesDependencyChecker(ctx BottomUpMutatorContext) {
|
|
m, ok := ctx.Module().(Module)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
// license modules have no licenses, but license_kinds must refer to license_kind modules
|
|
if _, ok := m.(*licenseModule); ok {
|
|
for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
|
|
if _, ok := module.(*licenseKindModule); !ok {
|
|
ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module))
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
if exemptFromRequiredApplicableLicensesProperty(m) {
|
|
return
|
|
}
|
|
|
|
for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
|
|
if _, ok := module.(*licenseModule); !ok {
|
|
propertyName := "licenses"
|
|
primaryProperty := m.base().primaryLicensesProperty
|
|
if primaryProperty != nil {
|
|
propertyName = primaryProperty.getName()
|
|
}
|
|
ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module))
|
|
}
|
|
}
|
|
}
|
|
|
|
// Flattens license and license_kind dependencies into calculated properties.
|
|
//
|
|
// Re-validates applicable licenses properties refer only to license modules and license_kinds properties refer
|
|
// only to license_kind modules.
|
|
func licensesPropertyFlattener(ctx ModuleContext) {
|
|
m, ok := ctx.Module().(Module)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
if exemptFromRequiredApplicableLicensesProperty(m) {
|
|
return
|
|
}
|
|
|
|
var licenses []string
|
|
for _, module := range ctx.GetDirectDepsWithTag(licensesTag) {
|
|
if l, ok := module.(*licenseModule); ok {
|
|
licenses = append(licenses, ctx.OtherModuleName(module))
|
|
if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil {
|
|
m.base().commonProperties.Effective_package_name = l.properties.Package_name
|
|
}
|
|
mergeStringProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...)
|
|
mergeNamedPathProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...)
|
|
mergeStringProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...)
|
|
mergeStringProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...)
|
|
} else {
|
|
propertyName := "licenses"
|
|
primaryProperty := m.base().primaryLicensesProperty
|
|
if primaryProperty != nil {
|
|
propertyName = primaryProperty.getName()
|
|
}
|
|
ctx.ModuleErrorf("%s property %q is not a license module", propertyName, ctx.OtherModuleName(module))
|
|
}
|
|
}
|
|
|
|
// Make the license information available for other modules.
|
|
licenseInfo := LicenseInfo{
|
|
Licenses: licenses,
|
|
}
|
|
ctx.SetProvider(LicenseInfoProvider, licenseInfo)
|
|
}
|
|
|
|
// Update a property string array with a distinct union of its values and a list of new values.
|
|
func mergeStringProps(prop *[]string, values ...string) {
|
|
*prop = append(*prop, values...)
|
|
*prop = SortedUniqueStrings(*prop)
|
|
}
|
|
|
|
// Update a property NamedPath array with a distinct union of its values and a list of new values.
|
|
func namePathProps(prop *NamedPaths, name *string, values ...Path) {
|
|
if name == nil {
|
|
for _, value := range values {
|
|
*prop = append(*prop, NamedPath{value, ""})
|
|
}
|
|
} else {
|
|
for _, value := range values {
|
|
*prop = append(*prop, NamedPath{value, *name})
|
|
}
|
|
}
|
|
*prop = SortedUniqueNamedPaths(*prop)
|
|
}
|
|
|
|
// Update a property NamedPath array with a distinct union of its values and a list of new values.
|
|
func mergeNamedPathProps(prop *NamedPaths, values ...NamedPath) {
|
|
*prop = append(*prop, values...)
|
|
*prop = SortedUniqueNamedPaths(*prop)
|
|
}
|
|
|
|
// Get the licenses property falling back to the package default.
|
|
func getLicenses(ctx BaseModuleContext, module Module) []string {
|
|
if exemptFromRequiredApplicableLicensesProperty(module) {
|
|
return nil
|
|
}
|
|
|
|
primaryProperty := module.base().primaryLicensesProperty
|
|
if primaryProperty == nil {
|
|
if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") {
|
|
ctx.ModuleErrorf("module type %q must have an applicable licenses property", ctx.OtherModuleType(module))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
licenses := primaryProperty.getStrings()
|
|
if len(licenses) > 0 {
|
|
s := make(map[string]bool)
|
|
for _, l := range licenses {
|
|
if _, ok := s[l]; ok {
|
|
ctx.ModuleErrorf("duplicate %q %s", l, primaryProperty.getName())
|
|
}
|
|
s[l] = true
|
|
}
|
|
return licenses
|
|
}
|
|
|
|
dir := ctx.OtherModuleDir(module)
|
|
|
|
moduleToApplicableLicenses := moduleToPackageDefaultLicensesMap(ctx.Config())
|
|
value, ok := moduleToApplicableLicenses.Load(dir)
|
|
var c licensesContainer
|
|
if ok {
|
|
c = value.(licensesContainer)
|
|
} else {
|
|
c = licensesContainer{}
|
|
}
|
|
return c.getLicenses()
|
|
}
|
|
|
|
// Returns whether a module is an allowed list of modules that do not have or need applicable licenses.
|
|
func exemptFromRequiredApplicableLicensesProperty(module Module) bool {
|
|
switch reflect.TypeOf(module).String() {
|
|
case "*android.licenseModule": // is a license, doesn't need one
|
|
case "*android.licenseKindModule": // is a license, doesn't need one
|
|
case "*android.genNoticeModule": // contains license texts as data
|
|
case "*android.NamespaceModule": // just partitions things, doesn't add anything
|
|
case "*android.soongConfigModuleTypeModule": // creates aliases for modules with licenses
|
|
case "*android.soongConfigModuleTypeImport": // creates aliases for modules with licenses
|
|
case "*android.soongConfigStringVariableDummyModule": // used for creating aliases
|
|
case "*android.soongConfigBoolVariableDummyModule": // used for creating aliases
|
|
default:
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// LicenseInfo contains information about licenses for a specific module.
|
|
type LicenseInfo struct {
|
|
// The list of license modules this depends upon, either explicitly or through default package
|
|
// configuration.
|
|
Licenses []string
|
|
}
|
|
|
|
var LicenseInfoProvider = blueprint.NewProvider(LicenseInfo{})
|
|
|
|
func init() {
|
|
RegisterMakeVarsProvider(pctx, licensesMakeVarsProvider)
|
|
}
|
|
|
|
func licensesMakeVarsProvider(ctx MakeVarsContext) {
|
|
ctx.Strict("BUILD_LICENSE_METADATA",
|
|
ctx.Config().HostToolPath(ctx, "build_license_metadata").String())
|
|
ctx.Strict("HTMLNOTICE", ctx.Config().HostToolPath(ctx, "htmlnotice").String())
|
|
ctx.Strict("XMLNOTICE", ctx.Config().HostToolPath(ctx, "xmlnotice").String())
|
|
ctx.Strict("TEXTNOTICE", ctx.Config().HostToolPath(ctx, "textnotice").String())
|
|
ctx.Strict("COMPLIANCENOTICE_BOM", ctx.Config().HostToolPath(ctx, "compliancenotice_bom").String())
|
|
ctx.Strict("COMPLIANCENOTICE_SHIPPEDLIBS", ctx.Config().HostToolPath(ctx, "compliancenotice_shippedlibs").String())
|
|
ctx.Strict("COMPLIANCE_LISTSHARE", ctx.Config().HostToolPath(ctx, "compliance_listshare").String())
|
|
ctx.Strict("COMPLIANCE_CHECKSHARE", ctx.Config().HostToolPath(ctx, "compliance_checkshare").String())
|
|
}
|