• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 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
17// This file generates the final rules for compiling all Java.  All properties related to
18// compiling should have been translated into javaBuilderFlags or another argument to the Transform*
19// functions.
20
21import (
22	"path/filepath"
23	"strconv"
24	"strings"
25
26	"github.com/google/blueprint"
27	"github.com/google/blueprint/proptools"
28
29	"android/soong/android"
30	"android/soong/remoteexec"
31)
32
33var (
34	pctx = android.NewPackageContext("android/soong/java")
35
36	// Compiling java is not conducive to proper dependency tracking.  The path-matches-class-name
37	// requirement leads to unpredictable generated source file names, and a single .java file
38	// will get compiled into multiple .class files if it contains inner classes.  To work around
39	// this, all java rules write into separate directories and then are combined into a .jar file
40	// (if the rule produces .class files) or a .srcjar file (if the rule produces .java files).
41	// .srcjar files are unzipped into a temporary directory when compiled with javac.
42	// TODO(b/143658984): goma can't handle the --system argument to javac.
43	javac, javacRE = pctx.MultiCommandRemoteStaticRules("javac",
44		blueprint.RuleParams{
45			Command: `rm -rf "$outDir" "$annoDir" "$annoSrcJar.tmp" "$srcJarDir" "$out.tmp" && ` +
46				`mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
47				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
48				`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
49				`${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
50				`${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` +
51				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
52				`-source $javaVersion -target $javaVersion ` +
53				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
54				`$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar.tmp -C $annoDir -D $annoDir && ` +
55				`$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` +
56				`if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` +
57				`if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` +
58				`rm -rf "$srcJarDir" "$outDir"`,
59			CommandDeps: []string{
60				"${config.JavacCmd}",
61				"${config.SoongZipCmd}",
62				"${config.ZipSyncCmd}",
63			},
64			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
65			Restat:           true,
66			Rspfile:          "$out.rsp",
67			RspfileContent:   "$in",
68		}, map[string]*remoteexec.REParams{
69			"$javaTemplate": &remoteexec.REParams{
70				Labels:       map[string]string{"type": "compile", "lang": "java", "compiler": "javac"},
71				ExecStrategy: "${config.REJavacExecStrategy}",
72				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
73			},
74			"$zipTemplate": &remoteexec.REParams{
75				Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
76				Inputs:       []string{"${config.SoongZipCmd}", "$outDir"},
77				OutputFiles:  []string{"$out.tmp"},
78				ExecStrategy: "${config.REJavacExecStrategy}",
79				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
80			},
81			"$annoSrcJarTemplate": &remoteexec.REParams{
82				Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
83				Inputs:       []string{"${config.SoongZipCmd}", "$annoDir"},
84				OutputFiles:  []string{"$annoSrcJar.tmp"},
85				ExecStrategy: "${config.REJavacExecStrategy}",
86				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
87			},
88		}, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
89			"outDir", "annoDir", "annoSrcJar", "javaVersion"}, nil)
90
91	_ = pctx.VariableFunc("kytheCorpus",
92		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
93	_ = pctx.VariableFunc("kytheCuEncoding",
94		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
95	_ = pctx.VariableFunc("kytheCuJavaSourceMax",
96		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuJavaSourceMax() })
97	_ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
98	// Run it with several --add-exports to allow the classes in the
99	// com.google.devtools.kythe.extractors.java.standalone package access the packages in the
100	// jdk.compiler compiler module. Long live Java modules.
101	kytheExtract = pctx.AndroidStaticRule("kythe",
102		blueprint.RuleParams{
103			Command: `${config.ZipSyncCmd} -d $srcJarDir ` +
104				`-l $srcJarDir/list -f "*.java" $srcJars && ` +
105				`( [ ! -s $srcJarDir/list -a ! -s $out.rsp ] || ` +
106				`KYTHE_ROOT_DIRECTORY=. KYTHE_OUTPUT_FILE=$out ` +
107				`KYTHE_CORPUS=${kytheCorpus} ` +
108				`KYTHE_VNAMES=${kytheVnames} ` +
109				`KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
110				`KYTHE_JAVA_SOURCE_BATCH_SIZE=${kytheCuJavaSourceMax} ` +
111				`${config.SoongJavacWrapper} ${config.JavaCmd} ` +
112				// Avoid JDK9's warning about "Illegal reflective access by com.google.protobuf.Utf8$UnsafeProcessor ...
113				// to field java.nio.Buffer.address"
114				`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
115				// Allow the classes in the com.google.devtools.kythe.extractors.java.standalone package
116				// access the packages in the jdk.compiler compiler module
117				`--add-opens=java.base/java.nio=ALL-UNNAMED ` +
118				`--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED ` +
119				`--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED ` +
120				`--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED ` +
121				`--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED ` +
122				`--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED ` +
123				`--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED ` +
124				`--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED ` +
125				`-jar ${config.JavaKytheExtractorJar} ` +
126				`${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
127				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
128				`-source $javaVersion -target $javaVersion ` +
129				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list)`,
130			CommandDeps: []string{
131				"${config.JavaCmd}",
132				"${config.JavaKytheExtractorJar}",
133				"${kytheVnames}",
134				"${config.ZipSyncCmd}",
135			},
136			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
137			Rspfile:          "$out.rsp",
138			RspfileContent:   "$in",
139		},
140		"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
141		"outDir", "annoDir", "javaVersion")
142
143	extractMatchingApks = pctx.StaticRule(
144		"extractMatchingApks",
145		blueprint.RuleParams{
146			Command: `rm -rf "$out" && ` +
147				`${config.ExtractApksCmd} -o "${out}" -zip "${zip}" -allow-prereleased=${allow-prereleased} ` +
148				`-sdk-version=${sdk-version} -skip-sdk-check=${skip-sdk-check} -abis=${abis} ` +
149				`--screen-densities=${screen-densities} --stem=${stem} ` +
150				`-apkcerts=${apkcerts} -partition=${partition} ` +
151				`${in}`,
152			CommandDeps: []string{"${config.ExtractApksCmd}"},
153		},
154		"abis", "allow-prereleased", "screen-densities", "sdk-version", "skip-sdk-check", "stem", "apkcerts", "partition", "zip")
155
156	turbine, turbineRE = pctx.RemoteStaticRules("turbine",
157		blueprint.RuleParams{
158			Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} $outputFlags ` +
159				`--sources @$out.rsp  --source_jars $srcJars ` +
160				`--javacopts ${config.CommonJdkFlags} ` +
161				`$javacFlags -source $javaVersion -target $javaVersion -- $turbineFlags && ` +
162				`(for o in $outputs; do if cmp -s $${o}.tmp $${o} ; then rm $${o}.tmp ; else mv $${o}.tmp $${o} ; fi; done )`,
163			CommandDeps: []string{
164				"${config.TurbineJar}",
165				"${config.JavaCmd}",
166			},
167			Rspfile:        "$out.rsp",
168			RspfileContent: "$in",
169			Restat:         true,
170		},
171		&remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"},
172			ExecStrategy:    "${config.RETurbineExecStrategy}",
173			Inputs:          []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"},
174			RSPFiles:        []string{"${out}.rsp"},
175			OutputFiles:     []string{"$rbeOutputs"},
176			ToolchainInputs: []string{"${config.JavaCmd}"},
177			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
178		},
179		[]string{"javacFlags", "turbineFlags", "outputFlags", "javaVersion", "outputs", "rbeOutputs", "srcJars"}, []string{"implicits"})
180
181	jar, jarRE = pctx.RemoteStaticRules("jar",
182		blueprint.RuleParams{
183			Command:        `$reTemplate${config.SoongZipCmd} -jar -o $out @$out.rsp`,
184			CommandDeps:    []string{"${config.SoongZipCmd}"},
185			Rspfile:        "$out.rsp",
186			RspfileContent: "$jarArgs",
187		},
188		&remoteexec.REParams{
189			ExecStrategy: "${config.REJarExecStrategy}",
190			Inputs:       []string{"${config.SoongZipCmd}", "${out}.rsp"},
191			RSPFiles:     []string{"${out}.rsp"},
192			OutputFiles:  []string{"$out"},
193			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
194		}, []string{"jarArgs"}, nil)
195
196	zip, zipRE = pctx.RemoteStaticRules("zip",
197		blueprint.RuleParams{
198			Command:        `${config.SoongZipCmd} -o $out @$out.rsp`,
199			CommandDeps:    []string{"${config.SoongZipCmd}"},
200			Rspfile:        "$out.rsp",
201			RspfileContent: "$jarArgs",
202		},
203		&remoteexec.REParams{
204			ExecStrategy: "${config.REZipExecStrategy}",
205			Inputs:       []string{"${config.SoongZipCmd}", "${out}.rsp", "$implicits"},
206			RSPFiles:     []string{"${out}.rsp"},
207			OutputFiles:  []string{"$out"},
208			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
209		}, []string{"jarArgs"}, []string{"implicits"})
210
211	combineJar = pctx.AndroidStaticRule("combineJar",
212		blueprint.RuleParams{
213			Command:     `${config.MergeZipsCmd} --ignore-duplicates -j $jarArgs $out $in`,
214			CommandDeps: []string{"${config.MergeZipsCmd}"},
215		},
216		"jarArgs")
217	combineJarRsp = pctx.AndroidStaticRule("combineJarRsp",
218		blueprint.RuleParams{
219			Command:        `${config.MergeZipsCmd} --ignore-duplicates -j $jarArgs $out @$out.rsp`,
220			CommandDeps:    []string{"${config.MergeZipsCmd}"},
221			Rspfile:        "$out.rsp",
222			RspfileContent: "$in",
223		},
224		"jarArgs")
225
226	jarjar = pctx.AndroidStaticRule("jarjar",
227		blueprint.RuleParams{
228			Command: "" +
229				// Jarjar doesn't exit with an error when the rules file contains a syntax error,
230				// leading to stale or missing files later in the build.  Remove the output file
231				// before running jarjar.
232				"rm -f ${out} && " +
233				"${config.JavaCmd} ${config.JavaVmFlags}" +
234				// b/146418363 Enable Android specific jarjar transformer to drop compat annotations
235				// for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes
236				// avoids adding new hiddenapis after jarjar'ing.
237				" -DremoveAndroidCompatAnnotations=true" +
238				" -jar ${config.JarjarCmd} process $rulesFile $in $out && " +
239				// Turn a missing output file into a ninja error
240				`[ -e ${out} ] || (echo "Missing output file"; exit 1)`,
241			CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
242		},
243		"rulesFile")
244
245	packageCheck = pctx.AndroidStaticRule("packageCheck",
246		blueprint.RuleParams{
247			Command: "rm -f $out && " +
248				"${config.PackageCheckCmd} $in $packages && " +
249				"touch $out",
250			CommandDeps: []string{"${config.PackageCheckCmd}"},
251		},
252		"packages")
253
254	jetifier = pctx.AndroidStaticRule("jetifier",
255		blueprint.RuleParams{
256			Command:     "${config.JavaCmd}  ${config.JavaVmFlags} -jar ${config.JetifierJar} -l error -o $out -i $in -t epoch",
257			CommandDeps: []string{"${config.JavaCmd}", "${config.JetifierJar}"},
258		},
259	)
260
261	zipalign = pctx.AndroidStaticRule("zipalign",
262		blueprint.RuleParams{
263			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
264				"${config.ZipAlign} -f -p 4 $in $out; " +
265				"else " +
266				"cp -f $in $out; " +
267				"fi",
268			CommandDeps: []string{"${config.ZipAlign}"},
269		},
270	)
271
272	convertImplementationJarToHeaderJarRule = pctx.AndroidStaticRule("convertImplementationJarToHeaderJar",
273		blueprint.RuleParams{
274			Command:     `${config.Zip2ZipCmd} -i ${in} -o ${out} -x 'META-INF/services/**/*'`,
275			CommandDeps: []string{"${config.Zip2ZipCmd}"},
276		})
277
278	writeCombinedProguardFlagsFileRule = pctx.AndroidStaticRule("writeCombinedProguardFlagsFileRule",
279		blueprint.RuleParams{
280			Command: `rm -f $out && ` +
281				`for f in $in; do ` +
282				` echo  && ` +
283				` echo "# including $$f" && ` +
284				` cat $$f; ` +
285				`done > $out`,
286		})
287
288	gatherReleasedFlaggedApisRule = pctx.AndroidStaticRule("gatherReleasedFlaggedApisRule",
289		blueprint.RuleParams{
290			Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}' ` +
291				`--out ${out} ` +
292				`${flags_path} ` +
293				`${filter_args} `,
294			CommandDeps: []string{"${aconfig}"},
295			Description: "aconfig_bool",
296		}, "flags_path", "filter_args")
297
298	generateMetalavaRevertAnnotationsRule = pctx.AndroidStaticRule("generateMetalavaRevertAnnotationsRule",
299		blueprint.RuleParams{
300			Command:     `${keep-flagged-apis} ${in} > ${out}`,
301			CommandDeps: []string{"${keep-flagged-apis}"},
302		})
303)
304
305func init() {
306	pctx.Import("android/soong/android")
307	pctx.Import("android/soong/java/config")
308
309	pctx.HostBinToolVariable("aconfig", "aconfig")
310	pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis")
311}
312
313type javaBuilderFlags struct {
314	javacFlags string
315
316	// bootClasspath is the list of jars that form the boot classpath (generally the java.* and
317	// android.* classes) for tools that still use it.  javac targeting 1.9 or higher uses
318	// systemModules and java9Classpath instead.
319	bootClasspath classpath
320
321	// classpath is the list of jars that form the classpath for javac and kotlinc rules.  It
322	// contains header jars for all static and non-static dependencies.
323	classpath classpath
324
325	// dexClasspath is the list of jars that form the classpath for d8 and r8 rules.  It contains
326	// header jars for all non-static dependencies.  Static dependencies have already been
327	// combined into the program jar.
328	dexClasspath classpath
329
330	// java9Classpath is the list of jars that will be added to the classpath when targeting
331	// 1.9 or higher.  It generally contains the android.* classes, while the java.* classes
332	// are provided by systemModules.
333	java9Classpath classpath
334
335	processorPath classpath
336	processors    []string
337	systemModules *systemModules
338	aidlFlags     string
339	aidlDeps      android.Paths
340	javaVersion   javaVersion
341
342	errorProneExtraJavacFlags string
343	errorProneProcessorPath   classpath
344
345	kotlincFlags     string
346	kotlincClasspath classpath
347	kotlincDeps      android.Paths
348
349	proto android.ProtoFlags
350}
351
352func DefaultJavaBuilderFlags() javaBuilderFlags {
353	return javaBuilderFlags{
354		javaVersion: JAVA_VERSION_8,
355	}
356}
357
358func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int,
359	srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) {
360
361	// Compile java sources into .class files
362	desc := "javac"
363	if shardIdx >= 0 {
364		desc += strconv.Itoa(shardIdx)
365	}
366
367	transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, flags, deps, "javac", desc)
368}
369
370// Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
371// to compile with given set of builder flags, etc.
372func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx int,
373	srcFiles, srcJars android.Paths,
374	flags javaBuilderFlags, deps android.Paths) {
375
376	deps = append(deps, srcJars...)
377	classpath := flags.classpath
378
379	var bootClasspath string
380	if flags.javaVersion.usesJavaModules() {
381		var systemModuleDeps android.Paths
382		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
383		deps = append(deps, systemModuleDeps...)
384		classpath = append(flags.java9Classpath, classpath...)
385	} else {
386		deps = append(deps, flags.bootClasspath...)
387		if len(flags.bootClasspath) == 0 && ctx.Device() {
388			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
389			// ensure java does not fall back to the default bootclasspath.
390			bootClasspath = `-bootclasspath ""`
391		} else {
392			bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath")
393		}
394	}
395
396	deps = append(deps, classpath...)
397	deps = append(deps, flags.processorPath...)
398
399	processor := "-proc:none"
400	if len(flags.processors) > 0 {
401		processor = "-processor " + strings.Join(flags.processors, ",")
402	}
403
404	intermediatesDir := "xref"
405	if idx >= 0 {
406		intermediatesDir += strconv.Itoa(idx)
407	}
408
409	ctx.Build(pctx,
410		android.BuildParams{
411			Rule:        kytheExtract,
412			Description: "Xref Java extractor",
413			Output:      xrefFile,
414			Inputs:      srcFiles,
415			Implicits:   deps,
416			Args: map[string]string{
417				"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, "anno").String(),
418				"bootClasspath": bootClasspath,
419				"classpath":     classpath.FormJavaClassPath("-classpath"),
420				"javacFlags":    flags.javacFlags,
421				"javaVersion":   flags.javaVersion.String(),
422				"outDir":        android.PathForModuleOut(ctx, "javac", "classes.xref").String(),
423				"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
424				"processor":     processor,
425				"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, "srcjars.xref").String(),
426				"srcJars":       strings.Join(srcJars.Strings(), " "),
427			},
428		})
429}
430
431func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string) (string, android.Paths) {
432	var deps android.Paths
433
434	classpath := flags.classpath
435
436	var bootClasspath string
437	if flags.javaVersion.usesJavaModules() {
438		var systemModuleDeps android.Paths
439		bootClasspath, systemModuleDeps = flags.systemModules.FormTurbineSystemModulesPath(ctx.Device())
440		deps = append(deps, systemModuleDeps...)
441		classpath = append(flags.java9Classpath, classpath...)
442	} else {
443		deps = append(deps, flags.bootClasspath...)
444		if len(flags.bootClasspath) == 0 && ctx.Device() {
445			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
446			// ensure turbine does not fall back to the default bootclasspath.
447			bootClasspath = `--bootclasspath ""`
448		} else {
449			bootClasspath = flags.bootClasspath.FormTurbineClassPath("--bootclasspath ")
450		}
451	}
452
453	deps = append(deps, classpath...)
454	turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ")
455
456	const flagsLimit = 32 * 1024
457	if len(turbineFlags) > flagsLimit {
458		flagsRspFile := android.PathForModuleOut(ctx, dir, "turbine-flags.rsp")
459		android.WriteFileRule(ctx, flagsRspFile, turbineFlags)
460		turbineFlags = "@" + flagsRspFile.String()
461		deps = append(deps, flagsRspFile)
462	}
463
464	return turbineFlags, deps
465}
466
467func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
468	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
469
470	turbineFlags, deps := turbineFlags(ctx, flags, "turbine")
471
472	deps = append(deps, srcJars...)
473
474	rule := turbine
475	args := map[string]string{
476		"javacFlags":   flags.javacFlags,
477		"srcJars":      strings.Join(srcJars.Strings(), " "),
478		"javaVersion":  flags.javaVersion.String(),
479		"turbineFlags": turbineFlags,
480		"outputFlags":  "--output " + outputFile.String() + ".tmp",
481		"outputs":      outputFile.String(),
482	}
483	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
484		rule = turbineRE
485		args["implicits"] = strings.Join(deps.Strings(), ",")
486		args["rbeOutputs"] = outputFile.String() + ".tmp"
487	}
488	ctx.Build(pctx, android.BuildParams{
489		Rule:        rule,
490		Description: "turbine",
491		Output:      outputFile,
492		Inputs:      srcFiles,
493		Implicits:   deps,
494		Args:        args,
495	})
496}
497
498// TurbineApt produces a rule to run annotation processors using turbine.
499func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath,
500	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
501
502	turbineFlags, deps := turbineFlags(ctx, flags, "kapt")
503
504	deps = append(deps, srcJars...)
505
506	deps = append(deps, flags.processorPath...)
507	turbineFlags += " " + flags.processorPath.FormTurbineClassPath("--processorpath ")
508	turbineFlags += " --processors " + strings.Join(flags.processors, " ")
509
510	outputs := android.WritablePaths{outputSrcJar, outputResJar}
511	outputFlags := "--gensrc_output " + outputSrcJar.String() + ".tmp " +
512		"--resource_output " + outputResJar.String() + ".tmp"
513
514	rule := turbine
515	args := map[string]string{
516		"javacFlags":   flags.javacFlags,
517		"srcJars":      strings.Join(srcJars.Strings(), " "),
518		"javaVersion":  flags.javaVersion.String(),
519		"turbineFlags": turbineFlags,
520		"outputFlags":  outputFlags,
521		"outputs":      strings.Join(outputs.Strings(), " "),
522	}
523	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
524		rule = turbineRE
525		args["implicits"] = strings.Join(deps.Strings(), ",")
526		args["rbeOutputs"] = outputSrcJar.String() + ".tmp," + outputResJar.String() + ".tmp"
527	}
528	ctx.Build(pctx, android.BuildParams{
529		Rule:            rule,
530		Description:     "turbine apt",
531		Output:          outputs[0],
532		ImplicitOutputs: outputs[1:],
533		Inputs:          srcFiles,
534		Implicits:       deps,
535		Args:            args,
536	})
537}
538
539// transformJavaToClasses takes source files and converts them to a jar containing .class files.
540// srcFiles is a list of paths to sources, srcJars is a list of paths to jar files that contain
541// sources.  flags contains various command line flags to be passed to the compiler.
542//
543// This method may be used for different compilers, including javac and Error Prone.  The rule
544// argument specifies which command line to use and desc sets the description of the rule that will
545// be printed at build time.  The stem argument provides the file name of the output jar, and
546// suffix will be appended to various intermediate files and directories to avoid collisions when
547// this function is called twice in the same module directory.
548func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
549	shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath,
550	flags javaBuilderFlags, deps android.Paths,
551	intermediatesDir, desc string) {
552
553	deps = append(deps, srcJars...)
554
555	javacClasspath := flags.classpath
556
557	var bootClasspath string
558	if flags.javaVersion.usesJavaModules() {
559		var systemModuleDeps android.Paths
560		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
561		deps = append(deps, systemModuleDeps...)
562		javacClasspath = append(flags.java9Classpath, javacClasspath...)
563	} else {
564		deps = append(deps, flags.bootClasspath...)
565		if len(flags.bootClasspath) == 0 && ctx.Device() {
566			// explicitly specify -bootclasspath "" if the bootclasspath is empty to
567			// ensure java does not fall back to the default bootclasspath.
568			bootClasspath = `-bootclasspath ""`
569		} else {
570			bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath")
571		}
572	}
573
574	classpathArg := javacClasspath.FormJavaClassPath("-classpath")
575
576	// Keep the command line under the MAX_ARG_STRLEN limit by putting the classpath argument into an rsp file
577	// if it is too long.
578	const classpathLimit = 64 * 1024
579	if len(classpathArg) > classpathLimit {
580		classpathRspFile := outputFile.ReplaceExtension(ctx, "classpath")
581		android.WriteFileRule(ctx, classpathRspFile, classpathArg)
582		deps = append(deps, classpathRspFile)
583		classpathArg = "@" + classpathRspFile.String()
584	}
585
586	deps = append(deps, javacClasspath...)
587	deps = append(deps, flags.processorPath...)
588
589	processor := "-proc:none"
590	if len(flags.processors) > 0 {
591		processor = "-processor " + strings.Join(flags.processors, ",")
592	}
593
594	srcJarDir := "srcjars"
595	outDir := "classes"
596	annoDir := "anno"
597	if shardIdx >= 0 {
598		shardDir := "shard" + strconv.Itoa(shardIdx)
599		srcJarDir = filepath.Join(shardDir, srcJarDir)
600		outDir = filepath.Join(shardDir, outDir)
601		annoDir = filepath.Join(shardDir, annoDir)
602	}
603	rule := javac
604	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAVAC") {
605		rule = javacRE
606	}
607	ctx.Build(pctx, android.BuildParams{
608		Rule:           rule,
609		Description:    desc,
610		Output:         outputFile,
611		ImplicitOutput: annoSrcJar,
612		Inputs:         srcFiles,
613		Implicits:      deps,
614		Args: map[string]string{
615			"javacFlags":    flags.javacFlags,
616			"bootClasspath": bootClasspath,
617			"classpath":     classpathArg,
618			"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
619			"processor":     processor,
620			"srcJars":       strings.Join(srcJars.Strings(), " "),
621			"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(),
622			"outDir":        android.PathForModuleOut(ctx, intermediatesDir, outDir).String(),
623			"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(),
624			"annoSrcJar":    annoSrcJar.String(),
625			"javaVersion":   flags.javaVersion.String(),
626		},
627	})
628}
629
630func TransformResourcesToJar(ctx android.ModuleContext, outputFile android.WritablePath,
631	jarArgs []string, deps android.Paths) {
632
633	rule := jar
634	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAR") {
635		rule = jarRE
636	}
637	ctx.Build(pctx, android.BuildParams{
638		Rule:        rule,
639		Description: "jar",
640		Output:      outputFile,
641		Implicits:   deps,
642		Args: map[string]string{
643			"jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
644		},
645	})
646}
647
648func TransformJarsToJar(ctx android.ModuleContext, outputFile android.WritablePath, desc string,
649	jars android.Paths, manifest android.OptionalPath, stripDirEntries bool, filesToStrip []string,
650	dirsToStrip []string) {
651
652	var deps android.Paths
653
654	var jarArgs []string
655	if manifest.Valid() {
656		jarArgs = append(jarArgs, "-m ", manifest.String())
657		deps = append(deps, manifest.Path())
658	}
659
660	for _, dir := range dirsToStrip {
661		jarArgs = append(jarArgs, "-stripDir ", dir)
662	}
663
664	for _, file := range filesToStrip {
665		jarArgs = append(jarArgs, "-stripFile ", file)
666	}
667
668	// Remove any module-info.class files that may have come from prebuilt jars, they cause problems
669	// for downstream tools like desugar.
670	jarArgs = append(jarArgs, "-stripFile module-info.class")
671
672	if stripDirEntries {
673		jarArgs = append(jarArgs, "-D")
674	}
675
676	rule := combineJar
677	// Keep the command line under the MAX_ARG_STRLEN limit by putting the list of jars into an rsp file
678	// if it is too long.
679	const jarsLengthLimit = 64 * 1024
680	jarsLength := 0
681	for i, jar := range jars {
682		if i != 0 {
683			jarsLength += 1
684		}
685		jarsLength += len(jar.String())
686	}
687	if jarsLength > jarsLengthLimit {
688		rule = combineJarRsp
689	}
690
691	ctx.Build(pctx, android.BuildParams{
692		Rule:        rule,
693		Description: desc,
694		Output:      outputFile,
695		Inputs:      jars,
696		Implicits:   deps,
697		Args: map[string]string{
698			"jarArgs": strings.Join(jarArgs, " "),
699		},
700	})
701}
702
703func convertImplementationJarToHeaderJar(ctx android.ModuleContext, implementationJarFile android.Path,
704	headerJarFile android.WritablePath) {
705	ctx.Build(pctx, android.BuildParams{
706		Rule:   convertImplementationJarToHeaderJarRule,
707		Input:  implementationJarFile,
708		Output: headerJarFile,
709	})
710}
711
712func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath,
713	classesJar android.Path, rulesFile android.Path) {
714	ctx.Build(pctx, android.BuildParams{
715		Rule:        jarjar,
716		Description: "jarjar",
717		Output:      outputFile,
718		Input:       classesJar,
719		Implicit:    rulesFile,
720		Args: map[string]string{
721			"rulesFile": rulesFile.String(),
722		},
723	})
724}
725
726func CheckJarPackages(ctx android.ModuleContext, outputFile android.WritablePath,
727	classesJar android.Path, permittedPackages []string) {
728	ctx.Build(pctx, android.BuildParams{
729		Rule:        packageCheck,
730		Description: "packageCheck",
731		Output:      outputFile,
732		Input:       classesJar,
733		Args: map[string]string{
734			"packages": strings.Join(permittedPackages, " "),
735		},
736	})
737}
738
739func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePath,
740	inputFile android.Path) {
741	ctx.Build(pctx, android.BuildParams{
742		Rule:        jetifier,
743		Description: "jetifier",
744		Output:      outputFile,
745		Input:       inputFile,
746	})
747}
748
749func GenerateMainClassManifest(ctx android.ModuleContext, outputFile android.WritablePath, mainClass string) {
750	android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n")
751}
752
753func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path, validations android.Paths) {
754	ctx.Build(pctx, android.BuildParams{
755		Rule:        zipalign,
756		Description: "align",
757		Input:       inputFile,
758		Output:      outputFile,
759		Validations: validations,
760	})
761}
762
763func writeCombinedProguardFlagsFile(ctx android.ModuleContext, outputFile android.WritablePath, files android.Paths) {
764	ctx.Build(pctx, android.BuildParams{
765		Rule:        writeCombinedProguardFlagsFileRule,
766		Description: "write combined proguard flags file",
767		Inputs:      files,
768		Output:      outputFile,
769	})
770}
771
772type classpath android.Paths
773
774func (x *classpath) formJoinedClassPath(optName string, sep string) string {
775	if optName != "" && !strings.HasSuffix(optName, "=") && !strings.HasSuffix(optName, " ") {
776		optName += " "
777	}
778	if len(*x) > 0 {
779		return optName + strings.Join(x.Strings(), sep)
780	} else {
781		return ""
782	}
783}
784func (x *classpath) FormJavaClassPath(optName string) string {
785	return x.formJoinedClassPath(optName, ":")
786}
787
788func (x *classpath) FormTurbineClassPath(optName string) string {
789	return x.formJoinedClassPath(optName, " ")
790}
791
792// FormRepeatedClassPath returns a list of arguments with the given optName prefixed to each element of the classpath.
793func (x *classpath) FormRepeatedClassPath(optName string) []string {
794	if x == nil || *x == nil {
795		return nil
796	}
797	flags := make([]string, len(*x))
798	for i, v := range *x {
799		flags[i] = optName + v.String()
800	}
801
802	return flags
803}
804
805// Convert a classpath to an android.Paths
806func (x *classpath) Paths() android.Paths {
807	return append(android.Paths(nil), (*x)...)
808}
809
810func (x *classpath) Strings() []string {
811	if x == nil {
812		return nil
813	}
814	ret := make([]string, len(*x))
815	for i, path := range *x {
816		ret[i] = path.String()
817	}
818	return ret
819}
820
821type systemModules struct {
822	dir  android.Path
823	deps android.Paths
824}
825
826// Returns a --system argument in the form javac expects with -source 1.9 and the list of files to
827// depend on.  If forceEmpty is true, returns --system=none if the list is empty to ensure javac
828// does not fall back to the default system modules.
829func (x *systemModules) FormJavaSystemModulesPath(forceEmpty bool) (string, android.Paths) {
830	if x != nil {
831		return "--system=" + x.dir.String(), x.deps
832	} else if forceEmpty {
833		return "--system=none", nil
834	} else {
835		return "", nil
836	}
837}
838
839// Returns a --system argument in the form turbine expects with -source 1.9 and the list of files to
840// depend on.  If forceEmpty is true, returns --bootclasspath "" if the list is empty to ensure turbine
841// does not fall back to the default bootclasspath.
842func (x *systemModules) FormTurbineSystemModulesPath(forceEmpty bool) (string, android.Paths) {
843	if x != nil {
844		return "--system " + x.dir.String(), x.deps
845	} else if forceEmpty {
846		return `--bootclasspath ""`, nil
847	} else {
848		return "--system ${config.JavaHome}", nil
849	}
850}
851