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