Merge changes from topic "metalics"

* changes:
  Define the standard license_kind rules.
  Export soong license data to make.
  Add ability to declare licenses in soong.
This commit is contained in:
Bob Badour 2021-01-06 18:08:07 +00:00 committed by Gerrit Code Review
commit 659f11fcfc
20 changed files with 3139 additions and 10 deletions

View File

@ -30,6 +30,9 @@ bootstrap_go_package {
"filegroup.go",
"hooks.go",
"image.go",
"license.go",
"license_kind.go",
"licenses.go",
"makefile_goal.go",
"makevars.go",
"metrics.go",
@ -77,6 +80,9 @@ bootstrap_go_package {
"depset_test.go",
"deptag_test.go",
"expand_test.go",
"license_kind_test.go",
"license_test.go",
"licenses_test.go",
"module_test.go",
"mutator_test.go",
"namespace_test.go",

View File

@ -28,6 +28,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
@ -434,6 +435,17 @@ func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string {
return generateDistContributionsForMake(distContributions)
}
// Write the license variables to Make for AndroidMkData.Custom(..) methods that do not call WriteAndroidMkData(..)
// It's required to propagate the license metadata even for module types that have non-standard interfaces to Make.
func (a *AndroidMkEntries) WriteLicenseVariables(w io.Writer) {
fmt.Fprintln(w, "LOCAL_LICENSE_KINDS :=", strings.Join(a.EntryMap["LOCAL_LICENSE_KINDS"], " "))
fmt.Fprintln(w, "LOCAL_LICENSE_CONDITIONS :=", strings.Join(a.EntryMap["LOCAL_LICENSE_CONDITIONS"], " "))
fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", strings.Join(a.EntryMap["LOCAL_NOTICE_FILE"], " "))
if pn, ok := a.EntryMap["LOCAL_LICENSE_PACKAGE_NAME"]; ok {
fmt.Fprintln(w, "LOCAL_LICENSE_PACKAGE_NAME :=", strings.Join(pn, " "))
}
}
// fillInEntries goes through the common variable processing and calls the extra data funcs to
// generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file.
func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
@ -460,6 +472,13 @@ func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod bluep
// Collect make variable assignment entries.
a.SetString("LOCAL_PATH", filepath.Dir(bpPath))
a.SetString("LOCAL_MODULE", name+a.SubName)
a.AddStrings("LOCAL_LICENSE_KINDS", amod.commonProperties.Effective_license_kinds...)
a.AddStrings("LOCAL_LICENSE_CONDITIONS", amod.commonProperties.Effective_license_conditions...)
a.AddStrings("LOCAL_NOTICE_FILE", amod.commonProperties.Effective_license_text...)
// TODO(b/151177513): Does this code need to set LOCAL_MODULE_IS_CONTAINER ?
if amod.commonProperties.Effective_package_name != nil {
a.SetString("LOCAL_LICENSE_PACKAGE_NAME", *amod.commonProperties.Effective_package_name)
}
a.SetString("LOCAL_MODULE_CLASS", a.Class)
a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
@ -682,6 +701,7 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.M
}
}()
// Additional cases here require review for correct license propagation to make.
switch x := mod.(type) {
case AndroidMkDataProvider:
return translateAndroidModule(ctx, w, mod, x)
@ -690,6 +710,7 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.M
case AndroidMkEntriesProvider:
return translateAndroidMkEntriesModule(ctx, w, mod, x)
default:
// Not exported to make so no make variables to set.
return nil
}
}
@ -703,6 +724,10 @@ func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Mo
fmt.Fprintln(w, ".PHONY:", name)
fmt.Fprintln(w, name+":", goBinary.InstallPath())
fmt.Fprintln(w, "")
// Assuming no rules in make include go binaries in distributables.
// If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files.
// In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for
// `goBinary.InstallPath()` pointing to the `name`.meta_lic file.
return nil
}
@ -768,6 +793,25 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Mod
blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
if data.Custom != nil {
// List of module types allowed to use .Custom(...)
// Additions to the list require careful review for proper license handling.
switch reflect.TypeOf(mod).String() { // ctx.ModuleType(mod) doesn't work: aidl_interface creates phony without type
case "*aidl.aidlApi": // writes non-custom before adding .phony
case "*aidl.aidlMapping": // writes non-custom before adding .phony
case "*android.customModule": // appears in tests only
case "*apex.apexBundle": // license properties written
case "*bpf.bpf": // license properties written (both for module and objs)
case "*genrule.Module": // writes non-custom before adding .phony
case "*java.SystemModules": // doesn't go through base_rules
case "*java.systemModulesImport": // doesn't go through base_rules
case "*phony.phony": // license properties written
case "*selinux.selinuxContextsModule": // license properties written
case "*sysprop.syspropLibrary": // license properties written
default:
if ctx.Config().IsEnvTrue("ANDROID_REQUIRE_LICENSES") {
return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod))
}
}
data.Custom(w, name, prefix, blueprintDir, data)
} else {
WriteAndroidMkData(w, data)
@ -804,6 +848,7 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blue
return nil
}
// Any new or special cases here need review to verify correct propagation of license information.
for _, entries := range provider.AndroidMkEntries() {
entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
entries.write(w)

View File

@ -204,6 +204,9 @@ func InitDefaultsModule(module DefaultsModule) {
// its checking phase and parsing phase so add it to the list as a normal property.
AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
// The applicable licenses property for defaults is 'licenses'.
setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
base.module = module
}

82
android/license.go Normal file
View File

@ -0,0 +1,82 @@
// 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 (
"github.com/google/blueprint"
)
type licenseKindDependencyTag struct {
blueprint.BaseDependencyTag
}
var (
licenseKindTag = licenseKindDependencyTag{}
)
func init() {
RegisterLicenseBuildComponents(InitRegistrationContext)
}
// Register the license module type.
func RegisterLicenseBuildComponents(ctx RegistrationContext) {
ctx.RegisterModuleType("license", LicenseFactory)
}
type licenseProperties struct {
// Specifies the kinds of license that apply.
License_kinds []string
// Specifies a short copyright notice to use for the license.
Copyright_notice *string
// Specifies the path or label for the text of the license.
License_text []string `android:"path"`
// Specifies the package name to which the license applies.
Package_name *string
// Specifies where this license can be used
Visibility []string
}
type licenseModule struct {
ModuleBase
DefaultableModuleBase
properties licenseProperties
}
func (m *licenseModule) DepsMutator(ctx BottomUpMutatorContext) {
ctx.AddVariationDependencies(nil, licenseKindTag, m.properties.License_kinds...)
}
func (m *licenseModule) GenerateAndroidBuildActions(ctx ModuleContext) {
// Nothing to do.
}
func LicenseFactory() Module {
module := &licenseModule{}
base := module.base()
module.AddProperties(&base.nameProperties, &module.properties)
base.generalProperties = module.GetProperties()
base.customizableProperties = module.GetProperties()
// The visibility property needs to be checked and parsed by the visibility module.
setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
initAndroidModuleBase(module)
InitDefaultableModule(module)
return module
}

