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