1// Copyright 2019 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 java 16 17import ( 18 "fmt" 19 "io" 20 21 "android/soong/android" 22 "android/soong/dexpreopt" 23 24 "github.com/google/blueprint/depset" 25 "github.com/google/blueprint/proptools" 26) 27 28type GenruleCombiner struct { 29 android.ModuleBase 30 android.DefaultableModuleBase 31 32 genruleCombinerProperties GenruleCombinerProperties 33 34 headerJars android.Paths 35 implementationJars android.Paths 36 implementationAndResourceJars android.Paths 37 resourceJars android.Paths 38 aconfigProtoFiles android.Paths 39 40 srcJarArgs []string 41 srcJarDeps android.Paths 42 43 headerDirs android.Paths 44 45 combinedHeaderJar android.Path 46 combinedImplementationJar android.Path 47} 48 49type GenruleCombinerProperties struct { 50 // List of modules whose implementation (and resources) jars will be visible to modules 51 // that depend on this module. 52 Static_libs proptools.Configurable[[]string] `android:"arch_variant"` 53 54 // List of modules whose header jars will be visible to modules that depend on this module. 55 Headers proptools.Configurable[[]string] `android:"arch_variant"` 56} 57 58// java_genrule_combiner provides the implementation and resource jars from `static_libs`, with 59// the header jars from `headers`. 60// 61// This is useful when a java_genrule is used to change the implementation of a java library 62// without requiring a change in the header jars. 63func GenruleCombinerFactory() android.Module { 64 module := &GenruleCombiner{} 65 66 module.AddProperties(&module.genruleCombinerProperties) 67 InitJavaModule(module, android.HostAndDeviceSupported) 68 return module 69} 70 71var genruleCombinerHeaderDepTag = dependencyTag{name: "genrule_combiner_header"} 72 73func (j *GenruleCombiner) DepsMutator(ctx android.BottomUpMutatorContext) { 74 ctx.AddVariationDependencies(nil, staticLibTag, 75 j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) 76 ctx.AddVariationDependencies(nil, genruleCombinerHeaderDepTag, 77 j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) 78} 79 80func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) { 81 if len(j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)) < 1 { 82 ctx.PropertyErrorf("static_libs", "at least one dependency is required") 83 } 84 85 if len(j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)) < 1 { 86 ctx.PropertyErrorf("headers", "at least one dependency is required") 87 } 88 89 var transitiveHeaderJars []depset.DepSet[android.Path] 90 var transitiveImplementationJars []depset.DepSet[android.Path] 91 var transitiveResourceJars []depset.DepSet[android.Path] 92 var sdkVersion android.SdkSpec 93 var stubsLinkType StubsLinkType 94 moduleWithSdkDepInfo := &ModuleWithSdkDepInfo{} 95 96 // Collect the headers first, so that aconfig flag values for the libraries will override 97 // values from the headers (if they are different). 98 ctx.VisitDirectDepsWithTag(genruleCombinerHeaderDepTag, func(m android.Module) { 99 if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { 100 j.headerJars = append(j.headerJars, dep.HeaderJars...) 101 102 j.srcJarArgs = append(j.srcJarArgs, dep.SrcJarArgs...) 103 j.srcJarDeps = append(j.srcJarDeps, dep.SrcJarDeps...) 104 j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) 105 sdkVersion = dep.SdkVersion 106 stubsLinkType = dep.StubsLinkType 107 *moduleWithSdkDepInfo = *dep.ModuleWithSdkDepInfo 108 109 transitiveHeaderJars = append(transitiveHeaderJars, dep.TransitiveStaticLibsHeaderJars) 110 } else if dep, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok { 111 j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) 112 } else { 113 ctx.PropertyErrorf("headers", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) 114 } 115 }) 116 ctx.VisitDirectDepsWithTag(staticLibTag, func(m android.Module) { 117 if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { 118 j.implementationJars = append(j.implementationJars, dep.ImplementationJars...) 119 j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.ImplementationAndResourcesJars...) 120 j.resourceJars = append(j.resourceJars, dep.ResourceJars...) 121 122 transitiveImplementationJars = append(transitiveImplementationJars, dep.TransitiveStaticLibsImplementationJars) 123 transitiveResourceJars = append(transitiveResourceJars, dep.TransitiveStaticLibsResourceJars) 124 j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) 125 } else if dep, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok { 126 // This is provided by `java_genrule` modules. 127 j.implementationJars = append(j.implementationJars, dep.DefaultOutputFiles...) 128 j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.DefaultOutputFiles...) 129 stubsLinkType = Implementation 130 } else { 131 ctx.PropertyErrorf("static_libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) 132 } 133 }) 134 135 jarName := ctx.ModuleName() + ".jar" 136 137 if len(j.implementationAndResourceJars) > 1 { 138 outputFile := android.PathForModuleOut(ctx, "combined", jarName) 139 TransformJarsToJar(ctx, outputFile, "combine", j.implementationAndResourceJars, 140 android.OptionalPath{}, false, nil, nil) 141 j.combinedImplementationJar = outputFile 142 } else if len(j.implementationAndResourceJars) == 1 { 143 j.combinedImplementationJar = j.implementationAndResourceJars[0] 144 } 145 146 if len(j.headerJars) > 1 { 147 outputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName) 148 TransformJarsToJar(ctx, outputFile, "turbine combine", j.headerJars, 149 android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"}) 150 j.combinedHeaderJar = outputFile 151 j.headerDirs = append(j.headerDirs, android.PathForModuleOut(ctx, "turbine-combined")) 152 } else if len(j.headerJars) == 1 { 153 j.combinedHeaderJar = j.headerJars[0] 154 } 155 156 javaInfo := &JavaInfo{ 157 HeaderJars: android.Paths{j.combinedHeaderJar}, 158 LocalHeaderJars: android.Paths{j.combinedHeaderJar}, 159 TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, android.Paths{j.combinedHeaderJar}, transitiveHeaderJars), 160 TransitiveStaticLibsImplementationJars: depset.New(depset.PREORDER, android.Paths{j.combinedImplementationJar}, transitiveImplementationJars), 161 TransitiveStaticLibsResourceJars: depset.New(depset.PREORDER, nil, transitiveResourceJars), 162 GeneratedSrcjars: android.Paths{j.combinedImplementationJar}, 163 ImplementationAndResourcesJars: android.Paths{j.combinedImplementationJar}, 164 ImplementationJars: android.Paths{j.combinedImplementationJar}, 165 ModuleWithSdkDepInfo: moduleWithSdkDepInfo, 166 ResourceJars: j.resourceJars, 167 OutputFile: j.combinedImplementationJar, 168 SdkVersion: sdkVersion, 169 SrcJarArgs: j.srcJarArgs, 170 SrcJarDeps: j.srcJarDeps, 171 StubsLinkType: stubsLinkType, 172 AconfigIntermediateCacheOutputPaths: j.aconfigProtoFiles, 173 } 174 setExtraJavaInfo(ctx, j, javaInfo) 175 ctx.SetOutputFiles(android.Paths{javaInfo.OutputFile}, "") 176 ctx.SetOutputFiles(android.Paths{javaInfo.OutputFile}, android.DefaultDistTag) 177 ctx.SetOutputFiles(javaInfo.ImplementationAndResourcesJars, ".jar") 178 ctx.SetOutputFiles(javaInfo.HeaderJars, ".hjar") 179 android.SetProvider(ctx, JavaInfoProvider, javaInfo) 180 181} 182 183func (j *GenruleCombiner) GeneratedSourceFiles() android.Paths { 184 return append(android.Paths{}, j.combinedImplementationJar) 185} 186 187func (j *GenruleCombiner) GeneratedHeaderDirs() android.Paths { 188 return append(android.Paths{}, j.headerDirs...) 189} 190 191func (j *GenruleCombiner) GeneratedDeps() android.Paths { 192 return append(android.Paths{}, j.combinedImplementationJar) 193} 194 195func (j *GenruleCombiner) Srcs() android.Paths { 196 return append(android.Paths{}, j.implementationAndResourceJars...) 197} 198 199func (j *GenruleCombiner) HeaderJars() android.Paths { 200 return j.headerJars 201} 202 203func (j *GenruleCombiner) ImplementationAndResourcesJars() android.Paths { 204 return j.implementationAndResourceJars 205} 206 207func (j *GenruleCombiner) DexJarBuildPath(ctx android.ModuleErrorfContext) android.Path { 208 return nil 209} 210 211func (j *GenruleCombiner) DexJarInstallPath() android.Path { 212 return nil 213} 214 215func (j *GenruleCombiner) AidlIncludeDirs() android.Paths { 216 return nil 217} 218 219func (j *GenruleCombiner) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { 220 return nil 221} 222 223func (j *GenruleCombiner) JacocoReportClassesFile() android.Path { 224 return nil 225} 226 227func (j *GenruleCombiner) AndroidMk() android.AndroidMkData { 228 return android.AndroidMkData{ 229 Class: "JAVA_LIBRARIES", 230 OutputFile: android.OptionalPathForPath(j.combinedImplementationJar), 231 // Make does not support Windows Java modules 232 Disabled: j.Os() == android.Windows, 233 Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", 234 Extra: []android.AndroidMkExtraFunc{ 235 func(w io.Writer, outputFile android.Path) { 236 fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") 237 fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", j.combinedHeaderJar.String()) 238 fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", j.combinedImplementationJar.String()) 239 }, 240 }, 241 } 242} 243 244// implement the following interface for IDE completion. 245var _ android.IDEInfo = (*GenruleCombiner)(nil) 246 247func (j *GenruleCombiner) IDEInfo(ctx android.BaseModuleContext, ideInfo *android.IdeInfo) { 248 ideInfo.Deps = append(ideInfo.Deps, j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) 249 ideInfo.Libs = append(ideInfo.Libs, j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) 250 ideInfo.Deps = append(ideInfo.Deps, j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) 251 ideInfo.Libs = append(ideInfo.Libs, j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) 252} 253