66
android/license_kind.go Normal file
View File

@ -0,0 +1,66 @@
// 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
func init() {
RegisterLicenseKindBuildComponents(InitRegistrationContext)
}
// Register the license_kind module type.
func RegisterLicenseKindBuildComponents(ctx RegistrationContext) {
ctx.RegisterModuleType("license_kind", LicenseKindFactory)
}
type licenseKindProperties struct {
// Specifies the conditions for all licenses of the kind.
Conditions []string
// Specifies the url to the canonical license definition.
Url string
// Specifies where this license can be used
Visibility []string
}
type licenseKindModule struct {
ModuleBase
DefaultableModuleBase
properties licenseKindProperties
}
func (m *licenseKindModule) DepsMutator(ctx BottomUpMutatorContext) {
// Nothing to do.
}
func (m *licenseKindModule) GenerateAndroidBuildActions(ModuleContext) {
// Nothing to do.
}
func LicenseKindFactory() Module {
module := &licenseKindModule{}
base := module.base()
module.AddProperties(&base.nameProperties, &module.properties)
base.generalProperties = module.GetProperties()
base.customizableProperties = module.GetProperties()
// The visibility property needs to be checked and parsed by the visibility module.
setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
initAndroidModuleBase(module)
InitDefaultableModule(module)
return module
}

View File

@ -0,0 +1,174 @@
package android
import (
"testing"
"github.com/google/blueprint"
)
var licenseKindTests = []struct {
name string
fs map[string][]byte
expectedErrors []string
}{
{
name: "license_kind must not accept licenses property",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "top_license",
licenses: ["other_license"],
}`),
},
expectedErrors: []string{
`top/Blueprints:4:14: unrecognized property "licenses"`,
},
},
{
name: "bad license_kind",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "top_notice",
conditions: ["notice"],
}`),
"other/Blueprints": []byte(`
mock_license {
name: "other_notice",
license_kinds: ["notice"],
}`),
},
expectedErrors: []string{
`other/Blueprints:2:5: "other_notice" depends on undefined module "notice"`,
},
},
{
name: "good license kind",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "top_by_exception_only",
conditions: ["by_exception_only"],
}
mock_license {
name: "top_proprietary",
license_kinds: ["top_by_exception_only"],
}`),
"other/Blueprints": []byte(`
mock_license {
name: "other_proprietary",
license_kinds: ["top_proprietary"],
}`),
},
},
{
name: "multiple license kinds",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "top_notice",
conditions: ["notice"],
}
license_kind {
name: "top_by_exception_only",
conditions: ["by_exception_only"],
}
mock_license {
name: "top_allowed_as_notice",
license_kinds: ["top_notice"],
}
mock_license {
name: "top_proprietary",
license_kinds: ["top_by_exception_only"],
}`),
"other/Blueprints": []byte(`
mock_license {
name: "other_rule",
license_kinds: ["top_by_exception_only"],
}`),
},
},
}
func TestLicenseKind(t *testing.T) {
for _, test := range licenseKindTests {
t.Run(test.name, func(t *testing.T) {
_, errs := testLicenseKind(test.fs)
expectedErrors := test.expectedErrors
if expectedErrors == nil {
FailIfErrored(t, errs)
} else {
for _, expectedError := range expectedErrors {
FailIfNoMatchingErrors(t, expectedError, errs)
}
if len(errs) > len(expectedErrors) {
t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
for i, expectedError := range expectedErrors {
t.Errorf("expectedErrors[%d] = %s", i, expectedError)
}
for i, err := range errs {
t.Errorf("errs[%d] = %s", i, err)
}
}
}
})
}
}
func testLicenseKind(fs map[string][]byte) (*TestContext, []error) {
// Create a new config per test as license_kind information is stored in the config.
config := TestArchConfig(buildDir, nil, "", fs)
ctx := NewTestArchContext(config)
RegisterLicenseKindBuildComponents(ctx)
ctx.RegisterModuleType("mock_license", newMockLicenseModule)
ctx.Register()
_, errs := ctx.ParseBlueprintsFiles(".")
if len(errs) > 0 {
return ctx, errs
}
_, errs = ctx.PrepareBuildActions(config)
return ctx, errs
}
type mockLicenseProperties struct {
License_kinds []string
}
type mockLicenseModule struct {
ModuleBase
DefaultableModuleBase
properties mockLicenseProperties
}
func newMockLicenseModule() Module {
m := &mockLicenseModule{}
m.AddProperties(&m.properties)
InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
InitDefaultableModule(m)
return m
}
type licensekindTag struct {
blueprint.BaseDependencyTag
}
func (j *mockLicenseModule) DepsMutator(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
return
}
ctx.AddDependency(m, licensekindTag{}, j.properties.License_kinds...)
}
func (p *mockLicenseModule) GenerateAndroidBuildActions(ModuleContext) {
}

