diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Android.bp | 66 | ||||
| -rw-r--r-- | java/androidmk.go | 21 | ||||
| -rwxr-xr-x | java/app.go | 31 | ||||
| -rw-r--r-- | java/app_builder.go | 44 | ||||
| -rw-r--r-- | java/app_test.go | 121 | ||||
| -rw-r--r-- | java/builder.go | 103 | ||||
| -rw-r--r-- | java/config/Android.bp | 15 | ||||
| -rw-r--r-- | java/config/config.go | 31 | ||||
| -rw-r--r-- | java/dex.go | 75 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars.go | 4 | ||||
| -rw-r--r-- | java/java.go | 25 | ||||
| -rw-r--r-- | java/java_test.go | 27 | ||||
| -rw-r--r-- | java/sdk_library.go | 27 |
13 files changed, 506 insertions, 84 deletions
diff --git a/java/Android.bp b/java/Android.bp new file mode 100644 index 000000000..2de1b8ea1 --- /dev/null +++ b/java/Android.bp @@ -0,0 +1,66 @@ +bootstrap_go_package { + name: "soong-java", + pkgPath: "android/soong/java", + deps: [ + "blueprint", + "blueprint-pathtools", + "soong", + "soong-android", + "soong-cc", + "soong-dexpreopt", + "soong-genrule", + "soong-java-config", + "soong-remoteexec", + "soong-tradefed", + ], + srcs: [ + "aapt2.go", + "aar.go", + "android_manifest.go", + "android_resources.go", + "androidmk.go", + "app_builder.go", + "app.go", + "builder.go", + "device_host_converter.go", + "dex.go", + "dexpreopt.go", + "dexpreopt_bootjars.go", + "dexpreopt_config.go", + "droiddoc.go", + "gen.go", + "genrule.go", + "hiddenapi.go", + "hiddenapi_singleton.go", + "jacoco.go", + "java.go", + "jdeps.go", + "java_resources.go", + "kotlin.go", + "platform_compat_config.go", + "plugin.go", + "prebuilt_apis.go", + "proto.go", + "robolectric.go", + "sdk.go", + "sdk_library.go", + "support_libraries.go", + "sysprop.go", + "system_modules.go", + "testing.go", + "tradefed.go", + ], + testSrcs: [ + "androidmk_test.go", + "app_test.go", + "device_host_converter_test.go", + "dexpreopt_test.go", + "dexpreopt_bootjars_test.go", + "java_test.go", + "jdeps_test.go", + "kotlin_test.go", + "plugin_test.go", + "sdk_test.go", + ], + pluginFor: ["soong_build"], +} diff --git a/java/androidmk.go b/java/androidmk.go index 861bb5e99..75fb5fb02 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -69,7 +69,26 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) { hideFromMake = true } - if !hideFromMake { + if hideFromMake { + // May still need to add some additional dependencies. This will be called + // once for the platform variant (even if it is not being used) and once each + // for the APEX specific variants. In order to avoid adding the dependency + // multiple times only add it for the platform variant. + checkedModulePaths := library.additionalCheckedModules + if library.IsForPlatform() && len(checkedModulePaths) != 0 { + mainEntries = android.AndroidMkEntries{ + Class: "FAKE", + // Need at least one output file in order for this to take effect. + OutputFile: android.OptionalPathForPath(checkedModulePaths[0]), + Include: "$(BUILD_PHONY_PACKAGE)", + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(entries *android.AndroidMkEntries) { + entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", checkedModulePaths.Strings()...) + }, + }, + } + } + } else { mainEntries = android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", DistFile: android.OptionalPathForPath(library.distFile), diff --git a/java/app.go b/java/app.go index e44b87d92..5bc09ff4d 100755 --- a/java/app.go +++ b/java/app.go @@ -421,12 +421,43 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if String(a.deviceProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } + if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil { + a.checkJniLibsSdkVersion(ctx, minSdkVersion) + } else { + ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) + } } a.checkPlatformAPI(ctx) a.checkSdkVersions(ctx) } +// If an updatable APK sets min_sdk_version, min_sdk_vesion of JNI libs should match with it. +// This check is enforced for "updatable" APKs (including APK-in-APEX). +// b/155209650: until min_sdk_version is properly supported, use sdk_version instead. +// because, sdk_version is overridden by min_sdk_version (if set as smaller) +// and linkType is checked with dependencies so we can be sure that the whole dependency tree +// will meet the requirements. +func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion sdkVersion) { + // It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType() + ctx.VisitDirectDeps(func(m android.Module) { + if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) { + return + } + dep, _ := m.(*cc.Module) + // The domain of cc.sdk_version is "current" and <number> + // We can rely on sdkSpec to convert it to <number> so that "current" is handled + // properly regardless of sdk finalization. + jniSdkVersion, err := sdkSpecFrom(dep.SdkVersion()).effectiveVersion(ctx) + if err != nil || minSdkVersion < jniSdkVersion { + ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", + dep.SdkVersion(), minSdkVersion, ctx.ModuleName()) + return + } + + }) +} + // Returns true if the native libraries should be stored in the APK uncompressed and the // extractNativeLibs application flag should be set to false in the manifest. func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool { diff --git a/java/app_builder.go b/java/app_builder.go index 967c55fcc..97ec269ee 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -26,16 +26,23 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/remoteexec" ) var ( - Signapk = pctx.AndroidStaticRule("signapk", + Signapk, SignapkRE = remoteexec.StaticRules(pctx, "signapk", blueprint.RuleParams{ - Command: `${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` + + Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -Djava.library.path=$$(dirname ${config.SignapkJniLibrary}) ` + `-jar ${config.SignapkCmd} $flags $certificates $in $out`, CommandDeps: []string{"${config.SignapkCmd}", "${config.SignapkJniLibrary}"}, }, - "flags", "certificates") + &remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "signapk"}, + ExecStrategy: "${config.RESignApkExecStrategy}", + Inputs: []string{"${config.SignapkCmd}", "$in", "$$(dirname ${config.SignapkJniLibrary})", "$implicits"}, + OutputFiles: []string{"$outCommaList"}, + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, []string{"flags", "certificates"}, []string{"implicits", "outCommaList"}) ) var combineApk = pctx.AndroidStaticRule("combineApk", @@ -90,16 +97,23 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u deps = append(deps, lineageFile) } + rule := Signapk + args := map[string]string{ + "certificates": strings.Join(certificateArgs, " "), + "flags": strings.Join(flags, " "), + } + if ctx.Config().IsEnvTrue("RBE_SIGNAPK") { + rule = SignapkRE + args["implicits"] = strings.Join(deps.Strings(), ",") + args["outCommaList"] = strings.Join(outputFiles.Strings(), ",") + } ctx.Build(pctx, android.BuildParams{ - Rule: Signapk, + Rule: rule, Description: "signapk", Outputs: outputFiles, Input: unsignedApk, Implicits: deps, - Args: map[string]string{ - "certificates": strings.Join(certificateArgs, " "), - "flags": strings.Join(flags, " "), - }, + Args: args, }) } @@ -223,14 +237,20 @@ func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.Writabl "-f", j.path.String()) } + rule := zip + args := map[string]string{ + "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "), + } + if ctx.Config().IsEnvTrue("RBE_ZIP") { + rule = zipRE + args["implicits"] = strings.Join(deps.Strings(), ",") + } ctx.Build(pctx, android.BuildParams{ - Rule: zip, + Rule: rule, Description: "zip jni libs", Output: outputFile, Implicits: deps, - Args: map[string]string{ - "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "), - }, + Args: args, }) } diff --git a/java/app_test.go b/java/app_test.go index 8afd97d9e..e686f2780 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -473,6 +473,127 @@ func TestUpdatableApps(t *testing.T) { } } +func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) { + testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "current", + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + system_shared_libs: [], + sdk_version: "current", + } + `) +} + +func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { + bp := cc.GatherRequiredDepsForTest(android.Android) + ` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + system_shared_libs: [], + sdk_version: "29", + } + + ndk_prebuilt_object { + name: "ndk_crtbegin_so.29", + sdk_version: "29", + } + + ndk_prebuilt_object { + name: "ndk_crtend_so.29", + sdk_version: "29", + } + ` + fs := map[string][]byte{ + "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": nil, + "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": nil, + "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtbegin_so.o": nil, + "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtend_so.o": nil, + } + + ctx, _ := testJavaWithConfig(t, testConfig(nil, bp, fs)) + + inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits + var crtbeginFound, crtendFound bool + for _, input := range inputs { + switch input.String() { + case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": + crtbeginFound = true + case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": + crtendFound = true + } + } + if !crtbeginFound || !crtendFound { + t.Error("should link with ndk_crtbegin_so.29 and ndk_crtend_so.29") + } +} + +func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) { + bp := cc.GatherRequiredDepsForTest(android.Android) + ` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", // this APK should support 29 + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + sdk_version: "current", + } + ` + testJavaError(t, `"libjni" .*: sdk_version\(current\) is higher than min_sdk_version\(29\)`, bp) +} + +func TestUpdatableApps_ErrorIfDepSdkVersionIsHigher(t *testing.T) { + bp := cc.GatherRequiredDepsForTest(android.Android) + ` + android_app { + name: "foo", + srcs: ["a.java"], + updatable: true, + sdk_version: "current", + min_sdk_version: "29", // this APK should support 29 + jni_libs: ["libjni"], + } + + cc_library { + name: "libjni", + stl: "none", + shared_libs: ["libbar"], + system_shared_libs: [], + sdk_version: "27", + } + + cc_library { + name: "libbar", + stl: "none", + system_shared_libs: [], + sdk_version: "current", + } + ` + testJavaError(t, `"libjni" .*: links "libbar" built against newer API version "current"`, bp) +} + func TestResourceDirs(t *testing.T) { testCases := []struct { name string diff --git a/java/builder.go b/java/builder.go index 714d76aa5..a27e5c390 100644 --- a/java/builder.go +++ b/java/builder.go @@ -27,6 +27,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/remoteexec" ) var ( @@ -38,17 +39,18 @@ var ( // this, all java rules write into separate directories and then are combined into a .jar file // (if the rule produces .class files) or a .srcjar file (if the rule produces .java files). // .srcjar files are unzipped into a temporary directory when compiled with javac. - javac = pctx.AndroidRemoteStaticRule("javac", android.RemoteRuleSupports{Goma: true, RBE: true, RBEFlag: android.RBE_JAVAC}, + // TODO(b/143658984): goma can't handle the --system argument to javac. + javac, javacRE = remoteexec.MultiCommandStaticRules(pctx, "javac", blueprint.RuleParams{ Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + `(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` + - `${config.SoongJavacWrapper} ${config.JavacWrapper}${config.JavacCmd} ` + + `${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` + `${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` + `$processorpath $processor $javacFlags $bootClasspath $classpath ` + `-source $javaVersion -target $javaVersion ` + `-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` + - `${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` + + `$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` + `rm -rf "$srcJarDir"`, CommandDeps: []string{ "${config.JavacCmd}", @@ -58,9 +60,21 @@ var ( CommandOrderOnly: []string{"${config.SoongJavacWrapper}"}, Rspfile: "$out.rsp", RspfileContent: "$in", - }, - "javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir", - "outDir", "annoDir", "javaVersion") + }, map[string]*remoteexec.REParams{ + "$javaTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "lang": "java", "compiler": "javac"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$out"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir", + "outDir", "annoDir", "javaVersion"}, nil) _ = pctx.VariableFunc("kytheCorpus", func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() }) @@ -111,10 +125,10 @@ var ( }, "abis", "allow-prereleased", "screen-densities", "sdk-version", "stem") - turbine = pctx.AndroidStaticRule("turbine", + turbine, turbineRE = remoteexec.StaticRules(pctx, "turbine", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + - `${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` + + `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` + `--temp_dir "$outDir" --sources @$out.rsp --source_jars $srcJars ` + `--javacopts ${config.CommonJdkFlags} ` + `$javacFlags -source $javaVersion -target $javaVersion -- $bootClasspath $classpath && ` + @@ -129,25 +143,45 @@ var ( RspfileContent: "$in", Restat: true, }, - "javacFlags", "bootClasspath", "classpath", "srcJars", "outDir", "javaVersion") - - jar = pctx.AndroidStaticRule("jar", + &remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"}, + ExecStrategy: "${config.RETurbineExecStrategy}", + Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"}, + RSPFile: "${out}.rsp", + OutputFiles: []string{"$out.tmp"}, + OutputDirectories: []string{"$outDir"}, + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, []string{"javacFlags", "bootClasspath", "classpath", "srcJars", "outDir", "javaVersion"}, []string{"implicits"}) + + jar, jarRE = remoteexec.StaticRules(pctx, "jar", blueprint.RuleParams{ - Command: `${config.SoongZipCmd} -jar -o $out @$out.rsp`, + Command: `$reTemplate${config.SoongZipCmd} -jar -o $out @$out.rsp`, CommandDeps: []string{"${config.SoongZipCmd}"}, Rspfile: "$out.rsp", RspfileContent: "$jarArgs", }, - "jarArgs") - - zip = pctx.AndroidStaticRule("zip", + &remoteexec.REParams{ + ExecStrategy: "${config.REJarExecStrategy}", + Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp"}, + RSPFile: "${out}.rsp", + OutputFiles: []string{"$out"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, []string{"jarArgs"}, nil) + + zip, zipRE = remoteexec.StaticRules(pctx, "zip", blueprint.RuleParams{ Command: `${config.SoongZipCmd} -o $out @$out.rsp`, CommandDeps: []string{"${config.SoongZipCmd}"}, Rspfile: "$out.rsp", RspfileContent: "$jarArgs", }, - "jarArgs") + &remoteexec.REParams{ + ExecStrategy: "${config.REZipExecStrategy}", + Inputs: []string{"${config.SoongZipCmd}", "${out}.rsp", "$implicits"}, + RSPFile: "${out}.rsp", + OutputFiles: []string{"$out"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, []string{"jarArgs"}, []string{"implicits"}) combineJar = pctx.AndroidStaticRule("combineJar", blueprint.RuleParams{ @@ -199,6 +233,7 @@ var ( func init() { pctx.Import("android/soong/android") pctx.Import("android/soong/java/config") + pctx.Import("android/soong/remoteexec") } type javaBuilderFlags struct { @@ -340,20 +375,26 @@ func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android. deps = append(deps, classpath...) deps = append(deps, flags.processorPath...) + rule := turbine + args := map[string]string{ + "javacFlags": flags.javacFlags, + "bootClasspath": bootClasspath, + "srcJars": strings.Join(srcJars.Strings(), " "), + "classpath": classpath.FormTurbineClassPath("--classpath "), + "outDir": android.PathForModuleOut(ctx, "turbine", "classes").String(), + "javaVersion": flags.javaVersion.String(), + } + if ctx.Config().IsEnvTrue("RBE_TURBINE") { + rule = turbineRE + args["implicits"] = strings.Join(deps.Strings(), ",") + } ctx.Build(pctx, android.BuildParams{ - Rule: turbine, + Rule: rule, Description: "turbine", Output: outputFile, Inputs: srcFiles, Implicits: deps, - Args: map[string]string{ - "javacFlags": flags.javacFlags, - "bootClasspath": bootClasspath, - "srcJars": strings.Join(srcJars.Strings(), " "), - "classpath": classpath.FormTurbineClassPath("--classpath "), - "outDir": android.PathForModuleOut(ctx, "turbine", "classes").String(), - "javaVersion": flags.javaVersion.String(), - }, + Args: args, }) } @@ -409,8 +450,12 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab outDir = filepath.Join(shardDir, outDir) annoDir = filepath.Join(shardDir, annoDir) } + rule := javac + if ctx.Config().IsEnvTrue("RBE_JAVAC") { + rule = javacRE + } ctx.Build(pctx, android.BuildParams{ - Rule: javac, + Rule: rule, Description: desc, Output: outputFile, Inputs: srcFiles, @@ -433,8 +478,12 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab func TransformResourcesToJar(ctx android.ModuleContext, outputFile android.WritablePath, jarArgs []string, deps android.Paths) { + rule := jar + if ctx.Config().IsEnvTrue("RBE_JAR") { + rule = jarRE + } ctx.Build(pctx, android.BuildParams{ - Rule: jar, + Rule: rule, Description: "jar", Output: outputFile, Implicits: deps, diff --git a/java/config/Android.bp b/java/config/Android.bp new file mode 100644 index 000000000..198352187 --- /dev/null +++ b/java/config/Android.bp @@ -0,0 +1,15 @@ +bootstrap_go_package { + name: "soong-java-config", + pkgPath: "android/soong/java/config", + deps: [ + "blueprint-proptools", + "soong-android", + "soong-remoteexec", + ], + srcs: [ + "config.go", + "error_prone.go", + "kotlin.go", + "makevars.go", + ], +} diff --git a/java/config/config.go b/java/config/config.go index 9ac5a50cb..337355d80 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -22,6 +22,7 @@ import ( _ "github.com/google/blueprint/bootstrap" "android/soong/android" + "android/soong/remoteexec" ) var ( @@ -139,30 +140,20 @@ func init() { pctx.HostJavaToolVariable("MetalavaJar", "metalava.jar") pctx.HostJavaToolVariable("DokkaJar", "dokka.jar") pctx.HostJavaToolVariable("JetifierJar", "jetifier.jar") + pctx.HostJavaToolVariable("R8Jar", "r8-compat-proguard.jar") + pctx.HostJavaToolVariable("D8Jar", "d8.jar") pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper") pctx.HostBinToolVariable("DexpreoptGen", "dexpreopt_gen") - pctx.VariableFunc("JavacWrapper", func(ctx android.PackageVarContext) string { - if override := ctx.Config().Getenv("JAVAC_WRAPPER"); override != "" { - return override + " " - } - return "" - }) - - pctx.VariableFunc("R8Wrapper", func(ctx android.PackageVarContext) string { - if override := ctx.Config().Getenv("R8_WRAPPER"); override != "" { - return override + " " - } - return "" - }) - - pctx.VariableFunc("D8Wrapper", func(ctx android.PackageVarContext) string { - if override := ctx.Config().Getenv("D8_WRAPPER"); override != "" { - return override + " " - } - return "" - }) + pctx.VariableFunc("REJavaPool", remoteexec.EnvOverrideFunc("RBE_JAVA_POOL", "java16")) + pctx.VariableFunc("REJavacExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAVAC_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("RETurbineExecStrategy", remoteexec.EnvOverrideFunc("RBE_TURBINE_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("RESignApkExecStrategy", remoteexec.EnvOverrideFunc("RBE_SIGNAPK_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("REJarExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAR_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("REZipExecStrategy", remoteexec.EnvOverrideFunc("RBE_ZIP_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar") diff --git a/java/dex.go b/java/dex.go index 62f17c6d8..9e61e95ad 100644 --- a/java/dex.go +++ b/java/dex.go @@ -21,41 +21,70 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/remoteexec" ) -var d8 = pctx.AndroidRemoteStaticRule("d8", android.RemoteRuleSupports{RBE: true, RBEFlag: android.RBE_D8}, +var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + - `${config.D8Wrapper}${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` + - `${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + + `$d8Template${config.D8Cmd} ${config.DexFlags} --output $outDir $d8Flags $in && ` + + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, CommandDeps: []string{ "${config.D8Cmd}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, - }, - "outDir", "d8Flags", "zipFlags") + }, map[string]*remoteexec.REParams{ + "$d8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "d8"}, + Inputs: []string{"${config.D8Jar}"}, + ExecStrategy: "${config.RED8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$outDir/classes.dex.jar"}, + ExecStrategy: "${config.RED8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "d8Flags", "zipFlags"}, nil) -var r8 = pctx.AndroidRemoteStaticRule("r8", android.RemoteRuleSupports{RBE: true, RBEFlag: android.RBE_R8}, +var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + `rm -f "$outDict" && ` + - `${config.R8Wrapper}${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` + + `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` + `--force-proguard-compatibility ` + `--no-data-resources ` + `-printmapping $outDict ` + `$r8Flags && ` + `touch "$outDict" && ` + - `${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, CommandDeps: []string{ "${config.R8Cmd}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, - }, - "outDir", "outDict", "r8Flags", "zipFlags") + }, map[string]*remoteexec.REParams{ + "$r8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "r8"}, + Inputs: []string{"$implicits", "${config.R8Jar}"}, + ExecStrategy: "${config.RER8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$outDir/classes.dex.jar"}, + ExecStrategy: "${config.RER8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"}) func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string { flags := j.deviceProperties.Dxflags @@ -186,24 +215,34 @@ func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") j.proguardDictionary = proguardDictionary r8Flags, r8Deps := j.r8Flags(ctx, flags) + rule := r8 + args := map[string]string{ + "r8Flags": strings.Join(r8Flags, " "), + "zipFlags": zipFlags, + "outDict": j.proguardDictionary.String(), + "outDir": outDir.String(), + } + if ctx.Config().IsEnvTrue("RBE_R8") { + rule = r8RE + args["implicits"] = strings.Join(r8Deps.Strings(), ",") + } ctx.Build(pctx, android.BuildParams{ - Rule: r8, + Rule: rule, Description: "r8", Output: javalibJar, ImplicitOutput: proguardDictionary, Input: classesJar, Implicits: r8Deps, - Args: map[string]string{ - "r8Flags": strings.Join(r8Flags, " "), - "zipFlags": zipFlags, - "outDict": j.proguardDictionary.String(), - "outDir": outDir.String(), - }, + Args: args, }) } else { d8Flags, d8Deps := j.d8Flags(ctx, flags) + rule := d8 + if ctx.Config().IsEnvTrue("RBE_D8") { + rule = d8RE + } ctx.Build(pctx, android.BuildParams{ - Rule: d8, + Rule: rule, Description: "d8", Output: javalibJar, Input: classesJar, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index b518e9c0d..2f0cbdb8c 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -611,10 +611,10 @@ func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConf // Collect `permitted_packages` for updatable boot jars. var updatablePackages []string ctx.VisitAllModules(func(module android.Module) { - if j, ok := module.(*Library); ok { + if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok { name := ctx.ModuleName(module) if i := android.IndexList(name, updatableModules); i != -1 { - pp := j.properties.Permitted_packages + pp := j.PermittedPackagesForUpdatableBootJars() if len(pp) > 0 { updatablePackages = append(updatablePackages, pp...) } else { diff --git a/java/java.go b/java/java.go index c30dc4e50..2623d2c10 100644 --- a/java/java.go +++ b/java/java.go @@ -1462,13 +1462,19 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { serviceFile := file.String() zipargs = append(zipargs, "-C", filepath.Dir(serviceFile), "-f", serviceFile) } + rule := zip + args := map[string]string{ + "jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "), + } + if ctx.Config().IsEnvTrue("RBE_ZIP") { + rule = zipRE + args["implicits"] = strings.Join(services.Strings(), ",") + } ctx.Build(pctx, android.BuildParams{ - Rule: zip, + Rule: rule, Output: servicesJar, Implicits: services, - Args: map[string]string{ - "jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "), - }, + Args: args, }) jars = append(jars, servicesJar) } @@ -1839,6 +1845,17 @@ type Library struct { InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths) } +// Provides access to the list of permitted packages from updatable boot jars. +type PermittedPackagesForUpdatableBootJars interface { + PermittedPackagesForUpdatableBootJars() []string +} + +var _ PermittedPackagesForUpdatableBootJars = (*Library)(nil) + +func (j *Library) PermittedPackagesForUpdatableBootJars() []string { + return j.properties.Permitted_packages +} + func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool { // Store uncompressed (and aligned) any dex files from jars in APEXes. if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() { diff --git a/java/java_test.go b/java/java_test.go index 385fe6afd..04717238d 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1465,6 +1465,33 @@ func TestJavaSdkLibrary_FallbackScope(t *testing.T) { `) } +func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) { + ctx, _ := testJava(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + system: { + enabled: true, + }, + default_to_stubs: true, + } + + java_library { + name: "baz", + srcs: ["a.java"], + libs: ["foo"], + // does not have sdk_version set, should fallback to module, + // which will then fallback to system because the module scope + // is not enabled. + } + `) + // The baz library should depend on the system stubs jar. + bazLibrary := ctx.ModuleForTests("baz", "android_common").Rule("javac") + if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + t.Errorf("expected %q, found %#q", expected, actual) + } +} + var compilerFlagsTestCases = []struct { in string out bool diff --git a/java/sdk_library.go b/java/sdk_library.go index 17217ed41..03b63b9f8 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -438,6 +438,14 @@ type sdkLibraryProperties struct { // disabled by default. Module_lib ApiScopeProperties + // Determines if the stubs are preferred over the implementation library + // for linking, even when the client doesn't specify sdk_version. When this + // is set to true, such clients are provided with the widest API surface that + // this lib provides. Note however that this option doesn't affect the clients + // that are in the same APEX as this library. In that case, the clients are + // always linked with the implementation library. Default is false. + Default_to_stubs *bool + // Properties related to api linting. Api_lint struct { // Enable api linting. @@ -1354,6 +1362,13 @@ func (module *SdkLibrary) withinSameApexAs(other android.Module) bool { } func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { + // If the client doesn't set sdk_version, but if this library prefers stubs over + // the impl library, let's provide the widest API surface possible. To do so, + // force override sdk_version to module_current so that the closest possible API + // surface could be found in selectHeaderJarsForSdkVersion + if module.defaultsToStubs() && !sdkVersion.specified() { + sdkVersion = sdkSpecFrom("module_current") + } // Only provide access to the implementation library if it is actually built. if module.requiresRuntimeImplementationLibrary() { @@ -1517,6 +1532,10 @@ func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool { return !proptools.Bool(module.sdkLibraryProperties.Api_only) } +func (module *SdkLibrary) defaultsToStubs() bool { + return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs) +} + // Defines how to name the individual component modules the sdk library creates. type sdkLibraryComponentNamingScheme interface { stubsLibraryModuleName(scope *apiScope, baseName string) string @@ -2017,6 +2036,10 @@ type sdkLibrarySdkMemberProperties struct { // The naming scheme. Naming_scheme *string + + // True if the java_sdk_library_import is for a shared library, false + // otherwise. + Shared_library *bool } type scopeProperties struct { @@ -2051,12 +2074,16 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Libs = sdk.properties.Libs s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme + s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary()) } func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { if s.Naming_scheme != nil { propertySet.AddProperty("naming_scheme", proptools.String(s.Naming_scheme)) } + if s.Shared_library != nil { + propertySet.AddProperty("shared_library", *s.Shared_library) + } for _, apiScope := range allApiScopes { if properties, ok := s.Scopes[apiScope]; ok { |