Build license metadata files in Soong am: 3dd2ff28ed am: 05ff6289c2 am: a25d6989dc am: 2904cf5cfc

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1899702

Change-Id: I35fabcb7e7210fc0e0f55c2db4f73a716561db66
This commit is contained in:
Colin Cross 2021-12-10 23:02:00 +00:00 committed by Automerger Merge Worker
commit d9b928c776
7 changed files with 286 additions and 23 deletions

View file

@ -47,6 +47,7 @@ bootstrap_go_package {
"image.go",
"license.go",
"license_kind.go",
"license_metadata.go",
"license_sdk_member.go",
"licenses.go",
"makefile_goal.go",

View file

@ -474,6 +474,7 @@ type fillInEntriesContext interface {
ModuleDir(module blueprint.Module) string
Config() Config
ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
}
func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) {
@ -609,6 +610,11 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint
}
}
if ctx.ModuleHasProvider(mod, LicenseMetadataProvider) {
licenseMetadata := ctx.ModuleProvider(mod, LicenseMetadataProvider).(*LicenseMetadataInfo)
a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
}
extraCtx := &androidMkExtraEntriesContext{
ctx: ctx,
mod: mod,

231
android/license_metadata.go Normal file
View file

@ -0,0 +1,231 @@
// 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 (
"fmt"
"sort"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
var (
_ = pctx.HostBinToolVariable("licenseMetadataCmd", "build_license_metadata")
licenseMetadataRule = pctx.AndroidStaticRule("licenseMetadataRule", blueprint.RuleParams{
Command: "${licenseMetadataCmd} -o $out @${out}.rsp",
CommandDeps: []string{"${licenseMetadataCmd}"},
Rspfile: "${out}.rsp",
RspfileContent: "${args}",
}, "args")
)
func buildLicenseMetadata(ctx ModuleContext) {
base := ctx.Module().base()
if !base.Enabled() {
return
}
if exemptFromRequiredApplicableLicensesProperty(ctx.Module()) {
return
}
var allDepMetadataFiles Paths
var allDepMetadataArgs []string
var allDepOutputFiles Paths
ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
dep, _ := bpdep.(Module)
if dep == nil {
return
}
if !dep.Enabled() {
return
}
if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
depAnnotations := licenseAnnotationsFromTag(ctx.OtherModuleDependencyTag(dep))
allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations)
if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 {
allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...)
} else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil {
depOutputFiles = PathsIfNonNil(depOutputFiles...)
allDepOutputFiles = append(allDepOutputFiles, depOutputFiles...)
}
}
})
allDepMetadataFiles = SortedUniquePaths(allDepMetadataFiles)
sort.Strings(allDepMetadataArgs)
allDepOutputFiles = SortedUniquePaths(allDepOutputFiles)
var orderOnlyDeps Paths
var args []string
if t := ctx.ModuleType(); t != "" {
args = append(args,
"-mt "+proptools.NinjaAndShellEscape(t))
}
args = append(args,
"-r "+proptools.NinjaAndShellEscape(ctx.ModuleDir()),
"-mc UNKNOWN")
if p := base.commonProperties.Effective_package_name; p != nil {
args = append(args,
"-p "+proptools.NinjaAndShellEscape(*p))
}
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_kinds), "-k "))
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_conditions), "-c "))
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n "))
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d "))
orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...)
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepOutputFiles.Strings()), "-s "))
// Install map
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
// Built files
var outputFiles Paths
if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok {
outputFiles, _ = outputFileProducer.OutputFiles("")
outputFiles = PathsIfNonNil(outputFiles...)
}
if len(outputFiles) > 0 {
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t "))
} else {
args = append(args, fmt.Sprintf("-t //%s:%s", ctx.ModuleDir(), ctx.ModuleName()))
}
// Installed files
args = append(args,
JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i "))
isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles)
if isContainer {
args = append(args, "--is_container")
}
licenseMetadataFile := PathForModuleOut(ctx, "meta_lic")
ctx.Build(pctx, BuildParams{
Rule: licenseMetadataRule,
Output: licenseMetadataFile,
OrderOnly: orderOnlyDeps,
Description: "license metadata",
Args: map[string]string{
"args": strings.Join(args, " "),
},
})
ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
LicenseMetadataPath: licenseMetadataFile,
})
}
func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) bool {
var paths Paths
if len(installPaths) > 0 {
paths = installPaths.Paths()
} else {
paths = builtPaths
}
for _, path := range paths {
switch path.Ext() {
case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex":
return true
}
}
return false
}
// LicenseMetadataProvider is used to propagate license metadata paths between modules.
var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{})
// LicenseMetadataInfo stores the license metadata path for a module.
type LicenseMetadataInfo struct {
LicenseMetadataPath Path
}
// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into
// a string, or an empty string if there are none.
func licenseAnnotationsFromTag(tag blueprint.DependencyTag) string {
if annoTag, ok := tag.(LicenseAnnotationsDependencyTag); ok {
annos := annoTag.LicenseAnnotations()
if len(annos) > 0 {
annoStrings := make([]string, len(annos))
for i, s := range annos {
annoStrings[i] = string(s)
}
return ":" + strings.Join(annoStrings, ",")
}
}
return ""
}
// LicenseAnnotationsDependencyTag is implemented by dependency tags in order to provide a
// list of license dependency annotations.
type LicenseAnnotationsDependencyTag interface {
LicenseAnnotations() []LicenseAnnotation
}
// LicenseAnnotation is an enum of annotations that can be applied to dependencies for propagating
// license information.
type LicenseAnnotation string
const (
// LicenseAnnotationSharedDependency should be returned by LicenseAnnotations implementations
// of dependency tags when the usage of the dependency is dynamic, for example a shared library
// linkage for native modules or as a classpath library for java modules.
LicenseAnnotationSharedDependency LicenseAnnotation = "dynamic"
// LicenseAnnotationToolchain should be returned by LicenseAnnotations implementations of
// dependency tags when the dependency is used as a toolchain.
//
// Dependency tags that need to always return LicenseAnnotationToolchain
// can embed LicenseAnnotationToolchainDependencyTag to implement LicenseAnnotations.
LicenseAnnotationToolchain LicenseAnnotation = "toolchain"
)
// LicenseAnnotationToolchainDependencyTag can be embedded in a dependency tag to implement
// LicenseAnnotations that always returns LicenseAnnotationToolchain.
type LicenseAnnotationToolchainDependencyTag struct{}
func (LicenseAnnotationToolchainDependencyTag) LicenseAnnotations() []LicenseAnnotation {
return []LicenseAnnotation{LicenseAnnotationToolchain}
}