233
android/license_test.go Normal file
View File

@ -0,0 +1,233 @@
package android
import (
"testing"
)
var licenseTests = []struct {
name string
fs map[string][]byte
expectedErrors []string
}{
{
name: "license must not accept licenses property",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license {
name: "top_license",
visibility: ["//visibility:private"],
licenses: ["other_license"],
}`),
},
expectedErrors: []string{
`top/Blueprints:5:14: unrecognized property "licenses"`,
},
},
{
name: "private license",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "top_notice",
conditions: ["notice"],
visibility: ["//visibility:private"],
}
license {
name: "top_allowed_as_notice",
license_kinds: ["top_notice"],
visibility: ["//visibility:private"],
}`),
"other/Blueprints": []byte(`
rule {
name: "arule",
licenses: ["top_allowed_as_notice"],
}`),
"yetmore/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_allowed_as_notice"],
}`),
},
expectedErrors: []string{
`other/Blueprints:2:5: module "arule": depends on //top:top_allowed_as_notice `+
`which is not visible to this module`,
`yetmore/Blueprints:2:5: module "//yetmore": depends on //top:top_allowed_as_notice `+
`which is not visible to this module`,
},
},
{
name: "must reference license_kind module",
fs: map[string][]byte{
"top/Blueprints": []byte(`
rule {
name: "top_by_exception_only",
}
license {
name: "top_proprietary",
license_kinds: ["top_by_exception_only"],
visibility: ["//visibility:public"],
}`),
},
expectedErrors: []string{
`top/Blueprints:6:5: module "top_proprietary": license_kinds property `+
`"top_by_exception_only" is not a license_kind module`,
},
},
{
name: "license_kind module must exist",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license {
name: "top_notice_allowed",
license_kinds: ["top_notice"],
visibility: ["//visibility:public"],
}`),
},
expectedErrors: []string{
`top/Blueprints:2:5: "top_notice_allowed" depends on undefined module "top_notice"`,
},
},
{
name: "public license",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "top_by_exception_only",
conditions: ["by_exception_only"],
visibility: ["//visibility:private"],
}
license {
name: "top_proprietary",
license_kinds: ["top_by_exception_only"],
visibility: ["//visibility:public"],
}`),
"other/Blueprints": []byte(`
rule {
name: "arule",
licenses: ["top_proprietary"],
}`),
"yetmore/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_proprietary"],
}`),
},
},
{
name: "multiple licenses",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_proprietary"],
}
license_kind {
name: "top_notice",
conditions: ["notice"],
}
license_kind {
name: "top_by_exception_only",
conditions: ["by_exception_only"],
visibility: ["//visibility:public"],
}
license {
name: "top_allowed_as_notice",
license_kinds: ["top_notice"],
}
license {
name: "top_proprietary",
license_kinds: ["top_by_exception_only"],
visibility: ["//visibility:public"],
}
rule {
name: "myrule",
licenses: ["top_allowed_as_notice", "top_proprietary"]
}`),
"other/Blueprints": []byte(`
rule {
name: "arule",
licenses: ["top_proprietary"],
}`),
"yetmore/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_proprietary"],
}`),
},
},
}
func TestLicense(t *testing.T) {
for _, test := range licenseTests {
t.Run(test.name, func(t *testing.T) {
_, errs := testLicense(test.fs)
expectedErrors := test.expectedErrors
if expectedErrors == nil {
FailIfErrored(t, errs)
} else {
for _, expectedError := range expectedErrors {
FailIfNoMatchingErrors(t, expectedError, errs)
}
if len(errs) > len(expectedErrors) {
t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs))
for i, expectedError := range expectedErrors {
t.Errorf("expectedErrors[%d] = %s", i, expectedError)
}
for i, err := range errs {
t.Errorf("errs[%d] = %s", i, err)
}
}
}
})
}
}
func testLicense(fs map[string][]byte) (*TestContext, []error) {
// Create a new config per test as visibility information is stored in the config.
env := make(map[string]string)
env["ANDROID_REQUIRE_LICENSES"] = "1"
config := TestArchConfig(buildDir, env, "", fs)
ctx := NewTestArchContext(config)
RegisterPackageBuildComponents(ctx)
registerTestPrebuiltBuildComponents(ctx)
RegisterLicenseKindBuildComponents(ctx)
RegisterLicenseBuildComponents(ctx)
ctx.RegisterModuleType("rule", newMockRuleModule)
ctx.PreArchMutators(RegisterVisibilityRuleChecker)
ctx.PreArchMutators(RegisterLicensesPackageMapper)
ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
ctx.PreArchMutators(RegisterLicensesPropertyGatherer)
ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
ctx.PostDepsMutators(RegisterLicensesDependencyChecker)
ctx.Register()
_, errs := ctx.ParseBlueprintsFiles(".")
if len(errs) > 0 {
return ctx, errs
}
_, errs = ctx.PrepareBuildActions(config)
return ctx, errs
}
type mockRuleModule struct {
ModuleBase
DefaultableModuleBase
}
func newMockRuleModule() Module {
m := &mockRuleModule{}
InitAndroidModule(m)
InitDefaultableModule(m)
return m
}
func (p *mockRuleModule) GenerateAndroidBuildActions(ModuleContext) {
}

295
android/licenses.go Normal file
View File

@ -0,0 +1,295 @@
// 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
}
var (
licensesTag = licensesDependencyTag{}
)
// 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
}
// license modules have no licenses, but license_kinds must refer to license_kind modules
if l, ok := m.(*licenseModule); ok {
mergeProps(&m.base().commonProperties.Effective_licenses, ctx.ModuleName())
mergeProps(&m.base().commonProperties.Effective_license_text, PathsForModuleSrc(ctx, l.properties.License_text).Strings()...)
for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) {
if lk, ok := module.(*licenseKindModule); ok {
mergeProps(&m.base().commonProperties.Effective_license_conditions, lk.properties.Conditions...)
mergeProps(&m.base().commonProperties.Effective_license_kinds, ctx.OtherModuleName(module))
} else {
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 l, ok := module.(*licenseModule); ok {
if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil {
m.base().commonProperties.Effective_package_name = l.properties.Package_name
}
mergeProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...)
mergeProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...)
mergeProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...)
mergeProps(&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))
}
}
}
// Update a property string array with a distinct union of its values and a list of new values.
func mergeProps(prop *[]string, values ...string) {
s := make(map[string]bool)
for _, v := range *prop {
s[v] = true
}
for _, v := range values {
s[v] = true
}
*prop = []string{}
*prop = append(*prop, SortedStringKeys(s)...)
}
// 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().IsEnvTrue("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
}

863
android/licenses_test.go Normal file
View File

@ -0,0 +1,863 @@
package android
import (
"testing"
"github.com/google/blueprint"
)
var licensesTests = []struct {
name string
fs map[string][]byte
expectedErrors []string
effectiveLicenses map[string][]string
effectiveInheritedLicenses map[string][]string
effectivePackage map[string]string
effectiveNotices map[string][]string
effectiveKinds map[string][]string
effectiveConditions map[string][]string
}{
{
name: "invalid module type without licenses property",
fs: map[string][]byte{
"top/Blueprints": []byte(`
mock_bad_module {
name: "libexample",
}`),
},
expectedErrors: []string{`module type "mock_bad_module" must have an applicable licenses property`},
},
{
name: "license must exist",
fs: map[string][]byte{
"top/Blueprints": []byte(`
mock_library {
name: "libexample",
licenses: ["notice"],
}`),
},
expectedErrors: []string{`"libexample" depends on undefined module "notice"`},
},
{
name: "all good",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "notice",
conditions: ["shownotice"],
}
license {
name: "top_Apache2",
license_kinds: ["notice"],
package_name: "topDog",
license_text: ["LICENSE", "NOTICE"],
}
mock_library {
name: "libexample1",
licenses: ["top_Apache2"],
}`),
"top/nested/Blueprints": []byte(`
mock_library {
name: "libnested",
licenses: ["top_Apache2"],
}`),
"other/Blueprints": []byte(`
mock_library {
name: "libother",
licenses: ["top_Apache2"],
}`),
},
effectiveLicenses: map[string][]string{
"libexample1": []string{"top_Apache2"},
"libnested": []string{"top_Apache2"},
"libother": []string{"top_Apache2"},
},
effectiveKinds: map[string][]string{
"libexample1": []string{"notice"},
"libnested": []string{"notice"},
"libother": []string{"notice"},
},
effectivePackage: map[string]string{
"libexample1": "topDog",
"libnested": "topDog",
"libother": "topDog",
},
effectiveConditions: map[string][]string{
"libexample1": []string{"shownotice"},
"libnested": []string{"shownotice"},
"libother": []string{"shownotice"},
},
effectiveNotices: map[string][]string{
"libexample1": []string{"top/LICENSE", "top/NOTICE"},
"libnested": []string{"top/LICENSE", "top/NOTICE"},
"libother": []string{"top/LICENSE", "top/NOTICE"},
},
},
// Defaults propagation tests
{
// Check that licenses is the union of the defaults modules.
name: "defaults union, basic",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license_kind {
name: "top_notice",
conditions: ["notice"],
}
license {
name: "top_other",
license_kinds: ["top_notice"],
}
mock_defaults {
name: "libexample_defaults",
licenses: ["top_other"],
}
mock_library {
name: "libexample",
licenses: ["nested_other"],
defaults: ["libexample_defaults"],
}
mock_library {
name: "libsamepackage",
deps: ["libexample"],
}`),
"top/nested/Blueprints": []byte(`
license_kind {
name: "nested_notice",
conditions: ["notice"],
}
license {
name: "nested_other",
license_kinds: ["nested_notice"],
}
mock_library {
name: "libnested",
deps: ["libexample"],
}`),
"other/Blueprints": []byte(`
mock_library {
name: "libother",
deps: ["libexample"],
}`),
},
effectiveLicenses: map[string][]string{
"libexample": []string{"nested_other", "top_other"},
"libsamepackage": []string{},
"libnested": []string{},
"libother": []string{},
},
effectiveInheritedLicenses: map[string][]string{
"libexample": []string{"nested_other", "top_other"},
"libsamepackage": []string{"nested_other", "top_other"},
"libnested": []string{"nested_other", "top_other"},
"libother": []string{"nested_other", "top_other"},
},
effectiveKinds: map[string][]string{
"libexample": []string{"nested_notice", "top_notice"},
"libsamepackage": []string{},
"libnested": []string{},
"libother": []string{},
},
effectiveConditions: map[string][]string{
"libexample": []string{"notice"},
"libsamepackage": []string{},
"libnested": []string{},
"libother": []string{},
},
},
{
name: "defaults union, multiple defaults",
fs: map[string][]byte{
"top/Blueprints": []byte(`
license {
name: "top",
}
mock_defaults {
name: "libexample_defaults_1",
licenses: ["other"],
}
mock_defaults {
name: "libexample_defaults_2",
licenses: ["top_nested"],
}
mock_library {
name: "libexample",
defaults: ["libexample_defaults_1", "libexample_defaults_2"],
}
mock_library {
name: "libsamepackage",
deps: ["libexample"],
}`),
"top/nested/Blueprints": []byte(`
license {
name: "top_nested",
license_text: ["LICENSE.txt"],
}
mock_library {
name: "libnested",
deps: ["libexample"],
}`),
"other/Blueprints": []byte(`
license {
name: "other",
}
mock_library {
name: "libother",
deps: ["libexample"],
}`),
"outsider/Blueprints": []byte(`
mock_library {
name: "liboutsider",
deps: ["libexample"],
}`),
},
effectiveLicenses: map[string][]string{
"libexample": []string{"other", "top_nested"},
"libsamepackage": []string{},
"libnested": []string{},
"libother": []string{},
"liboutsider": []string{},
},
effectiveInheritedLicenses: map[string][]string{
"libexample": []string{"other", "top_nested"},
"libsamepackage": []string{"other", "top_nested"},
"libnested": []string{"other", "top_nested"},
"libother": []string{"other", "top_nested"},
"liboutsider": []string{"other", "top_nested"},
},
effectiveKinds: map[string][]string{
"libexample": []string{},
"libsamepackage": []string{},
"libnested": []string{},
"libother": []string{},
"liboutsider": []string{},
},
effectiveNotices: map[string][]string{
"libexample": []string{"top/nested/LICENSE.txt"},
"libsamepackage": []string{},
"libnested": []string{},
"libother": []string{},
"liboutsider": []string{},
},
},
// Defaults module's defaults_licenses tests
{
name: "defaults_licenses invalid",
fs: map[string][]byte{
"top/Blueprints": []byte(`
mock_defaults {
name: "top_defaults",
licenses: ["notice"],
}`),
},
expectedErrors: []string{`"top_defaults" depends on undefined module "notice"`},
},
{
name: "defaults_licenses overrides package default",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
default_applicable_licenses: ["by_exception_only"],
}
license {
name: "by_exception_only",
}
license {
name: "notice",
}
mock_defaults {
name: "top_defaults",
licenses: ["notice"],
}
mock_library {
name: "libexample",
}
mock_library {
name: "libdefaults",
defaults: ["top_defaults"],
}`),
},
effectiveLicenses: map[string][]string{
"libexample": []string{"by_exception_only"},
"libdefaults": []string{"notice"},
},
effectiveInheritedLicenses: map[string][]string{
"libexample": []string{"by_exception_only"},
"libdefaults": []string{"notice"},
},
},
// Package default_applicable_licenses tests
{
name: "package default_applicable_licenses must exist",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
default_applicable_licenses: ["notice"],
}`),
},
expectedErrors: []string{`"//top" depends on undefined module "notice"`},
},
{
// This test relies on the default licenses being legacy_public.
name: "package default_applicable_licenses property used when no licenses specified",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_notice"],
}
license {
name: "top_notice",
}
mock_library {
name: "libexample",
}`),
"outsider/Blueprints": []byte(`
mock_library {
name: "liboutsider",
deps: ["libexample"],
}`),
},
effectiveLicenses: map[string][]string{
"libexample": []string{"top_notice"},
"liboutsider": []string{},
},
effectiveInheritedLicenses: map[string][]string{
"libexample": []string{"top_notice"},
"liboutsider": []string{"top_notice"},
},
},
{
name: "package default_applicable_licenses not inherited to subpackages",
fs: map[string][]byte{
"top/Blueprints": []byte(`
package {
default_applicable_licenses: ["top_notice"],
}
license {
name: "top_notice",
}
mock_library {
name: "libexample",
}`),
"top/nested/Blueprints": []byte(`
package {
default_applicable_licenses: ["outsider"],
}
mock_library {
name: "libnested",
}`),
"top/other/Blueprints": []byte(`
mock_library {
name: "libother",
}`),
"outsider/Blueprints": []byte(`
license {
name: "outsider",
}
mock_library {
name: "liboutsider",
deps: ["libexample", "libother", "libnested"],
}`),
},
effectiveLicenses: map[string][]string{
"libexample": []string{"top_notice"},
"libnested": []string{"outsider"},
"libother": []string{},
"liboutsider": []string{},
},
effectiveInheritedLicenses: map[string][]string{
"libexample": []string{"top_notice"},
"libnested": []string{"outsider"},
"libother": []string{},
"liboutsider": []string{"top_notice", "outsider"},
},
},
{
name: "verify that prebuilt dependencies are included",
fs: map[string][]byte{
"prebuilts/Blueprints": []byte(`
license {
name: "prebuilt"
}
prebuilt {
name: "module",
licenses: ["prebuilt"],
}`),
"top/sources/source_file": nil,
"top/sources/Blueprints": []byte(`
license {
name: "top_sources"
}
source {
name: "module",
licenses: ["top_sources"],
}`),
"top/other/source_file": nil,
"top/other/Blueprints": []byte(`
source {
name: "other",
deps: [":module"],
}`),
},
effectiveLicenses: map[string][]string{
"other": []string{},
},
effectiveInheritedLicenses: map[string][]string{
"other": []string{"prebuilt", "top_sources"},
},
},
{
name: "verify that prebuilt dependencies are ignored for licenses reasons (preferred)",
fs: map[string][]byte{
"prebuilts/Blueprints": []byte(`
license {
name: "prebuilt"
}
prebuilt {
name: "module",
licenses: ["prebuilt"],
prefer: true,
}`),
"top/sources/source_file": nil,
"top/sources/Blueprints": []byte(`
license {
name: "top_sources"
}
source {
name: "module",
licenses: ["top_sources"],
}`),
"top/other/source_file": nil,
"top/other/Blueprints": []byte(`
source {
name: "other",
deps: [":module"],
}`),
},
effectiveLicenses: map[string][]string{
"other": []string{},
},
effectiveInheritedLicenses: map[string][]string{
"module": []string{"prebuilt", "top_sources"},
"other": []string{"prebuilt", "top_sources"},
},
},
}
func TestLicenses(t *testing.T) {
for _, test := range licensesTests {
t.Run(test.name, func(t *testing.T) {
ctx, errs := testLicenses(buildDir, test.fs)
CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
if test.effectiveLicenses != nil {
checkEffectiveLicenses(t, ctx, test.effectiveLicenses)
}
if test.effectivePackage != nil {
checkEffectivePackage(t, ctx, test.effectivePackage)
}
if test.effectiveNotices != nil {
checkEffectiveNotices(t, ctx, test.effectiveNotices)
}
if test.effectiveKinds != nil {
checkEffectiveKinds(t, ctx, test.effectiveKinds)
}
if test.effectiveConditions != nil {
checkEffectiveConditions(t, ctx, test.effectiveConditions)
}
if test.effectiveInheritedLicenses != nil {
checkEffectiveInheritedLicenses(t, ctx, test.effectiveInheritedLicenses)
}
})
}
}
func checkEffectiveLicenses(t *testing.T, ctx *TestContext, effectiveLicenses map[string][]string) {
actualLicenses := make(map[string][]string)
ctx.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
return
}
if _, ok := m.(*licenseKindModule); ok {
return
}
if _, ok := m.(*packageModule); ok {
return
}
module, ok := m.(Module)
if !ok {
t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
if base == nil {
return
}
actualLicenses[m.Name()] = base.commonProperties.Effective_licenses
})
for moduleName, expectedLicenses := range effectiveLicenses {
licenses, ok := actualLicenses[moduleName]
if !ok {
licenses = []string{}
}
if !compareUnorderedStringArrays(expectedLicenses, licenses) {
t.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses)
}
}
}
func checkEffectiveInheritedLicenses(t *testing.T, ctx *TestContext, effectiveInheritedLicenses map[string][]string) {
actualLicenses := make(map[string][]string)
ctx.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
return
}
if _, ok := m.(*licenseKindModule); ok {
return
}
if _, ok := m.(*packageModule); ok {
return
}
module, ok := m.(Module)
if !ok {
t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
if base == nil {
return
}
inherited := make(map[string]bool)
for _, l := range base.commonProperties.Effective_licenses {
inherited[l] = true
}
ctx.Context.Context.VisitDepsDepthFirst(m, func(c blueprint.Module) {
if _, ok := c.(*licenseModule); ok {
return
}
if _, ok := c.(*licenseKindModule); ok {
return
}
if _, ok := c.(*packageModule); ok {
return
}
cmodule, ok := c.(Module)
if !ok {
t.Errorf("%q not a module", c.Name())
return
}
cbase := cmodule.base()
if cbase == nil {
return
}
for _, l := range cbase.commonProperties.Effective_licenses {
inherited[l] = true
}
})
actualLicenses[m.Name()] = []string{}
for l := range inherited {
actualLicenses[m.Name()] = append(actualLicenses[m.Name()], l)
}
})
for moduleName, expectedInheritedLicenses := range effectiveInheritedLicenses {
licenses, ok := actualLicenses[moduleName]
if !ok {
licenses = []string{}
}
if !compareUnorderedStringArrays(expectedInheritedLicenses, licenses) {
t.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses)
}
}
}
func checkEffectivePackage(t *testing.T, ctx *TestContext, effectivePackage map[string]string) {
actualPackage := make(map[string]string)
ctx.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
return
}
if _, ok := m.(*licenseKindModule); ok {
return
}
if _, ok := m.(*packageModule); ok {
return
}
module, ok := m.(Module)
if !ok {
t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
if base == nil {
return
}
if base.commonProperties.Effective_package_name == nil {
actualPackage[m.Name()] = ""
} else {
actualPackage[m.Name()] = *base.commonProperties.Effective_package_name
}
})
for moduleName, expectedPackage := range effectivePackage {
packageName, ok := actualPackage[moduleName]
if !ok {
packageName = ""
}
if expectedPackage != packageName {
t.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName)
}
}
}
func checkEffectiveNotices(t *testing.T, ctx *TestContext, effectiveNotices map[string][]string) {
actualNotices := make(map[string][]string)
ctx.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
return
}
if _, ok := m.(*licenseKindModule); ok {
return
}
if _, ok := m.(*packageModule); ok {
return
}
module, ok := m.(Module)
if !ok {
t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
if base == nil {
return
}
actualNotices[m.Name()] = base.commonProperties.Effective_license_text
})
for moduleName, expectedNotices := range effectiveNotices {
notices, ok := actualNotices[moduleName]
if !ok {
notices = []string{}
}
if !compareUnorderedStringArrays(expectedNotices, notices) {
t.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices)
}
}
}
func checkEffectiveKinds(t *testing.T, ctx *TestContext, effectiveKinds map[string][]string) {
actualKinds := make(map[string][]string)
ctx.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
return
}
if _, ok := m.(*licenseKindModule); ok {
return
}
if _, ok := m.(*packageModule); ok {
return
}
module, ok := m.(Module)
if !ok {
t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
if base == nil {
return
}
actualKinds[m.Name()] = base.commonProperties.Effective_license_kinds
})
for moduleName, expectedKinds := range effectiveKinds {
kinds, ok := actualKinds[moduleName]
if !ok {
kinds = []string{}
}
if !compareUnorderedStringArrays(expectedKinds, kinds) {
t.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds)
}
}
}
func checkEffectiveConditions(t *testing.T, ctx *TestContext, effectiveConditions map[string][]string) {
actualConditions := make(map[string][]string)
ctx.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
return
}
if _, ok := m.(*licenseKindModule); ok {
return
}
if _, ok := m.(*packageModule); ok {
return
}
module, ok := m.(Module)
if !ok {
t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
if base == nil {
return
}
actualConditions[m.Name()] = base.commonProperties.Effective_license_conditions
})
for moduleName, expectedConditions := range effectiveConditions {
conditions, ok := actualConditions[moduleName]
if !ok {
conditions = []string{}
}
if !compareUnorderedStringArrays(expectedConditions, conditions) {
t.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions)
}
}
}
func compareUnorderedStringArrays(expected, actual []string) bool {
if len(expected) != len(actual) {
return false
}
s := make(map[string]int)
for _, v := range expected {
s[v] += 1
}
for _, v := range actual {
c, ok := s[v]
if !ok {
return false
}
if c < 1 {
return false
}
s[v] -= 1
}
return true
}
func testLicenses(buildDir string, fs map[string][]byte) (*TestContext, []error) {
// Create a new config per test as licenses information is stored in the config.
env := make(map[string]string)
env["ANDROID_REQUIRE_LICENSES"] = "1"
config := TestArchConfig(buildDir, env, "", fs)
ctx := NewTestArchContext(config)
ctx.RegisterModuleType("mock_bad_module", newMockLicensesBadModule)
ctx.RegisterModuleType("mock_library", newMockLicensesLibraryModule)
ctx.RegisterModuleType("mock_defaults", defaultsLicensesFactory)
// Order of the following method calls is significant.
RegisterPackageBuildComponents(ctx)
registerTestPrebuiltBuildComponents(ctx)
RegisterLicenseKindBuildComponents(ctx)
RegisterLicenseBuildComponents(ctx)
ctx.PreArchMutators(RegisterVisibilityRuleChecker)
ctx.PreArchMutators(RegisterLicensesPackageMapper)
ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
ctx.PreArchMutators(RegisterLicensesPropertyGatherer)
ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
ctx.PostDepsMutators(RegisterLicensesDependencyChecker)
ctx.Register()
_, errs := ctx.ParseBlueprintsFiles(".")
if len(errs) > 0 {
return ctx, errs
}
_, errs = ctx.PrepareBuildActions(config)
return ctx, errs
}
type mockLicensesBadProperties struct {
Visibility []string
}
type mockLicensesBadModule struct {
ModuleBase
DefaultableModuleBase
properties mockLicensesBadProperties
}
func newMockLicensesBadModule() Module {
m := &mockLicensesBadModule{}
base := m.base()
m.AddProperties(&base.nameProperties, &m.properties)
base.generalProperties = m.GetProperties()
base.customizableProperties = m.GetProperties()
// The default_visibility property needs to be checked and parsed by the visibility module during
// its checking and parsing phases so make it the primary visibility property.
setPrimaryVisibilityProperty(m, "visibility", &m.properties.Visibility)
initAndroidModuleBase(m)
InitDefaultableModule(m)
return m
}
func (m *mockLicensesBadModule) GenerateAndroidBuildActions(ModuleContext) {
}
type mockLicensesLibraryProperties struct {
Deps []string
}
type mockLicensesLibraryModule struct {
ModuleBase
DefaultableModuleBase
properties mockLicensesLibraryProperties
}
func newMockLicensesLibraryModule() Module {
m := &mockLicensesLibraryModule{}
m.AddProperties(&m.properties)
InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
InitDefaultableModule(m)
return m
}
type dependencyLicensesTag struct {
blueprint.BaseDependencyTag
name string
}
func (j *mockLicensesLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
ctx.AddVariationDependencies(nil, dependencyLicensesTag{name: "mockdeps"}, j.properties.Deps...)
}
func (p *mockLicensesLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
type mockLicensesDefaults struct {
ModuleBase
DefaultsModuleBase
}
func defaultsLicensesFactory() Module {
m := &mockLicensesDefaults{}
InitDefaultsModule(m)
return m
}

View File

@ -619,6 +619,20 @@ type commonProperties struct {
// more details.
Visibility []string
// Describes the licenses applicable to this module. Must reference license modules.
Licenses []string
// Flattened from direct license dependencies. Equal to Licenses unless particular module adds more.
Effective_licenses []string `blueprint:"mutated"`
// Override of module name when reporting licenses
Effective_package_name *string `blueprint:"mutated"`
// Notice files
Effective_license_text []string `blueprint:"mutated"`
// License names
Effective_license_kinds []string `blueprint:"mutated"`
// License conditions
Effective_license_conditions []string `blueprint:"mutated"`
// control whether this module compiles for 32-bit, 64-bit, or both. Possible values
// are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both
// architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit
@ -940,6 +954,10 @@ func InitAndroidModule(m Module) {
// The default_visibility property needs to be checked and parsed by the visibility module during
// its checking and parsing phases so make it the primary visibility property.
setPrimaryVisibilityProperty(m, "visibility", &base.commonProperties.Visibility)
// The default_applicable_licenses property needs to be checked and parsed by the licenses module during
// its checking and parsing phases so make it the primary licenses property.
setPrimaryLicensesProperty(m, "licenses", &base.commonProperties.Licenses)
}
// InitAndroidArchModule initializes the Module as an Android module that is architecture-specific.
@ -1057,6 +1075,9 @@ type ModuleBase struct {
// The primary visibility property, may be nil, that controls access to the module.
primaryVisibilityProperty visibilityProperty
// The primary licenses property, may be nil, records license metadata for the module.
primaryLicensesProperty applicableLicensesProperty
noAddressSanitizer bool
installFiles InstallPaths
installFilesDepSet *installPathsDepSet
@ -1732,6 +1753,11 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
}
}
licensesPropertyFlattener(ctx)
if ctx.Failed() {
return
}
m.module.GenerateAndroidBuildActions(ctx)
if ctx.Failed() {
return

View File

@ -115,6 +115,11 @@ var preArch = []RegisterMutatorFunc{
//
RegisterVisibilityRuleChecker,
// Record the default_applicable_licenses for each package.
//
// This must run before the defaults so that defaults modules can pick up the package default.
RegisterLicensesPackageMapper,
// Apply properties from defaults modules to the referencing modules.
//
// Any mutators that are added before this will not see any modules created by
@ -141,6 +146,12 @@ var preArch = []RegisterMutatorFunc{
// prebuilt.
RegisterPrebuiltsPreArchMutators,
// Gather the licenses properties for all modules for use during expansion and enforcement.
//
// This must come after the defaults mutators to ensure that any licenses supplied
// in a defaults module has been successfully applied before the rules are gathered.
RegisterLicensesPropertyGatherer,
// Gather the visibility rules for all modules for us during visibility enforcement.
//
// This must come after the defaults mutators to ensure that any visibility supplied
@ -162,6 +173,7 @@ var postDeps = []RegisterMutatorFunc{
registerPathDepsMutator,
RegisterPrebuiltsPostDepsMutators,
RegisterVisibilityRuleEnforcer,
RegisterLicensesDependencyChecker,
RegisterNeverallowMutator,
RegisterOverridePostDepsMutators,
}

View File

@ -31,6 +31,8 @@ func RegisterPackageBuildComponents(ctx RegistrationContext) {
type packageProperties struct {
// Specifies the default visibility for all modules defined in this package.
Default_visibility []string
// Specifies the default license terms for all modules defined in this package.
Default_applicable_licenses []string
}
type packageModule struct {
@ -68,5 +70,9 @@ func PackageFactory() Module {
// its checking and parsing phases so make it the primary visibility property.
setPrimaryVisibilityProperty(module, "default_visibility", &module.properties.Default_visibility)
// The default_applicable_licenses property needs to be checked and parsed by the licenses module during
// its checking and parsing phases so make it the primary licenses property.
setPrimaryLicensesProperty(module, "default_applicable_licenses", &module.properties.Default_applicable_licenses)
return module
}

View File

@ -17,9 +17,11 @@ var packageTests = []struct {
package {
name: "package",
visibility: ["//visibility:private"],
licenses: ["license"],
}`),
},
expectedErrors: []string{
`top/Blueprints:5:14: unrecognized property "licenses"`,
`top/Blueprints:3:10: unrecognized property "name"`,
`top/Blueprints:4:16: unrecognized property "visibility"`,
},
@ -44,9 +46,10 @@ var packageTests = []struct {
"top/Blueprints": []byte(`
package {
default_visibility: ["//visibility:private"],
default_applicable_licenses: ["license"],
}
package {
package {
}`),
},
expectedErrors: []string{

View File

@ -63,6 +63,16 @@ func (class apexFileClass) nameInMake() string {
}
}
// Return the full module name for a dependency module, which appends the apex module name unless re-using a system lib.
func (a *apexBundle) fullModuleName(apexBundleName string, fi *apexFile) string {
linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
if linkToSystemLib {
return fi.androidMkModuleName
}
return fi.androidMkModuleName + "." + apexBundleName + a.suffix
}
func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string,
apexAndroidMkData android.AndroidMkData) []string {
@ -114,12 +124,7 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
var moduleName string
if linkToSystemLib {
moduleName = fi.androidMkModuleName
} else {
moduleName = fi.androidMkModuleName + "." + apexBundleName + a.suffix
}
moduleName := a.fullModuleName(apexBundleName, &fi)
if !android.InList(moduleName, moduleNames) {
moduleNames = append(moduleNames, moduleName)
@ -311,14 +316,16 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
return moduleNames
}
func (a *apexBundle) writeRequiredModules(w io.Writer) {
func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) {
var required []string
var targetRequired []string
var hostRequired []string
installMapSet := make(map[string]bool) // set of dependency module:location mappings
for _, fi := range a.filesInfo {
required = append(required, fi.requiredModuleNames...)
targetRequired = append(targetRequired, fi.targetRequiredModuleNames...)
hostRequired = append(hostRequired, fi.hostRequiredModuleNames...)
installMapSet[a.fullModuleName(apexBundleName, &fi)+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
}
if len(required) > 0 {
@ -330,6 +337,11 @@ func (a *apexBundle) writeRequiredModules(w io.Writer) {
if len(hostRequired) > 0 {
fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES +=", strings.Join(hostRequired, " "))
}
if len(installMapSet) > 0 {
var installs []string
installs = append(installs, android.SortedStringKeys(installMapSet)...)
fmt.Fprintln(w, "LOCAL_LICENSE_INSTALL_MAP +=", strings.Join(installs, " "))
}
}
func (a *apexBundle) androidMkForType() android.AndroidMkData {
@ -347,16 +359,18 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData {
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix)
data.Entries.WriteLicenseVariables(w)
if len(moduleNames) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
}
a.writeRequiredModules(w)
a.writeRequiredModules(w, name)
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
} else {
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix)
data.Entries.WriteLicenseVariables(w)
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
@ -389,7 +403,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData {
if len(a.requiredDeps) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.requiredDeps, " "))
}
a.writeRequiredModules(w)
a.writeRequiredModules(w, name)
var postInstallCommands []string
if a.prebuiltFileToDelete != "" {
postInstallCommands = append(postInstallCommands, "rm -rf "+

View File

@ -120,6 +120,7 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData {
names = append(names, objName)
fmt.Fprintln(w, "include $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
data.Entries.WriteLicenseVariables(w)
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
@ -129,6 +130,7 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData {
}
fmt.Fprintln(w, "include $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_MODULE := ", name)
data.Entries.WriteLicenseVariables(w)
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(names, " "))
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
},

View File

@ -192,6 +192,7 @@ func (system *SystemModules) AndroidMk() android.AndroidMkData {
fmt.Fprintln(w, name+":", "$("+makevar+")")
fmt.Fprintln(w, ".PHONY:", name)
// TODO(b/151177513): Licenses: Doesn't go through base_rules. May have to generate meta_lic and meta_module here.
},
}
}

1082
licenses/Android.bp Normal file

File diff suppressed because it is too large Load Diff

214
licenses/LICENSE Normal file
View File

@ -0,0 +1,214 @@
Copyright (c) The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
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.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -52,6 +52,7 @@ func (p *phony) AndroidMk() android.AndroidMkData {
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
data.Entries.WriteLicenseVariables(w)
if p.Host() {
fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
}

View File

@ -307,6 +307,7 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData {
// Actual implementation libraries are created on LoadHookMutator
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintf(w, "LOCAL_MODULE := %s\n", m.Name())
data.Entries.WriteLicenseVariables(w)
fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n")
fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n")
fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n")