// 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.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()) }