• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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