1// Copyright 2021 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 "sort" 20 "strings" 21 22 "github.com/google/blueprint" 23 "github.com/google/blueprint/proptools" 24) 25 26var ( 27 _ = pctx.HostBinToolVariable("licenseMetadataCmd", "build_license_metadata") 28 29 licenseMetadataRule = pctx.AndroidStaticRule("licenseMetadataRule", blueprint.RuleParams{ 30 Command: "${licenseMetadataCmd} -o $out @${out}.rsp", 31 CommandDeps: []string{"${licenseMetadataCmd}"}, 32 Rspfile: "${out}.rsp", 33 RspfileContent: "${args}", 34 }, "args") 35) 36 37func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) { 38 base := ctx.Module().base() 39 40 if !base.Enabled() { 41 return 42 } 43 44 if exemptFromRequiredApplicableLicensesProperty(ctx.Module()) { 45 return 46 } 47 48 var outputFiles Paths 49 if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok { 50 outputFiles, _ = outputFileProducer.OutputFiles("") 51 outputFiles = PathsIfNonNil(outputFiles...) 52 } 53 54 isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles) 55 56 var allDepMetadataFiles Paths 57 var allDepMetadataArgs []string 58 var allDepOutputFiles Paths 59 var allDepMetadataDepSets []*PathsDepSet 60 61 ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) { 62 dep, _ := bpdep.(Module) 63 if dep == nil { 64 return 65 } 66 if !dep.Enabled() { 67 return 68 } 69 70 if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) { 71 info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo) 72 allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath) 73 if isContainer || IsInstallDepNeeded(ctx.OtherModuleDependencyTag(dep)) { 74 allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet) 75 } 76 77 depAnnotations := licenseAnnotationsFromTag(ctx.OtherModuleDependencyTag(dep)) 78 79 allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations) 80 81 if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 { 82 allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...) 83 } else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil { 84 depOutputFiles = PathsIfNonNil(depOutputFiles...) 85 allDepOutputFiles = append(allDepOutputFiles, depOutputFiles...) 86 } 87 } 88 }) 89 90 allDepMetadataFiles = SortedUniquePaths(allDepMetadataFiles) 91 sort.Strings(allDepMetadataArgs) 92 allDepOutputFiles = SortedUniquePaths(allDepOutputFiles) 93 94 var orderOnlyDeps Paths 95 var args []string 96 97 if t := ctx.ModuleType(); t != "" { 98 args = append(args, 99 "-mt "+proptools.NinjaAndShellEscape(t)) 100 } 101 102 args = append(args, 103 "-r "+proptools.NinjaAndShellEscape(ctx.ModuleDir()), 104 "-mc UNKNOWN") 105 106 if p := base.commonProperties.Effective_package_name; p != nil { 107 args = append(args, 108 `-p "`+proptools.NinjaAndShellEscape(*p)+`"`) 109 } 110 111 args = append(args, 112 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_kinds), "-k ")) 113 114 args = append(args, 115 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_conditions), "-c ")) 116 117 args = append(args, 118 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n ")) 119 120 if isContainer { 121 transitiveDeps := newPathsDepSet(nil, allDepMetadataDepSets).ToList() 122 args = append(args, 123 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(transitiveDeps.Strings()), "-d ")) 124 orderOnlyDeps = append(orderOnlyDeps, transitiveDeps...) 125 } else { 126 args = append(args, 127 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d ")) 128 orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...) 129 } 130 131 args = append(args, 132 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepOutputFiles.Strings()), "-s ")) 133 134 // Install map 135 args = append(args, 136 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m ")) 137 138 // Built files 139 if len(outputFiles) > 0 { 140 args = append(args, 141 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t ")) 142 } else { 143 args = append(args, fmt.Sprintf("-t //%s:%s", ctx.ModuleDir(), ctx.ModuleName())) 144 } 145 146 // Installed files 147 args = append(args, 148 JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i ")) 149 150 if isContainer { 151 args = append(args, "--is_container") 152 } 153 154 ctx.Build(pctx, BuildParams{ 155 Rule: licenseMetadataRule, 156 Output: licenseMetadataFile, 157 OrderOnly: orderOnlyDeps, 158 Description: "license metadata", 159 Args: map[string]string{ 160 "args": strings.Join(args, " "), 161 }, 162 }) 163 164 ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{ 165 LicenseMetadataPath: licenseMetadataFile, 166 LicenseMetadataDepSet: newPathsDepSet(Paths{licenseMetadataFile}, allDepMetadataDepSets), 167 }) 168} 169 170func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) bool { 171 var paths Paths 172 if len(installPaths) > 0 { 173 paths = installPaths.Paths() 174 } else { 175 paths = builtPaths 176 } 177 178 for _, path := range paths { 179 switch path.Ext() { 180 case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex": 181 return true 182 } 183 } 184 185 return false 186} 187 188// LicenseMetadataProvider is used to propagate license metadata paths between modules. 189var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{}) 190 191// LicenseMetadataInfo stores the license metadata path for a module. 192type LicenseMetadataInfo struct { 193 LicenseMetadataPath Path 194 LicenseMetadataDepSet *PathsDepSet 195} 196 197// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into 198// a string, or an empty string if there are none. 199func licenseAnnotationsFromTag(tag blueprint.DependencyTag) string { 200 if annoTag, ok := tag.(LicenseAnnotationsDependencyTag); ok { 201 annos := annoTag.LicenseAnnotations() 202 if len(annos) > 0 { 203 annoStrings := make([]string, len(annos)) 204 for i, s := range annos { 205 annoStrings[i] = string(s) 206 } 207 return ":" + strings.Join(annoStrings, ",") 208 } 209 } 210 return "" 211} 212 213// LicenseAnnotationsDependencyTag is implemented by dependency tags in order to provide a 214// list of license dependency annotations. 215type LicenseAnnotationsDependencyTag interface { 216 LicenseAnnotations() []LicenseAnnotation 217} 218 219// LicenseAnnotation is an enum of annotations that can be applied to dependencies for propagating 220// license information. 221type LicenseAnnotation string 222 223const ( 224 // LicenseAnnotationSharedDependency should be returned by LicenseAnnotations implementations 225 // of dependency tags when the usage of the dependency is dynamic, for example a shared library 226 // linkage for native modules or as a classpath library for java modules. 227 // 228 // Dependency tags that need to always return LicenseAnnotationSharedDependency 229 // can embed LicenseAnnotationSharedDependencyTag to implement LicenseAnnotations. 230 LicenseAnnotationSharedDependency LicenseAnnotation = "dynamic" 231 232 // LicenseAnnotationToolchain should be returned by LicenseAnnotations implementations of 233 // dependency tags when the dependency is used as a toolchain. 234 // 235 // Dependency tags that need to always return LicenseAnnotationToolchain 236 // can embed LicenseAnnotationToolchainDependencyTag to implement LicenseAnnotations. 237 LicenseAnnotationToolchain LicenseAnnotation = "toolchain" 238) 239 240// LicenseAnnotationSharedDependencyTag can be embedded in a dependency tag to implement 241// LicenseAnnotations that always returns LicenseAnnotationSharedDependency. 242type LicenseAnnotationSharedDependencyTag struct{} 243 244func (LicenseAnnotationSharedDependencyTag) LicenseAnnotations() []LicenseAnnotation { 245 return []LicenseAnnotation{LicenseAnnotationSharedDependency} 246} 247 248// LicenseAnnotationToolchainDependencyTag can be embedded in a dependency tag to implement 249// LicenseAnnotations that always returns LicenseAnnotationToolchain. 250type LicenseAnnotationToolchainDependencyTag struct{} 251 252func (LicenseAnnotationToolchainDependencyTag) LicenseAnnotations() []LicenseAnnotation { 253 return []LicenseAnnotation{LicenseAnnotationToolchain} 254} 255