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