diff --git a/android/Android.bp b/android/Android.bp index 6124654a4..5d0f2b941 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -42,6 +42,7 @@ bootstrap_go_package { "image.go", "license.go", "license_kind.go", + "license_sdk_member.go", "licenses.go", "makefile_goal.go", "makevars.go", diff --git a/android/license_sdk_member.go b/android/license_sdk_member.go new file mode 100644 index 000000000..cd36ed6c5 --- /dev/null +++ b/android/license_sdk_member.go @@ -0,0 +1,118 @@ +// Copyright 2021 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 ( + "path/filepath" + + "github.com/google/blueprint" +) + +// Contains support for adding license modules to an sdk. + +func init() { + RegisterSdkMemberType(LicenseModuleSdkMemberType) +} + +// licenseSdkMemberType determines how a license module is added to the sdk. +type licenseSdkMemberType struct { + SdkMemberTypeBase +} + +func (l *licenseSdkMemberType) AddDependencies(mctx BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) { + // Add dependencies onto the license module from the sdk module. + mctx.AddDependency(mctx.Module(), dependencyTag, names...) +} + +func (l *licenseSdkMemberType) IsInstance(module Module) bool { + // Verify that the module being added is compatible with this module type. + _, ok := module.(*licenseModule) + return ok +} + +func (l *licenseSdkMemberType) AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule { + // Add the basics of a prebuilt module. + return ctx.SnapshotBuilder().AddPrebuiltModule(member, "license") +} + +func (l *licenseSdkMemberType) CreateVariantPropertiesStruct() SdkMemberProperties { + // Create the structure into which the properties of the license module that need to be output to + // the snapshot will be placed. The structure may be populated with information from a variant or + // may be used as the destination for properties that are common to a set of variants. + return &licenseSdkMemberProperties{} +} + +// LicenseModuleSdkMemberType is the instance of licenseSdkMemberType +var LicenseModuleSdkMemberType = &licenseSdkMemberType{ + SdkMemberTypeBase{ + PropertyName: "licenses", + + // This should never be added directly to an sdk/module_exports, all license modules should be + // added indirectly as transitive dependencies of other sdk members. + BpPropertyNotRequired: true, + + SupportsSdk: true, + + // The snapshot of the license module is just another license module (not a prebuilt). They are + // internal modules only so will have an sdk specific name that will not clash with the + // originating source module. + UseSourceModuleTypeInSnapshot: true, + }, +} + +var _ SdkMemberType = (*licenseSdkMemberType)(nil) + +// licenseSdkMemberProperties is the set of properties that need to be added to the license module +// in the snapshot. +type licenseSdkMemberProperties struct { + SdkMemberPropertiesBase + + // The kinds of licenses provided by the module. + License_kinds []string + + // The source paths to the files containing license text. + License_text Paths +} + +func (p *licenseSdkMemberProperties) PopulateFromVariant(_ SdkMemberContext, variant Module) { + // Populate the properties from the variant. + l := variant.(*licenseModule) + p.License_kinds = l.properties.License_kinds + p.License_text = l.base().commonProperties.Effective_license_text +} + +func (p *licenseSdkMemberProperties) AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet) { + // Just pass any specified license_kinds straight through. + if len(p.License_kinds) > 0 { + propertySet.AddProperty("license_kinds", p.License_kinds) + } + + // Copy any license test files to the snapshot into a module specific location. + if len(p.License_text) > 0 { + dests := []string{} + for _, path := range p.License_text { + // The destination path only uses the path of the license file in the source not the license + // module name. That ensures that if the same license file is used by multiple license modules + // that it only gets copied once as the snapshot builder will dedup copies where the source + // and destination match. + dest := filepath.Join("licenses", path.String()) + dests = append(dests, dest) + ctx.SnapshotBuilder().CopyToSnapshot(path, dest) + } + propertySet.AddProperty("license_text", dests) + } +} + +var _ SdkMemberProperties = (*licenseSdkMemberProperties)(nil) diff --git a/android/licenses.go b/android/licenses.go index c9e1da40f..464ba49b4 100644 --- a/android/licenses.go +++ b/android/licenses.go @@ -32,8 +32,23 @@ 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. + _ SdkMemberTypeDependencyTag = licensesTag ) // Describes the property provided by a module to reference applicable licenses. @@ -140,7 +155,6 @@ func licensesPropertyGatherer(ctx BottomUpMutatorContext) { } licenses := getLicenses(ctx, m) - ctx.AddVariationDependencies(nil, licensesTag, licenses...) } @@ -191,8 +205,10 @@ func licensesPropertyFlattener(ctx ModuleContext) { 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 } @@ -209,6 +225,12 @@ func licensesPropertyFlattener(ctx ModuleContext) { 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. @@ -277,3 +299,12 @@ func exemptFromRequiredApplicableLicensesProperty(module Module) bool { } 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{}) diff --git a/sdk/license_sdk_test.go b/sdk/license_sdk_test.go index 9d6ab0698..97ac6a94f 100644 --- a/sdk/license_sdk_test.go +++ b/sdk/license_sdk_test.go @@ -68,9 +68,23 @@ java_import { prefer: false, visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], + licenses: ["mysdk_mylicense"], jars: ["java/myjavalib.jar"], } -`), + +license { + name: "mysdk_mylicense", + visibility: ["//visibility:private"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + "legacy_unencumbered", + ], + license_text: [ + "licenses/NOTICE1", + "licenses/NOTICE2", + ], +} + `), checkVersionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -79,17 +93,34 @@ java_import { sdk_member_name: "myjavalib", visibility: ["//visibility:public"], apex_available: ["//apex_available:platform"], + licenses: ["mysdk_mylicense@current"], jars: ["java/myjavalib.jar"], } +license { + name: "mysdk_mylicense@current", + sdk_member_name: "mylicense", + visibility: ["//visibility:private"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + "legacy_unencumbered", + ], + license_text: [ + "licenses/NOTICE1", + "licenses/NOTICE2", + ], +} + sdk_snapshot { name: "mysdk@current", visibility: ["//visibility:public"], java_header_libs: ["mysdk_myjavalib@current"], } -`), + `), checkAllCopyRules(` .intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/myjavalib.jar +NOTICE1 -> licenses/NOTICE1 +NOTICE2 -> licenses/NOTICE2 `), ) } diff --git a/sdk/update.go b/sdk/update.go index a265676e7..deac0ec20 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -893,6 +893,13 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType m.AddProperty("apex_available", apexAvailable) } + // The licenses are the same for all variants. + mctx := s.ctx + licenseInfo := mctx.OtherModuleProvider(variant, android.LicenseInfoProvider).(android.LicenseInfo) + if len(licenseInfo.Licenses) > 0 { + m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag()) + } + deviceSupported := false hostSupported := false @@ -920,6 +927,12 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType } func addHostDeviceSupportedProperties(deviceSupported bool, hostSupported bool, bpModule *bpModule) { + // If neither device or host is supported then this module does not support either so will not + // recognize the properties. + if !deviceSupported && !hostSupported { + return + } + if !deviceSupported { bpModule.AddProperty("device_supported", false) }