View file

@ -1227,6 +1227,10 @@ type ModuleBase struct {
initRcPaths Paths
vintfFragmentsPaths Paths
// set of dependency module:location mappings used to populate the license metadata for
// apex containers.
licenseInstallMap []string
}
// A struct containing all relevant information about a Bazel target converted via bp2build.
@ -1773,6 +1777,12 @@ func (m *ModuleBase) VintfFragments() Paths {
return append(Paths{}, m.vintfFragmentsPaths...)
}
// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
// apex container for use when generation the license metadata file.
func (m *ModuleBase) SetLicenseInstallMap(installMap []string) {
m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
}
func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
var allInstalledFiles InstallPaths
var allCheckbuildFiles Paths
@ -2038,6 +2048,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
m.installFilesDepSet = newInstallPathsDepSet(m.installFiles, dependencyInstallFiles)
m.packagingSpecsDepSet = newPackagingSpecsDepSet(m.packagingSpecs, dependencyPackagingSpecs)
buildLicenseMetadata(ctx)
m.buildParams = ctx.buildParams
m.ruleParams = ctx.ruleParams
m.variables = ctx.variables

View file

@ -309,19 +309,17 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo
return moduleNames
}
func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) {
func (a *apexBundle) writeRequiredModules(w io.Writer) {
var required []string
var targetRequired []string
var hostRequired []string
required = append(required, a.RequiredModuleNames()...)
targetRequired = append(targetRequired, a.TargetRequiredModuleNames()...)
hostRequired = append(hostRequired, a.HostRequiredModuleNames()...)
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 {
@ -333,11 +331,6 @@ func (a *apexBundle) writeRequiredModules(w io.Writer, apexBundleName string) {
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 {
@ -359,7 +352,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData {
if len(moduleNames) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
}
a.writeRequiredModules(w, name)
a.writeRequiredModules(w)
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
} else {
@ -401,7 +394,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, name)
a.writeRequiredModules(w)
if a.mergedNotices.Merged.Valid() {
fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", a.mergedNotices.Merged.Path().String())

View file

@ -434,7 +434,10 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
// Avoid creating duplicate build rules for multi-installed APEXes.
if proptools.BoolDefault(a.properties.Multi_install_skip_symbol_files, false) {
installSymbolFiles = false
}
// set of dependency module:location mappings
installMapSet := make(map[string]bool)
// TODO(jiyong): use the RuleBuilder
var copyCommands []string
@ -442,7 +445,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
pathWhenActivated := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
for _, fi := range a.filesInfo {
destPath := imageDir.Join(ctx, fi.path()).String()
var installedPath android.InstallPath
// Prepare the destination path
destPathDir := filepath.Dir(destPath)
if fi.class == appSet {
@ -450,6 +452,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
}
copyCommands = append(copyCommands, "mkdir -p "+destPathDir)
installMapPath := fi.builtFile
// Copy the built file to the directory. But if the symlink optimization is turned
// on, place a symlink to the corresponding file in /system partition instead.
if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
@ -457,6 +461,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
pathOnDevice := filepath.Join("/system", fi.path())
copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
} else {
var installedPath android.InstallPath
if fi.class == appSet {
copyCommands = append(copyCommands,
fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
@ -475,17 +480,19 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
if installSymbolFiles {
implicitInputs = append(implicitInputs, installedPath)
}
}
// Create additional symlinks pointing the file inside the APEX (if any). Note that
// this is independent from the symlink optimization.
for _, symlinkPath := range fi.symlinkPaths() {
symlinkDest := imageDir.Join(ctx, symlinkPath).String()
copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
if installSymbolFiles {
installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
implicitInputs = append(implicitInputs, installedSymlink)
// Create additional symlinks pointing the file inside the APEX (if any). Note that
// this is independent from the symlink optimization.
for _, symlinkPath := range fi.symlinkPaths() {
symlinkDest := imageDir.Join(ctx, symlinkPath).String()
copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
if installSymbolFiles {
installedSymlink := ctx.InstallSymlink(pathWhenActivated.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
implicitInputs = append(implicitInputs, installedSymlink)
}
}
installMapPath = installedPath
}
// Copy the test files (if any)
@ -502,6 +509,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
implicitInputs = append(implicitInputs, d.SrcPath)
}
installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
}
implicitInputs = append(implicitInputs, a.manifestPbOut)
if installSymbolFiles {
@ -510,6 +519,12 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
implicitInputs = append(implicitInputs, installedManifest, installedKey)
}
if len(installMapSet) > 0 {
var installs []string
installs = append(installs, android.SortedStringKeys(installMapSet)...)
a.SetLicenseInstallMap(installs)
}
////////////////////////////////////////////////////////////////////////////////////////////
// Step 1.a: Write the list of files in this APEX to a txt file and compare it against
// the allowed list given via the allowed_files property. Build fails when the two lists

View file

@ -1222,11 +1222,16 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
paths, err := module.commonOutputFiles(tag)
if paths == nil && err == nil {
return module.Library.OutputFiles(tag)
} else {
if paths != nil || err != nil {
return paths, err
}
if module.requiresRuntimeImplementationLibrary() {
return module.Library.OutputFiles(tag)
}
if tag == "" {
return nil, nil
}
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
}
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {