diff options
Diffstat (limited to 'java')
42 files changed, 2169 insertions, 388 deletions
diff --git a/java/Android.bp b/java/Android.bp index 9df4ab4de..0bf7a0b26 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -43,6 +43,7 @@ bootstrap_go_package { "dexpreopt_bootjars.go", "dexpreopt_check.go", "dexpreopt_config.go", + "dexpreopt_config_testing.go", "droiddoc.go", "droidstubs.go", "fuzz.go", @@ -64,6 +65,7 @@ bootstrap_go_package { "plugin.go", "prebuilt_apis.go", "proto.go", + "resourceshrinker.go", "robolectric.go", "rro.go", "sdk.go", @@ -86,6 +88,7 @@ bootstrap_go_package { "dex_test.go", "dexpreopt_test.go", "dexpreopt_bootjars_test.go", + "dexpreopt_config_test.go", "droiddoc_test.go", "droidstubs_test.go", "genrule_test.go", diff --git a/java/aapt2.go b/java/aapt2.go index 5346ddf89..7845a0b23 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -256,17 +256,21 @@ func aapt2Link(ctx android.ModuleContext, var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert", blueprint.RuleParams{ - Command: `${config.Aapt2Cmd} convert --output-format proto $in -o $out`, + Command: `${config.Aapt2Cmd} convert --output-format $format $in -o $out`, CommandDeps: []string{"${config.Aapt2Cmd}"}, - }) + }, "format", +) // Converts xml files and resource tables (resources.arsc) in the given jar/apk file to a proto // format. The proto definition is available at frameworks/base/tools/aapt2/Resources.proto. -func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path) { +func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path, format string) { ctx.Build(pctx, android.BuildParams{ Rule: aapt2ConvertRule, Input: in, Output: out, - Description: "convert to proto", + Description: "convert to " + format, + Args: map[string]string{ + "format": format, + }, }) } diff --git a/java/aar.go b/java/aar.go index d5996ba02..6261f2974 100644 --- a/java/aar.go +++ b/java/aar.go @@ -270,7 +270,7 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string, - extraLinkFlags ...string) { + enforceDefaultTargetSdkVersion bool, extraLinkFlags ...string) { transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags := aaptLibs(ctx, sdkContext, classLoaderContexts) @@ -283,15 +283,16 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{ - SdkContext: sdkContext, - ClassLoaderContexts: classLoaderContexts, - IsLibrary: a.isLibrary, - DefaultManifestVersion: a.defaultManifestVersion, - UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs, - UsesNonSdkApis: a.usesNonSdkApis, - UseEmbeddedDex: a.useEmbeddedDex, - HasNoCode: a.hasNoCode, - LoggingParent: a.LoggingParent, + SdkContext: sdkContext, + ClassLoaderContexts: classLoaderContexts, + IsLibrary: a.isLibrary, + DefaultManifestVersion: a.defaultManifestVersion, + UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs, + UsesNonSdkApis: a.usesNonSdkApis, + UseEmbeddedDex: a.useEmbeddedDex, + HasNoCode: a.hasNoCode, + LoggingParent: a.LoggingParent, + EnforceDefaultTargetSdkVersion: enforceDefaultTargetSdkVersion, }) // Add additional manifest files to transitive manifests. @@ -439,7 +440,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoa switch depTag { case instrumentationForTag: // Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2. - case libTag: + case sdkLibTag, libTag: if exportPackage != nil { sharedLibs = append(sharedLibs, exportPackage) } @@ -535,7 +536,7 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) - a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil) + a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil, false) a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() diff --git a/java/android_manifest.go b/java/android_manifest.go index 522b6647a..c7853103f 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -43,13 +43,12 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger", // targetSdkVersion for manifest_fixer // When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK // This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK -func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string { - targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx) - // Return 10000 for modules targeting "current" if either - // 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty) - // 2. The module is run as part of MTS, and should be testable on stable branches +func targetSdkVersionForManifestFixer(ctx android.ModuleContext, params ManifestFixerParams) string { + targetSdkVersionSpec := params.SdkContext.TargetSdkVersion(ctx) + + // Check if we want to return 10000 // TODO(b/240294501): Determine the rules for handling test apexes - if targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) { + if shouldReturnFinalOrFutureInt(ctx, targetSdkVersionSpec, params.EnforceDefaultTargetSdkVersion) { return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt()) } targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx) @@ -59,6 +58,17 @@ func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext andr return targetSdkVersion } +// Return true for modules targeting "current" if either +// 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty) +// 2. The module is run as part of MTS, and should be testable on stable branches +// Do not return 10000 if we are enforcing default targetSdkVersion and sdk has been finalised +func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionSpec android.SdkSpec, enforceDefaultTargetSdkVersion bool) bool { + if enforceDefaultTargetSdkVersion && ctx.Config().PlatformSdkFinal() { + return false + } + return targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) +} + // Helper function that casts android.Module to java.androidTestApp // If this type conversion is possible, it queries whether the test app is included in an MTS suite func includedInMts(module android.Module) bool { @@ -69,16 +79,17 @@ func includedInMts(module android.Module) bool { } type ManifestFixerParams struct { - SdkContext android.SdkContext - ClassLoaderContexts dexpreopt.ClassLoaderContextMap - IsLibrary bool - DefaultManifestVersion string - UseEmbeddedNativeLibs bool - UsesNonSdkApis bool - UseEmbeddedDex bool - HasNoCode bool - TestOnly bool - LoggingParent string + SdkContext android.SdkContext + ClassLoaderContexts dexpreopt.ClassLoaderContextMap + IsLibrary bool + DefaultManifestVersion string + UseEmbeddedNativeLibs bool + UsesNonSdkApis bool + UseEmbeddedDex bool + HasNoCode bool + TestOnly bool + LoggingParent string + EnforceDefaultTargetSdkVersion bool } // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml @@ -137,7 +148,7 @@ func ManifestFixer(ctx android.ModuleContext, manifest android.Path, var argsMapper = make(map[string]string) if params.SdkContext != nil { - targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params.SdkContext) + targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params) args = append(args, "--targetSdkVersion ", targetSdkVersion) if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" { diff --git a/java/androidmk.go b/java/androidmk.go index 75ac0e72d..42b4ef1b2 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -17,6 +17,7 @@ package java import ( "fmt" "io" + "strings" "android/soong/android" ) @@ -138,6 +139,7 @@ func (j *JavaFuzzLibrary) AndroidMkEntries() []android.AndroidMkEntries { entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", "null-suite") androidMkWriteTestData(j.jniFilePaths, entries) + androidMkWriteTestData(android.Paths{j.implementationJarFile}, entries) }) return entriesList } @@ -398,6 +400,19 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { } else { for _, jniLib := range app.jniLibs { entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name) + var partitionTag string + + // Mimic the creation of partition_tag in build/make, + // which defaults to an empty string when the partition is system. + // Otherwise, capitalize with a leading _ + if jniLib.partition == "system" { + partitionTag = "" + } else { + split := strings.Split(jniLib.partition, "/") + partitionTag = "_" + strings.ToUpper(split[len(split)-1]) + } + entries.AddStrings("LOCAL_SOONG_JNI_LIBS_PARTITION_"+jniLib.target.Arch.ArchType.String(), + jniLib.name+":"+partitionTag) } } diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 197da4f38..1232cd1ee 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -19,6 +19,9 @@ import ( "testing" "android/soong/android" + "android/soong/cc" + + "github.com/google/blueprint/proptools" ) func TestRequired(t *testing.T) { @@ -252,3 +255,149 @@ func TestGetOverriddenPackages(t *testing.T) { android.AssertDeepEquals(t, "overrides property", expected.overrides, actual) } } + +func TestJniPartition(t *testing.T) { + bp := ` + cc_library { + name: "libjni_system", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + } + + cc_library { + name: "libjni_system_ext", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + system_ext_specific: true, + } + + cc_library { + name: "libjni_odm", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + device_specific: true, + } + + cc_library { + name: "libjni_product", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + product_specific: true, + } + + cc_library { + name: "libjni_vendor", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + soc_specific: true, + } + + android_app { + name: "test_app_system_jni_system", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system"], + } + + android_app { + name: "test_app_system_jni_system_ext", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system_ext"], + } + + android_app { + name: "test_app_system_ext_jni_system", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system"], + system_ext_specific: true + } + + android_app { + name: "test_app_system_ext_jni_system_ext", + sdk_version: "core_platform", + jni_libs: ["libjni_system_ext"], + system_ext_specific: true + } + + android_app { + name: "test_app_product_jni_product", + sdk_version: "core_platform", + jni_libs: ["libjni_product"], + product_specific: true + } + + android_app { + name: "test_app_vendor_jni_odm", + sdk_version: "core_platform", + jni_libs: ["libjni_odm"], + soc_specific: true + } + + android_app { + name: "test_app_odm_jni_vendor", + sdk_version: "core_platform", + jni_libs: ["libjni_vendor"], + device_specific: true + } + android_app { + name: "test_app_system_jni_multiple", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system", "libjni_system_ext"], + } + android_app { + name: "test_app_vendor_jni_multiple", + sdk_version: "core_platform", + jni_libs: ["libjni_odm", "libjni_vendor"], + soc_specific: true + } + ` + arch := "arm64" + ctx := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + cc.PrepareForTestWithCcDefaultModules, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.DeviceArch = proptools.StringPtr(arch) + }), + ). + RunTestWithBp(t, bp) + testCases := []struct { + name string + partitionNames []string + partitionTags []string + }{ + {"test_app_system_jni_system", []string{"libjni_system"}, []string{""}}, + {"test_app_system_jni_system_ext", []string{"libjni_system_ext"}, []string{"_SYSTEM_EXT"}}, + {"test_app_system_ext_jni_system", []string{"libjni_system"}, []string{""}}, + {"test_app_system_ext_jni_system_ext", []string{"libjni_system_ext"}, []string{"_SYSTEM_EXT"}}, + {"test_app_product_jni_product", []string{"libjni_product"}, []string{"_PRODUCT"}}, + {"test_app_vendor_jni_odm", []string{"libjni_odm"}, []string{"_ODM"}}, + {"test_app_odm_jni_vendor", []string{"libjni_vendor"}, []string{"_VENDOR"}}, + {"test_app_system_jni_multiple", []string{"libjni_system", "libjni_system_ext"}, []string{"", "_SYSTEM_EXT"}}, + {"test_app_vendor_jni_multiple", []string{"libjni_odm", "libjni_vendor"}, []string{"_ODM", "_VENDOR"}}, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + mod := ctx.ModuleForTests(test.name, "android_common").Module() + entry := android.AndroidMkEntriesForTest(t, ctx.TestContext, mod)[0] + for i := range test.partitionNames { + actual := entry.EntryMap["LOCAL_SOONG_JNI_LIBS_PARTITION_"+arch][i] + expected := test.partitionNames[i] + ":" + test.partitionTags[i] + android.AssertStringEquals(t, "Expected and actual differ", expected, actual) + } + }) + } +} diff --git a/java/app.go b/java/app.go index bccd37fa0..2a51e10df 100755 --- a/java/app.go +++ b/java/app.go @@ -101,6 +101,15 @@ type appProperties struct { PreventInstall bool `blueprint:"mutated"` IsCoverageVariant bool `blueprint:"mutated"` + // It can be set to test the behaviour of default target sdk version. + // Only required when updatable: false. It is an error if updatable: true and this is false. + Enforce_default_target_sdk_version *bool + + // If set, the targetSdkVersion for the target is set to the latest default API level. + // This would be by default false, unless updatable: true or + // enforce_default_target_sdk_version: true in which case this defaults to true. + EnforceDefaultTargetSdkVersion bool `blueprint:"mutated"` + // Whether this app is considered mainline updatable or not. When set to true, this will enforce // additional rules to make sure an app can safely be updated. Default is false. // Prefer using other specific properties if build behaviour must be changed; avoid using this @@ -296,6 +305,18 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { } else { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } + + if !BoolDefault(a.appProperties.Enforce_default_target_sdk_version, true) { + ctx.PropertyErrorf("enforce_default_target_sdk_version", "Updatable apps must enforce default target sdk version") + } + // TODO(b/227460469) after all the modules removes the target sdk version, throw an error if the target sdk version is explicitly set. + if a.deviceProperties.Target_sdk_version == nil { + a.SetEnforceDefaultTargetSdkVersion(true) + } + } + + if Bool(a.appProperties.Enforce_default_target_sdk_version) { + a.SetEnforceDefaultTargetSdkVersion(true) } a.checkPlatformAPI(ctx) @@ -427,7 +448,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion } a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, - a.usesLibraryProperties.Exclude_uses_libs, aaptLinkFlags...) + a.usesLibraryProperties.Exclude_uses_libs, a.enforceDefaultTargetSdkVersion(), aaptLinkFlags...) // apps manifests are handled by aapt, don't let Module see them a.properties.Manifest = nil @@ -526,7 +547,8 @@ func (a *AndroidApp) JNISymbolsInstalls(installPath string) android.RuleBuilderI // Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it // isn't a cert module reference. Also checks and enforces system cert restriction if applicable. -func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate { +func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, + ctx android.ModuleContext) (mainCertificate Certificate, allCertificates []Certificate) { if android.SrcIsModule(certPropValue) == "" { var mainCert Certificate if certPropValue != "" { @@ -558,7 +580,22 @@ func processMainCert(m android.ModuleBase, certPropValue string, certificates [] } } - return certificates + if len(certificates) > 0 { + mainCertificate = certificates[0] + } else { + // This can be reached with an empty certificate list if AllowMissingDependencies is set + // and the certificate property for this module is a module reference to a missing module. + if !ctx.Config().AllowMissingDependencies() && len(ctx.GetMissingDependencies()) > 0 { + panic("Should only get here if AllowMissingDependencies set and there are missing dependencies") + } + // Set a certificate to avoid panics later when accessing it. + mainCertificate = Certificate{ + Key: android.PathForModuleOut(ctx, "missing.pk8"), + Pem: android.PathForModuleOut(ctx, "missing.pem"), + } + } + + return mainCertificate, certificates } func (a *AndroidApp) InstallApkName() string { @@ -632,29 +669,14 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { dexJarFile := a.dexBuildActions(ctx) - jniLibs, prebuiltJniPackages, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) + jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx) if ctx.Failed() { return } - certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx) - - // This can be reached with an empty certificate list if AllowMissingDependencies is set - // and the certificate property for this module is a module reference to a missing module. - if len(certificates) > 0 { - a.certificate = certificates[0] - } else { - if !ctx.Config().AllowMissingDependencies() && len(ctx.GetMissingDependencies()) > 0 { - panic("Should only get here if AllowMissingDependencies set and there are missing dependencies") - } - // Set a certificate to avoid panics later when accessing it. - a.certificate = Certificate{ - Key: android.PathForModuleOut(ctx, "missing.pk8"), - Pem: android.PathForModuleOut(ctx, "missing.pem"), - } - } + a.certificate, certificates = processMainCert(a.ModuleBase, a.getCertString(ctx), certificates, ctx) // Build a final signed app package. packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk") @@ -667,10 +689,9 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { if lineage := String(a.overridableAppProperties.Lineage); lineage != "" { lineageFile = android.PathForModuleSrc(ctx, lineage) } - rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion) - CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion) + CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, Bool(a.dexProperties.Optimize.Shrink_resources)) a.outputFile = packageFile if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -699,7 +720,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { if v4SigningRequested { v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig") } - CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion) + CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, false) a.extraOutputFiles = append(a.extraOutputFiles, packageFile) if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -777,6 +798,7 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, target: module.Target(), coverageFile: dep.CoverageOutputFile(), unstrippedFile: dep.UnstrippedOutputFile(), + partition: dep.Partition(), }) } else { ctx.ModuleErrorf("dependency %q missing output file", otherName) @@ -865,6 +887,14 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depsInfo) } +func (a *AndroidApp) enforceDefaultTargetSdkVersion() bool { + return a.appProperties.EnforceDefaultTargetSdkVersion +} + +func (a *AndroidApp) SetEnforceDefaultTargetSdkVersion(val bool) { + a.appProperties.EnforceDefaultTargetSdkVersion = val +} + func (a *AndroidApp) Updatable() bool { return Bool(a.appProperties.Updatable) } @@ -1456,8 +1486,8 @@ type bazelAndroidAppAttributes struct { *bazelAapt Deps bazel.LabelListAttribute Custom_package *string - Certificate *bazel.Label - Certificate_name *string + Certificate bazel.LabelAttribute + Certificate_name bazel.StringAttribute } // ConvertWithBp2build is used to convert android_app to Bazel. @@ -1469,15 +1499,8 @@ func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { aapt := a.convertAaptAttrsWithBp2Build(ctx) - var certificate *bazel.Label - certificateNamePtr := a.overridableAppProperties.Certificate - certificateName := proptools.StringDefault(certificateNamePtr, "") - certModule := android.SrcIsModule(certificateName) - if certModule != "" { - c := android.BazelLabelForModuleDepSingle(ctx, certificateName) - certificate = &c - certificateNamePtr = nil - } + certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate) + attrs := &bazelAndroidAppAttributes{ commonAttrs, aapt, @@ -1485,7 +1508,7 @@ func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES a.overridableAppProperties.Package_name, certificate, - certificateNamePtr, + certificateName, } props := bazel.BazelTargetModuleProperties{ diff --git a/java/app_builder.go b/java/app_builder.go index 18a975181..d20a6bfe4 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -52,7 +52,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk", }) func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath, - packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) { + packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string, shrinkResources bool) { unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk" unsignedApk := android.PathForModuleOut(ctx, unsignedApkName) @@ -65,7 +65,6 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa if jniJarFile != nil { inputs = append(inputs, jniJarFile) } - ctx.Build(pctx, android.BuildParams{ Rule: combineApk, Inputs: inputs, @@ -73,6 +72,11 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa Implicits: deps, }) + if shrinkResources { + shrunkenApk := android.PathForModuleOut(ctx, "resource-shrunken", unsignedApk.Base()) + ShrinkResources(ctx, unsignedApk, shrunkenApk) + unsignedApk = shrunkenApk + } SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion) } @@ -84,7 +88,6 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u certificateArgs = append(certificateArgs, c.Pem.String(), c.Key.String()) deps = append(deps, c.Pem, c.Key) } - outputFiles := android.WritablePaths{signedApk} var flags []string if v4SignatureFile != nil { @@ -182,7 +185,7 @@ func BuildBundleModule(ctx android.ModuleContext, outputFile android.WritablePat packageFile, jniJarFile, dexJarFile android.Path) { protoResJarFile := android.PathForModuleOut(ctx, "package-res.pb.apk") - aapt2Convert(ctx, protoResJarFile, packageFile) + aapt2Convert(ctx, protoResJarFile, packageFile, "proto") var zips android.Paths diff --git a/java/app_import.go b/java/app_import.go index d6dca3836..6e603c912 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -318,19 +318,17 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext if a.isPrebuiltFrameworkRes() { a.outputFile = srcApk - certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) + a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) if len(certificates) != 1 { ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates) } - a.certificate = certificates[0] } else if a.preprocessed { a.outputFile = srcApk a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. - certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) - a.certificate = certificates[0] + a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", apkFilename) var lineageFile android.Path if lineage := String(a.properties.Lineage); lineage != "" { diff --git a/java/app_import_test.go b/java/app_import_test.go index 41be092e2..ad27e3ae7 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -807,3 +807,23 @@ func TestAndroidTestImport_UncompressDex(t *testing.T) { } } } + +func TestAppImportMissingCertificateAllowMissingDependencies(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + ).RunTestWithBp(t, ` + android_app_import { + name: "foo", + apk: "a.apk", + certificate: ":missing_certificate", + }`) + + foo := result.ModuleForTests("foo", "android_common") + fooApk := foo.Output("signed/foo.apk") + if fooApk.Rule != android.ErrorRule { + t.Fatalf("expected ErrorRule for foo.apk, got %s", fooApk.Rule.String()) + } + android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n") +} diff --git a/java/app_set.go b/java/app_set.go index 694b1670e..d99fadb34 100644 --- a/java/app_set.go +++ b/java/app_set.go @@ -90,10 +90,11 @@ func (as *AndroidAppSet) APKCertsFile() android.Path { } var TargetCpuAbi = map[string]string{ - "arm": "ARMEABI_V7A", - "arm64": "ARM64_V8A", - "x86": "X86", - "x86_64": "X86_64", + "arm": "ARMEABI_V7A", + "arm64": "ARM64_V8A", + "riscv64": "RISCV64", + "x86": "X86", + "x86_64": "X86_64", } func SupportedAbis(ctx android.ModuleContext) []string { diff --git a/java/app_test.go b/java/app_test.go index 23635b960..e216c630b 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -3057,6 +3057,179 @@ func TestTargetSdkVersionManifestFixer(t *testing.T) { } } +func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) { + platform_sdk_codename := "Tiramisu" + platform_sdk_version := 33 + testCases := []struct { + name string + platform_sdk_final bool + targetSdkVersionInBp *string + targetSdkVersionExpected *string + updatable bool + }{ + { + name: "Non-Updatable Module: Android.bp has older targetSdkVersion", + targetSdkVersionInBp: proptools.StringPtr("29"), + targetSdkVersionExpected: proptools.StringPtr("29"), + updatable: false, + }, + { + name: "Updatable Module: Android.bp has older targetSdkVersion", + targetSdkVersionInBp: proptools.StringPtr("30"), + targetSdkVersionExpected: proptools.StringPtr("30"), + updatable: true, + }, + { + name: "Updatable Module: Android.bp has no targetSdkVersion", + targetSdkVersionExpected: proptools.StringPtr("10000"), + updatable: true, + }, + { + name: "[SDK finalised] Non-Updatable Module: Android.bp has older targetSdkVersion", + platform_sdk_final: true, + targetSdkVersionInBp: proptools.StringPtr("30"), + targetSdkVersionExpected: proptools.StringPtr("30"), + updatable: false, + }, + { + name: "[SDK finalised] Updatable Module: Android.bp has older targetSdkVersion", + platform_sdk_final: true, + targetSdkVersionInBp: proptools.StringPtr("30"), + targetSdkVersionExpected: proptools.StringPtr("30"), + updatable: true, + }, + { + name: "[SDK finalised] Updatable Module: Android.bp has targetSdkVersion as platform sdk codename", + platform_sdk_final: true, + targetSdkVersionInBp: proptools.StringPtr(platform_sdk_codename), + targetSdkVersionExpected: proptools.StringPtr("33"), + updatable: true, + }, + { + name: "[SDK finalised] Updatable Module: Android.bp has no targetSdkVersion", + platform_sdk_final: true, + targetSdkVersionExpected: proptools.StringPtr("33"), + updatable: true, + }, + } + for _, testCase := range testCases { + bp := fmt.Sprintf(` + android_app { + name: "foo", + sdk_version: "current", + min_sdk_version: "29", + target_sdk_version: "%v", + updatable: %t, + enforce_default_target_sdk_version: %t + } + `, proptools.String(testCase.targetSdkVersionInBp), testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable + + fixture := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set following platform variables to make the test deterministic + variables.Platform_sdk_final = &testCase.platform_sdk_final + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Platform_version_active_codenames = []string{platform_sdk_codename} + variables.Unbundled_build_apps = []string{"sampleModule"} + }), + ) + + result := fixture.RunTestWithBp(t, bp) + foo := result.ModuleForTests("foo", "android_common") + + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+*testCase.targetSdkVersionExpected) + } +} + +func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) { + platform_sdk_codename := "Tiramisu" + platform_sdk_version := 33 + testCases := []struct { + name string + enforceDefaultTargetSdkVersion bool + expectedError string + platform_sdk_final bool + targetSdkVersionInBp string + targetSdkVersionExpected string + updatable bool + }{ + { + name: "Not enforcing Target SDK Version: Android.bp has older targetSdkVersion", + enforceDefaultTargetSdkVersion: false, + targetSdkVersionInBp: "29", + targetSdkVersionExpected: "29", + updatable: false, + }, + { + name: "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion", + enforceDefaultTargetSdkVersion: true, + platform_sdk_final: true, + targetSdkVersionInBp: "current", + targetSdkVersionExpected: "33", + updatable: true, + }, + { + name: "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion", + enforceDefaultTargetSdkVersion: true, + platform_sdk_final: false, + targetSdkVersionInBp: "current", + targetSdkVersionExpected: "10000", + updatable: false, + }, + { + name: "Not enforcing Target SDK Version for Updatable app", + enforceDefaultTargetSdkVersion: false, + expectedError: "Updatable apps must enforce default target sdk version", + targetSdkVersionInBp: "29", + targetSdkVersionExpected: "29", + updatable: true, + }, + } + for _, testCase := range testCases { + errExpected := testCase.expectedError != "" + bp := fmt.Sprintf(` + android_app { + name: "foo", + enforce_default_target_sdk_version: %t, + sdk_version: "current", + min_sdk_version: "29", + target_sdk_version: "%v", + updatable: %t + } + `, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp, testCase.updatable) + + fixture := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set following platform variables to make the test deterministic + variables.Platform_sdk_final = &testCase.platform_sdk_final + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Unbundled_build_apps = []string{"sampleModule"} + }), + ) + + errorHandler := android.FixtureExpectsNoErrors + if errExpected { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) + } + result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) + + if !errExpected { + foo := result.ModuleForTests("foo", "android_common") + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + } + } +} + func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) { result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, diff --git a/java/base.go b/java/base.go index 53f0f52c2..96f36e87e 100644 --- a/java/base.go +++ b/java/base.go @@ -190,7 +190,7 @@ type CommonProperties struct { // constructing a new module. type DeviceProperties struct { // If not blank, set to the version of the sdk to compile against. - // Defaults to private. + // Defaults to an empty string, which compiles the module against the private platform APIs. // Values are of one of the following forms: // 1) numerical API level, "current", "none", or "core_platform" // 2) An SDK kind with an API level: "<sdk kind>_<API level>" @@ -447,9 +447,11 @@ type Module struct { // installed file for hostdex copy hostdexInstallFile android.InstallPath - // list of .java files and srcjars that was passed to javac - compiledJavaSrcs android.Paths - compiledSrcJars android.Paths + // list of unique .java and .kt source files + uniqueSrcFiles android.Paths + + // list of srcjars that was passed to javac + compiledSrcJars android.Paths // manifest file to use instead of properties.Manifest overrideManifest android.OptionalPath @@ -530,7 +532,7 @@ func (j *Module) checkSdkVersions(ctx android.ModuleContext) { // TODO(satayev): cover other types as well, e.g. imports case *Library, *AndroidLibrary: switch tag { - case bootClasspathTag, libTag, staticLibTag, java9LibTag: + case bootClasspathTag, sdkLibTag, libTag, staticLibTag, java9LibTag: j.checkSdkLinkType(ctx, module.(moduleWithSdkDep), tag.(dependencyTag)) } } @@ -650,6 +652,10 @@ func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { return false } +func (j *Module) setInstrument(value bool) { + j.properties.Instrument = value +} + func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version)) } @@ -789,9 +795,6 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { } else if j.shouldInstrumentStatic(ctx) { ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent") } - if j.shouldInstrument(ctx) { - ctx.AddVariationDependencies(nil, libTag, "jacocoagent") - } if j.useCompose() { ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, @@ -862,7 +865,9 @@ func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.Opt // add flags for dirs containing AIDL srcs that haven't been specified yet flags = append(flags, genAidlIncludeFlags(ctx, aidlSrcs, includeDirs)) - if Bool(j.deviceProperties.Aidl.Generate_traces) { + sdkVersion := (j.SdkVersion(ctx)).Kind + defaultTrace := ((sdkVersion == android.SdkSystemServer) || (sdkVersion == android.SdkCore) || (sdkVersion == android.SdkCorePlatform)) + if proptools.BoolDefault(j.deviceProperties.Aidl.Generate_traces, defaultTrace) { flags = append(flags, "-t") } @@ -890,7 +895,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB epEnabled := j.properties.Errorprone.Enabled if (ctx.Config().RunErrorProne() && epEnabled == nil) || Bool(epEnabled) { - if config.ErrorProneClasspath == nil && ctx.Config().TestProductVariables == nil { + if config.ErrorProneClasspath == nil && !ctx.Config().RunningInsideUnitTest() { ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?") } @@ -1075,15 +1080,26 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { jarName := ctx.ModuleName() + ".jar" - javaSrcFiles := srcFiles.FilterByExt(".java") - var uniqueSrcFiles android.Paths + var uniqueJavaFiles android.Paths set := make(map[string]bool) - for _, v := range javaSrcFiles { + for _, v := range srcFiles.FilterByExt(".java") { if _, found := set[v.String()]; !found { set[v.String()] = true - uniqueSrcFiles = append(uniqueSrcFiles, v) + uniqueJavaFiles = append(uniqueJavaFiles, v) } } + var uniqueKtFiles android.Paths + for _, v := range srcFiles.FilterByExt(".kt") { + if _, found := set[v.String()]; !found { + set[v.String()] = true + uniqueKtFiles = append(uniqueKtFiles, v) + } + } + + var uniqueSrcFiles android.Paths + uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...) + uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...) + j.uniqueSrcFiles = uniqueSrcFiles // We don't currently run annotation processors in turbine, which means we can't use turbine // generated header jars when an annotation processor that generates API is enabled. One @@ -1091,7 +1107,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // is used to run all of the annotation processors. disableTurbine := deps.disableTurbine - // Collect .java files for AIDEGen + // Collect .java and .kt files for AIDEGen j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...) var kotlinJars android.Paths @@ -1129,12 +1145,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { flags.kotlincFlags += "$kotlincFlags" } - var kotlinSrcFiles android.Paths - kotlinSrcFiles = append(kotlinSrcFiles, uniqueSrcFiles...) - kotlinSrcFiles = append(kotlinSrcFiles, srcFiles.FilterByExt(".kt")...) - - // Collect .kt files for AIDEGen - j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, srcFiles.FilterByExt(".kt").Strings()...) + // Collect common .kt files for AIDEGen j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...) flags.classpath = append(flags.classpath, deps.kotlinStdlib...) @@ -1147,7 +1158,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // Use kapt for annotation processing kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar") kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar") - kotlinKapt(ctx, kaptSrcJar, kaptResJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags) + kotlinKapt(ctx, kaptSrcJar, kaptResJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) srcJars = append(srcJars, kaptSrcJar) kotlinJars = append(kotlinJars, kaptResJar) // Disable annotation processing in javac, it's already been handled by kapt @@ -1157,7 +1168,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) - kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags) + kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) if ctx.Failed() { return } @@ -1182,8 +1193,6 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { jars := append(android.Paths(nil), kotlinJars...) - // Store the list of .java files that was passed to javac - j.compiledJavaSrcs = uniqueSrcFiles j.compiledSrcJars = srcJars enableSharding := false @@ -1198,12 +1207,12 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // with sharding enabled. See: b/77284273. } headerJarFileWithoutDepsOrJarjar, j.headerJarFile = - j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinHeaderJars) + j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars) if ctx.Failed() { return } } - if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 { + if len(uniqueJavaFiles) > 0 || len(srcJars) > 0 { hasErrorproneableFiles := false for _, ext := range j.sourceExtensions { if ext != ".proto" && ext != ".aidl" { @@ -1228,7 +1237,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { errorproneFlags := enableErrorproneFlags(flags) errorprone := android.PathForModuleOut(ctx, "errorprone", jarName) - transformJavaToClasses(ctx, errorprone, -1, uniqueSrcFiles, srcJars, errorproneFlags, nil, + transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneFlags, nil, "errorprone", "errorprone") extraJarDeps = append(extraJarDeps, errorprone) @@ -1240,8 +1249,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } shardSize := int(*(j.properties.Javac_shard_size)) var shardSrcs []android.Paths - if len(uniqueSrcFiles) > 0 { - shardSrcs = android.ShardPaths(uniqueSrcFiles, shardSize) + if len(uniqueJavaFiles) > 0 { + shardSrcs = android.ShardPaths(uniqueJavaFiles, shardSize) for idx, shardSrc := range shardSrcs { classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc, nil, flags, extraJarDeps) @@ -1254,7 +1263,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { jars = append(jars, classes) } } else { - classes := j.compileJavaClasses(ctx, jarName, -1, uniqueSrcFiles, srcJars, flags, extraJarDeps) + classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps) jars = append(jars, classes) } if ctx.Failed() { @@ -1435,10 +1444,6 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.headerJarFile = j.implementationJarFile } - if j.shouldInstrumentInApex(ctx) { - j.properties.Instrument = true - } - // enforce syntax check to jacoco filters for any build (http://b/183622051) specs := j.jacocoModuleToZipCommand(ctx) if ctx.Failed() { @@ -1956,7 +1961,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { if dep, ok := module.(SdkLibraryDependency); ok { switch tag { - case libTag: + case sdkLibTag, libTag: depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx)) deps.classpath = append(deps.classpath, depHeaderJars...) deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...) @@ -1976,7 +1981,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { switch tag { case bootClasspathTag: deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...) - case libTag, instrumentationForTag: + case sdkLibTag, libTag, instrumentationForTag: if _, ok := module.(*Plugin); ok { ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName) } @@ -2049,7 +2054,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } else if dep, ok := module.(android.SourceFileProducer); ok { switch tag { - case libTag: + case sdkLibTag, libTag: checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) deps.dexClasspath = append(deps.classpath, dep.Srcs()...) diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index 93168070e..3a28c5910 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -257,14 +257,14 @@ type commonBootclasspathFragment interface { // Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the // module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a // versioned sdk. - produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput + produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput // produceBootImageFiles will attempt to produce rules to create the boot image files at the paths // predefined in the bootImageConfig. // // If it could not create the files then it will return nil. Otherwise, it will return a map from // android.ArchType to the predefined paths of the boot image files. - produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch + produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs } var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil) @@ -583,23 +583,24 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // Perform hidden API processing. hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) - var bootImageFilesByArch bootImageFilesByArch + var bootImageFiles bootImageOutputs if imageConfig != nil { // Delegate the production of the boot image files to a module type specific method. common := ctx.Module().(commonBootclasspathFragment) - bootImageFilesByArch = common.produceBootImageFiles(ctx, imageConfig) + bootImageFiles = common.produceBootImageFiles(ctx, imageConfig) if shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) { // Zip the boot image files up, if available. This will generate the zip file in a // predefined location. - buildBootImageZipInPredefinedLocation(ctx, imageConfig, bootImageFilesByArch) + buildBootImageZipInPredefinedLocation(ctx, imageConfig, bootImageFiles.byArch) // Copy the dex jars of this fragment's content modules to their predefined locations. copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule) } - for _, variant := range imageConfig.apexVariants() { - arch := variant.target.Arch.ArchType.String() + for _, variant := range bootImageFiles.variants { + archType := variant.config.target.Arch.ArchType + arch := archType.String() for _, install := range variant.deviceInstalls { // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT. installDir := strings.TrimPrefix(filepath.Dir(install.To), "/") @@ -620,7 +621,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // A prebuilt fragment cannot contribute to an apex. if !android.IsModulePrebuilt(ctx.Module()) { // Provide the apex content info. - b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFilesByArch) + b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFiles) } } else { // Versioned fragments are not needed by make. @@ -663,7 +664,7 @@ func shouldCopyBootFilesToPredefinedLocations(ctx android.ModuleContext, imageCo // provideApexContentInfo creates, initializes and stores the apex content info for use by other // modules. -func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFilesByArch bootImageFilesByArch) { +func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFiles bootImageOutputs) { // Construct the apex content info from the config. info := BootclasspathFragmentApexContentInfo{ // Populate the apex content info with paths to the dex jars. @@ -674,14 +675,14 @@ func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleC info.modules = imageConfig.modules global := dexpreopt.GetGlobalConfig(ctx) if !global.DisableGenerateProfile { - info.profilePathOnHost = imageConfig.profilePathOnHost + info.profilePathOnHost = bootImageFiles.profile info.profileInstallPathInApex = imageConfig.profileInstallPathInApex } info.shouldInstallBootImageInApex = imageConfig.shouldInstallInApex() } - info.bootImageFilesByArch = bootImageFilesByArch + info.bootImageFilesByArch = bootImageFiles.byArch // Make the apex content info available for other modules. ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info) @@ -716,8 +717,6 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) // This is an exception to support end-to-end test for SdkExtensions, until such support exists. if android.InList("test_framework-sdkextensions", possibleUpdatableModules) { jars = jars.Append("com.android.sdkext", "test_framework-sdkextensions") - } else if android.InList("AddNewActivity", possibleUpdatableModules) { - jars = jars.Append("test_com.android.cts.frameworkresapkplits", "AddNewActivity") } else if android.InList("test_framework-apexd", possibleUpdatableModules) { jars = jars.Append("com.android.apex.test_package", "test_framework-apexd") } else if global.ApexBootJars.Len() != 0 && !android.IsModuleInVersionedSdk(ctx.Module()) { @@ -761,7 +760,7 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // Delegate the production of the hidden API all-flags.csv file to a module type specific method. common := ctx.Module().(commonBootclasspathFragment) - output := common.produceHiddenAPIOutput(ctx, contents, input) + output := common.produceHiddenAPIOutput(ctx, contents, fragments, input) // If the source or prebuilts module does not provide a signature patterns file then generate one // from the flags. @@ -769,7 +768,7 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // their own. if output.SignaturePatternsPath == nil { output.SignaturePatternsPath = buildRuleSignaturePatternsFile( - ctx, output.AllFlagsPath, []string{"*"}, nil, nil) + ctx, output.AllFlagsPath, []string{"*"}, nil, nil, "") } // Initialize a HiddenAPIInfo structure. @@ -840,30 +839,15 @@ func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.Modul // isTestFragment returns true if the current module is a test bootclasspath_fragment. func (b *BootclasspathFragmentModule) isTestFragment() bool { - if b.testFragment { - return true - } - - // TODO(b/194063708): Once test fragments all use bootclasspath_fragment_test - // Some temporary exceptions until all test fragments use the - // bootclasspath_fragment_test module type. - name := b.BaseModuleName() - if strings.HasPrefix(name, "test_") { - return true - } - if name == "apex.apexd_test_bootclasspath-fragment" { - return true - } - - return false + return b.testFragment } -// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files) -// for the fragment as well as encoding the flags in the boot dex jars. -func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +// generateHiddenApiFlagRules generates rules to generate hidden API flags and compute the signature +// patterns file. +func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput { // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the // paths to the created files. - output := hiddenAPIRulesForBootclasspathFragment(ctx, contents, input) + flagOutput := hiddenAPIFlagRulesForBootclasspathFragment(ctx, bootDexInfoByModule, contents, input, suffix) // If the module specifies split_packages or package_prefixes then use those to generate the // signature patterns. @@ -871,8 +855,8 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC packagePrefixes := input.PackagePrefixes singlePackages := input.SinglePackages if splitPackages != nil || packagePrefixes != nil || singlePackages != nil { - output.SignaturePatternsPath = buildRuleSignaturePatternsFile( - ctx, output.AllFlagsPath, splitPackages, packagePrefixes, singlePackages) + flagOutput.SignaturePatternsPath = buildRuleSignaturePatternsFile( + ctx, flagOutput.AllFlagsPath, splitPackages, packagePrefixes, singlePackages, suffix) } else if !b.isTestFragment() { ctx.ModuleErrorf(`Must specify at least one of the split_packages, package_prefixes and single_packages properties If this is a new bootclasspath_fragment or you are unsure what to do add the @@ -884,14 +868,76 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC should specify here. If you are happy with its suggestions then you can add the --fix option and it will fix them for you.`, b.BaseModuleName()) } + return flagOutput +} + +// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files) +// for the fragment as well as encoding the flags in the boot dex jars. +func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { + // Gather information about the boot dex files for the boot libraries provided by this fragment. + bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents) + + // Generate the flag file needed to encode into the dex files. + flagOutput := b.generateHiddenApiFlagRules(ctx, contents, input, bootDexInfoByModule, "") + + // Encode those flags into the dex files of the contents of this fragment. + encodedBootDexFilesByModule := hiddenAPIEncodeRulesForBootclasspathFragment(ctx, bootDexInfoByModule, flagOutput.AllFlagsPath) + + // Store that information for return for use by other rules. + output := &HiddenAPIOutput{ + HiddenAPIFlagOutput: flagOutput, + EncodedBootDexFilesByModule: encodedBootDexFilesByModule, + } + + // Get the ApiLevel associated with SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE, defaulting to current + // if not set. + config := ctx.Config() + targetApiLevel := android.ApiLevelOrPanic(ctx, + config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", "current")) + + // Filter the contents list to remove any modules that do not support the target build release. + // The current build release supports all the modules. + contentsForSdkSnapshot := []android.Module{} + for _, module := range contents { + // If the module has a min_sdk_version that is higher than the target build release then it will + // not work on the target build release and so must not be included in the sdk snapshot. + minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, module) + if minApiLevel.GreaterThan(targetApiLevel) { + continue + } + + contentsForSdkSnapshot = append(contentsForSdkSnapshot, module) + } + + var flagFilesByCategory FlagFilesByCategory + if len(contentsForSdkSnapshot) != len(contents) { + // The sdk snapshot has different contents to the runtime fragment so it is not possible to + // reuse the hidden API information generated for the fragment. So, recompute that information + // for the sdk snapshot. + filteredInput := b.createHiddenAPIFlagInput(ctx, contentsForSdkSnapshot, fragments) + + // Gather information about the boot dex files for the boot libraries provided by this fragment. + filteredBootDexInfoByModule := extractBootDexInfoFromModules(ctx, contentsForSdkSnapshot) + flagOutput = b.generateHiddenApiFlagRules(ctx, contentsForSdkSnapshot, filteredInput, filteredBootDexInfoByModule, "-for-sdk-snapshot") + flagFilesByCategory = filteredInput.FlagFilesByCategory + } else { + // The sdk snapshot has the same contents as the runtime fragment so reuse that information. + flagFilesByCategory = input.FlagFilesByCategory + } + + // Make the information available for the sdk snapshot. + ctx.SetProvider(HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{ + FlagFilesByCategory: flagFilesByCategory, + HiddenAPIFlagOutput: flagOutput, + }) return output } // produceBootImageFiles builds the boot image files from the source if it is required. -func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch { +func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { if SkipDexpreoptBootJars(ctx) { - return nil + return bootImageOutputs{} } // Only generate the boot image if the configuration does not skip it. @@ -903,21 +949,21 @@ func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleCo // // If it could not create the files then it will return nil. Otherwise, it will return a map from // android.ArchType to the predefined paths of the boot image files. -func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch { +func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { global := dexpreopt.GetGlobalConfig(ctx) if !shouldBuildBootImages(ctx.Config(), global) { - return nil + return bootImageOutputs{} } // Bootclasspath fragment modules that are for the platform do not produce a boot image. apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if apexInfo.IsForPlatform() { - return nil + return bootImageOutputs{} } // Bootclasspath fragment modules that are versioned do not produce a boot image. if android.IsModuleInVersionedSdk(ctx.Module()) { - return nil + return bootImageOutputs{} } // Build a profile for the image config and then use that to build the boot image. @@ -927,11 +973,11 @@ func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android. buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) // Build boot image files for the android variants. - androidBootImageFilesByArch := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) + bootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) // Return the boot image files for the android variants for inclusion in an APEX and to be zipped // up for the dist. - return androidBootImageFilesByArch + return bootImageFiles } func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries { @@ -1049,7 +1095,7 @@ func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx andro // Get the hidden API information from the module. mctx := ctx.SdkModuleContext() - hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoProvider).(HiddenAPIInfo) + hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoForSdkProvider).(HiddenAPIInfoForSdk) b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory // Copy all the generated file paths. @@ -1191,7 +1237,7 @@ func (module *PrebuiltBootclasspathFragmentModule) Name() string { } // produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified. -func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path { if src == nil { return defaultPath @@ -1232,14 +1278,14 @@ func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx an } // produceBootImageFiles extracts the boot image files from the APEX if available. -func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch { +func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) { - return nil + return bootImageOutputs{} } di := android.FindDeapexerProviderForModule(ctx) if di == nil { - return nil // An error has been reported by FindDeapexerProviderForModule. + return bootImageOutputs{} // An error has been reported by FindDeapexerProviderForModule. } profile := (android.WritablePath)(nil) @@ -1257,8 +1303,17 @@ func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx and // If the boot image files for the android variants are in the prebuilt apex, we must use those // rather than building new ones because those boot image files are going to be used on device. files := bootImageFilesByArch{} + bootImageFiles := bootImageOutputs{ + byArch: files, + profile: profile, + } for _, variant := range imageConfig.apexVariants() { arch := variant.target.Arch.ArchType + bootImageFiles.variants = append(bootImageFiles.variants, bootImageVariantOutputs{ + variant, + // No device installs needed when installed in APEX. + nil, + }) for _, toPath := range variant.imagesDeps { apexRelativePath := apexRootRelativePathToBootImageFile(arch, toPath.Base()) // Get the path to the file that the deapexer extracted from the prebuilt apex file. @@ -1276,11 +1331,11 @@ func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx and }) } } - return files + return bootImageFiles } else { if profile == nil { ctx.ModuleErrorf("Unable to produce boot image files: neither boot image files nor profiles exists in the prebuilt apex") - return nil + return bootImageOutputs{} } // Build boot image files for the android variants from the dex files provided by the contents // of this module. diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go index 2bfb255af..2541f14ff 100644 --- a/java/bootclasspath_fragment_test.go +++ b/java/bootclasspath_fragment_test.go @@ -96,23 +96,6 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testin } func TestBootclasspathFragment_Coverage(t *testing.T) { - prepareForTestWithFrameworkCoverage := android.GroupFixturePreparers( - android.FixtureMergeEnv(map[string]string{ - "EMMA_INSTRUMENT": "true", - "EMMA_INSTRUMENT_FRAMEWORK": "true", - }), - // need to mock jacocoagent here to satisfy dependency added for - // instrumented libraries at build time - android.FixtureAddFile("jacocoagent/Android.bp", []byte(` - java_library { - name: "jacocoagent", - srcs: ["Test.java"], - system_modules: "none", - sdk_version: "none", - } - `)), - ) - prepareWithBp := android.FixtureWithRootAndroidBp(` bootclasspath_fragment { name: "myfragment", @@ -191,7 +174,7 @@ func TestBootclasspathFragment_Coverage(t *testing.T) { t.Run("with coverage", func(t *testing.T) { result := android.GroupFixturePreparers( - prepareForTestWithFrameworkCoverage, + prepareForTestWithFrameworkJacocoInstrumentation, preparer, ).RunTest(t) checkContents(t, result, "mybootlib", "coveragelib") @@ -425,22 +408,6 @@ func TestBootclasspathFragment_Test(t *testing.T) { }, } - bootclasspath_fragment { - name: "test_fragment", - contents: ["mysdklibrary"], - hidden_api: { - split_packages: [], - }, - } - - bootclasspath_fragment { - name: "apex.apexd_test_bootclasspath-fragment", - contents: ["mysdklibrary"], - hidden_api: { - split_packages: [], - }, - } - bootclasspath_fragment_test { name: "a_test_fragment", contents: ["mysdklibrary"], @@ -462,12 +429,6 @@ func TestBootclasspathFragment_Test(t *testing.T) { fragment := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule) android.AssertBoolEquals(t, "not a test fragment", false, fragment.isTestFragment()) - fragment = result.Module("test_fragment", "android_common").(*BootclasspathFragmentModule) - android.AssertBoolEquals(t, "is a test fragment by prefix", true, fragment.isTestFragment()) - fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule) android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment()) - - fragment = result.Module("apex.apexd_test_bootclasspath-fragment", "android_common").(*BootclasspathFragmentModule) - android.AssertBoolEquals(t, "is a test fragment by name", true, fragment.isTestFragment()) } diff --git a/java/config/config.go b/java/config/config.go index 422f86002..45b668b0c 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -78,12 +78,12 @@ var ( func init() { pctx.Import("github.com/google/blueprint/bootstrap") - exportedVars.ExportStringStaticVariable("JavacHeapSize", "2048M") + exportedVars.ExportStringStaticVariable("JavacHeapSize", "4096M") exportedVars.ExportStringStaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}") // ErrorProne can use significantly more memory than javac alone, give it a higher heap // size (b/221480398). - exportedVars.ExportStringStaticVariable("ErrorProneHeapSize", "4096M") + exportedVars.ExportStringStaticVariable("ErrorProneHeapSize", "8192M") exportedVars.ExportStringStaticVariable("ErrorProneHeapFlags", "-J-Xmx${ErrorProneHeapSize}") // D8 invocations are shorter lived, so we restrict their JIT tiering relative to R8. @@ -128,12 +128,7 @@ func init() { if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" { return override } - switch ctx.Config().Getenv("EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN") { - case "true": - return "17" - default: - return "11" - } + return "17" }) pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin") @@ -160,6 +155,7 @@ func init() { pctx.HostBinToolVariable("ApiCheckCmd", "apicheck") pctx.HostBinToolVariable("D8Cmd", "d8") pctx.HostBinToolVariable("R8Cmd", "r8") + pctx.HostBinToolVariable("ResourceShrinkerCmd", "resourceshrinker") pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi") pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks") pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string { diff --git a/java/dex.go b/java/dex.go index a44d7921f..de36b1865 100644 --- a/java/dex.go +++ b/java/dex.go @@ -63,6 +63,8 @@ type DexProperties struct { // classes referenced by the app manifest. Defaults to false. No_aapt_flags *bool + Shrink_resources *bool + // Flags to pass to proguard. Proguard_flags []string @@ -200,6 +202,16 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, "--verbose") } + // Supplying the platform build flag disables various features like API modeling and desugaring. + // For targets with a stable min SDK version (i.e., when the min SDK is both explicitly specified + // and managed+versioned), we suppress this flag to ensure portability. + // Note: Targets with a min SDK kind of core_platform (e.g., framework.jar) or unspecified (e.g., + // services.jar), are not classified as stable, which is WAI. + // TODO(b/232073181): Expand to additional min SDK cases after validation. + if !minSdkVersion.Stable() { + flags = append(flags, "--android-platform-build") + } + effectiveVersion, err := minSdkVersion.EffectiveVersion(ctx) if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err) diff --git a/java/dex_test.go b/java/dex_test.go index a3e2deda4..66178732a 100644 --- a/java/dex_test.go +++ b/java/dex_test.go @@ -30,6 +30,19 @@ func TestR8(t *testing.T) { platform_apis: true, } + android_app { + name: "stable_app", + srcs: ["foo.java"], + sdk_version: "current", + min_sdk_version: "31", + } + + android_app { + name: "core_platform_app", + srcs: ["foo.java"], + sdk_version: "core_platform", + } + java_library { name: "lib", srcs: ["foo.java"], @@ -42,11 +55,15 @@ func TestR8(t *testing.T) { `) app := result.ModuleForTests("app", "android_common") + stableApp := result.ModuleForTests("stable_app", "android_common") + corePlatformApp := result.ModuleForTests("core_platform_app", "android_common") lib := result.ModuleForTests("lib", "android_common") staticLib := result.ModuleForTests("static_lib", "android_common") appJavac := app.Rule("javac") appR8 := app.Rule("r8") + stableAppR8 := stableApp.Rule("r8") + corePlatformAppR8 := corePlatformApp.Rule("r8") libHeader := lib.Output("turbine-combined/lib.jar").Output staticLibHeader := staticLib.Output("turbine-combined/static_lib.jar").Output @@ -61,6 +78,12 @@ func TestR8(t *testing.T) { appR8.Args["r8Flags"], staticLibHeader.String()) android.AssertStringDoesContain(t, "expected -ignorewarnings in app r8 flags", appR8.Args["r8Flags"], "-ignorewarnings") + android.AssertStringDoesContain(t, "expected --android-platform-build in app r8 flags", + appR8.Args["r8Flags"], "--android-platform-build") + android.AssertStringDoesNotContain(t, "expected no --android-platform-build in stable_app r8 flags", + stableAppR8.Args["r8Flags"], "--android-platform-build") + android.AssertStringDoesContain(t, "expected --android-platform-build in core_platform_app r8 flags", + corePlatformAppR8.Args["r8Flags"], "--android-platform-build") } func TestR8Flags(t *testing.T) { @@ -88,7 +111,8 @@ func TestR8Flags(t *testing.T) { appR8.Args["r8Flags"], "-dontobfuscate") android.AssertStringDoesNotContain(t, "expected no -ignorewarnings in app r8 flags", appR8.Args["r8Flags"], "-ignorewarnings") - + android.AssertStringDoesContain(t, "expected --android-platform-build in app r8 flags", + appR8.Args["r8Flags"], "--android-platform-build") } func TestD8(t *testing.T) { diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 4e416fc82..b3faae895 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -228,6 +228,11 @@ func init() { } // Target-independent description of a boot image. +// +// WARNING: All fields in this struct should be initialized in the genBootImageConfigs function. +// Failure to do so can lead to data races if there is no synchronization enforced ordering between +// the writer and the reader. Fields which break this rule are marked as deprecated and should be +// removed and replaced with something else, e.g. providers. type bootImageConfig struct { // If this image is an extension, the image that it extends. extends *bootImageConfig @@ -268,14 +273,15 @@ type bootImageConfig struct { zip android.WritablePath // Rules which should be used in make to install the outputs. + // + // Deprecated: Not initialized correctly, see struct comment. profileInstalls android.RuleBuilderInstalls // Path to the license metadata file for the module that built the profile. + // + // Deprecated: Not initialized correctly, see struct comment. profileLicenseMetadataFile android.OptionalPath - // Path to the image profile file on host (or empty, if profile is not generated). - profilePathOnHost android.Path - // Target-dependent fields. variants []*bootImageVariant @@ -284,6 +290,8 @@ type bootImageConfig struct { } // Target-dependent description of a boot image. +// +// WARNING: The warning comment on bootImageConfig applies here too. type bootImageVariant struct { *bootImageConfig @@ -314,14 +322,23 @@ type bootImageVariant struct { primaryImagesDeps android.Paths // Rules which should be used in make to install the outputs on host. - installs android.RuleBuilderInstalls - vdexInstalls android.RuleBuilderInstalls - unstrippedInstalls android.RuleBuilderInstalls + // + // Deprecated: Not initialized correctly, see struct comment. + installs android.RuleBuilderInstalls - // Rules which should be used in make to install the outputs on device. - deviceInstalls android.RuleBuilderInstalls + // Rules which should be used in make to install the vdex outputs on host. + // + // Deprecated: Not initialized correctly, see struct comment. + vdexInstalls android.RuleBuilderInstalls + + // Rules which should be used in make to install the unstripped outputs on host. + // + // Deprecated: Not initialized correctly, see struct comment. + unstrippedInstalls android.RuleBuilderInstalls // Path to the license metadata file for the module that built the image. + // + // Deprecated: Not initialized correctly, see struct comment. licenseMetadataFile android.OptionalPath } @@ -548,7 +565,7 @@ func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJars // boot image files. // // The paths are returned because they are needed elsewhere in Soong, e.g. for populating an APEX. -func buildBootImageVariantsForAndroidOs(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) bootImageFilesByArch { +func buildBootImageVariantsForAndroidOs(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) bootImageOutputs { return buildBootImageForOsType(ctx, image, profile, android.Android) } @@ -563,21 +580,38 @@ func buildBootImageVariantsForBuildOs(ctx android.ModuleContext, image *bootImag buildBootImageForOsType(ctx, image, profile, ctx.Config().BuildOS) } +// bootImageOutputs encapsulates information about boot images that were created/obtained by +// commonBootclasspathFragment.produceBootImageFiles. +type bootImageOutputs struct { + // Map from arch to the paths to the boot image files created/obtained for that arch. + byArch bootImageFilesByArch + + variants []bootImageVariantOutputs + + // The path to the profile file created/obtained for the boot image. + profile android.WritablePath +} + // buildBootImageForOsType takes a bootImageConfig, a profile file and an android.OsType // boot image files are required for and it creates rules to build the boot image // files for all the required architectures for them. // // It returns a map from android.ArchType to the predefined paths of the boot image files. -func buildBootImageForOsType(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath, requiredOsType android.OsType) bootImageFilesByArch { +func buildBootImageForOsType(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath, requiredOsType android.OsType) bootImageOutputs { filesByArch := bootImageFilesByArch{} + imageOutputs := bootImageOutputs{ + byArch: filesByArch, + profile: profile, + } for _, variant := range image.variants { if variant.target.Os == requiredOsType { - buildBootImageVariant(ctx, variant, profile) + variantOutputs := buildBootImageVariant(ctx, variant, profile) + imageOutputs.variants = append(imageOutputs.variants, variantOutputs) filesByArch[variant.target.Arch.ArchType] = variant.imagesDeps.Paths() } } - return filesByArch + return imageOutputs } // buildBootImageZipInPredefinedLocation generates a zip file containing all the boot image files. @@ -605,8 +639,13 @@ func buildBootImageZipInPredefinedLocation(ctx android.ModuleContext, image *boo rule.Build("zip_"+image.name, "zip "+image.name+" image") } +type bootImageVariantOutputs struct { + config *bootImageVariant + deviceInstalls android.RuleBuilderInstalls +} + // Generate boot image build rules for a specific target. -func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) { +func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) bootImageVariantOutputs { globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) @@ -764,11 +803,20 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p rule.Build(image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String()) // save output and installed files for makevars + // TODO - these are always the same and so should be initialized in genBootImageConfigs image.installs = rule.Installs() image.vdexInstalls = vdexInstalls image.unstrippedInstalls = unstrippedInstalls - image.deviceInstalls = deviceInstalls - image.licenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile()) + + // Only set the licenseMetadataFile from the active module. + if isActiveModule(ctx.Module()) { + image.licenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile()) + } + + return bootImageVariantOutputs{ + image, + deviceInstalls, + } } const failureMessage = `ERROR: Dex2oat failed to compile a boot image. @@ -824,8 +872,6 @@ func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) and rule.Build("bootJarsProfile", "profile boot jars") - image.profilePathOnHost = profile - return profile } diff --git a/java/dexpreopt_config_test.go b/java/dexpreopt_config_test.go new file mode 100644 index 000000000..b704d09d2 --- /dev/null +++ b/java/dexpreopt_config_test.go @@ -0,0 +1,35 @@ +// Copyright 2022 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "runtime" + "testing" + + "android/soong/android" +) + +func TestBootImageConfig(t *testing.T) { + if runtime.GOOS != "linux" { + t.Skipf("Skipping as boot image config test is only supported on linux not %s", runtime.GOOS) + } + + result := android.GroupFixturePreparers( + PrepareForBootImageConfigTest, + ).RunTest(t) + + CheckArtBootImageConfig(t, result) + CheckFrameworkBootImageConfig(t, result) +} diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go new file mode 100644 index 000000000..1c236d8af --- /dev/null +++ b/java/dexpreopt_config_testing.go @@ -0,0 +1,768 @@ +// Copyright 2022 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Testing support for dexpreopt config. +// +// The bootImageConfig/bootImageVariant structs returned by genBootImageConfigs are used in many +// places in the build and are currently mutated in a number of those locations. This provides +// comprehensive tests of the fields in those structs to ensure that they have been initialized +// correctly and where relevant, mutated correctly. +// +// This is used in TestBootImageConfig to verify that the + +package java + +import ( + "fmt" + "strings" + "testing" + + "android/soong/android" +) + +// PrepareForBootImageConfigTest is the minimal set of preparers that are needed to be able to use +// the Check*BootImageConfig methods define here. +var PrepareForBootImageConfigTest = android.GroupFixturePreparers( + android.PrepareForTestWithArchMutator, + android.PrepareForTestAccessingMakeVars, + FixtureConfigureBootJars("com.android.art:core1", "com.android.art:core2", "platform:framework"), +) + +// normalizedInstall represents a android.RuleBuilderInstall that has been normalized to remove +// test specific parts of the From path. +type normalizedInstall struct { + from string + to string +} + +// normalizeInstalls converts a slice of android.RuleBuilderInstall into a slice of +// normalizedInstall to allow them to be compared using android.AssertDeepEquals. +func normalizeInstalls(installs android.RuleBuilderInstalls) []normalizedInstall { + var normalized []normalizedInstall + for _, install := range installs { + normalized = append(normalized, normalizedInstall{ + from: install.From.RelativeToTop().String(), + to: install.To, + }) + } + return normalized +} + +// assertInstallsEqual normalized the android.RuleBuilderInstalls and compares against the expected +// normalizedInstalls. +func assertInstallsEqual(t *testing.T, message string, expected []normalizedInstall, actual android.RuleBuilderInstalls) { + t.Helper() + normalizedActual := normalizeInstalls(actual) + android.AssertDeepEquals(t, message, expected, normalizedActual) +} + +// expectedConfig encapsulates the expected properties that will be set in a bootImageConfig +// +// Each field <x> in here is compared against the corresponding field <x> in bootImageConfig. +type expectedConfig struct { + name string + stem string + dir string + symbolsDir string + installDirOnDevice string + installDirOnHost string + profileInstallPathInApex string + modules android.ConfiguredJarList + dexPaths []string + dexPathsDeps []string + zip string + variants []*expectedVariant + + // Mutated fields + profileInstalls []normalizedInstall + profileLicenseMetadataFile string +} + +// expectedVariant encapsulates the expected properties that will be set in a bootImageVariant +// +// Each field <x> in here is compared against the corresponding field <x> in bootImageVariant +// except for archType which is compared against the target.Arch.ArchType field in bootImageVariant. +type expectedVariant struct { + archType android.ArchType + dexLocations []string + dexLocationsDeps []string + imagePathOnHost string + imagePathOnDevice string + imagesDeps []string + primaryImages string + primaryImagesDeps []string + + // Mutated fields + installs []normalizedInstall + vdexInstalls []normalizedInstall + unstrippedInstalls []normalizedInstall + licenseMetadataFile string +} + +// CheckArtBootImageConfig checks the status of the fields of the bootImageConfig and +// bootImageVariant structures that are returned from artBootImageConfig. +// +// This is before any fields are mutated. +func CheckArtBootImageConfig(t *testing.T, result *android.TestResult) { + checkArtBootImageConfig(t, result, false, "") +} + +// getArtImageConfig gets the ART bootImageConfig that was created during the test. +func getArtImageConfig(result *android.TestResult) *bootImageConfig { + pathCtx := &android.TestPathContext{TestResult: result} + imageConfig := artBootImageConfig(pathCtx) + return imageConfig +} + +// checkArtBootImageConfig checks the ART boot image. +// +// mutated is true if this is called after fields in the image have been mutated by the ART +// bootclasspath_fragment and false otherwise. +func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated bool, expectedLicenseMetadataFile string) { + imageConfig := getArtImageConfig(result) + + expected := &expectedConfig{ + name: "art", + stem: "boot", + dir: "out/soong/test_device/dex_artjars", + symbolsDir: "out/soong/test_device/dex_artjars_unstripped", + installDirOnDevice: "system/framework", + installDirOnHost: "apex/art_boot_images/javalib", + profileInstallPathInApex: "etc/boot-image.prof", + modules: android.CreateTestConfiguredJarList([]string{"com.android.art:core1", "com.android.art:core2"}), + dexPaths: []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar"}, + dexPathsDeps: []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar"}, + zip: "out/soong/test_device/dex_artjars/art.zip", + variants: []*expectedVariant{ + { + archType: android.Arm64, + dexLocations: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, + dexLocationsDeps: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, + imagePathOnHost: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art", + imagePathOnDevice: "/system/framework/arm64/boot.art", + imagesDeps: []string{ + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art", + to: "/apex/art_boot_images/javalib/arm64/boot.art", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat", + to: "/apex/art_boot_images/javalib/arm64/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art", + to: "/apex/art_boot_images/javalib/arm64/boot-core2.art", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat", + to: "/apex/art_boot_images/javalib/arm64/boot-core2.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex", + to: "/apex/art_boot_images/javalib/arm64/boot.vdex", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex", + to: "/apex/art_boot_images/javalib/arm64/boot-core2.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat", + to: "/apex/art_boot_images/javalib/arm64/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat", + to: "/apex/art_boot_images/javalib/arm64/boot-core2.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + { + archType: android.Arm, + dexLocations: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, + dexLocationsDeps: []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"}, + imagePathOnHost: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art", + imagePathOnDevice: "/system/framework/arm/boot.art", + imagesDeps: []string{ + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art", + to: "/apex/art_boot_images/javalib/arm/boot.art", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat", + to: "/apex/art_boot_images/javalib/arm/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art", + to: "/apex/art_boot_images/javalib/arm/boot-core2.art", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat", + to: "/apex/art_boot_images/javalib/arm/boot-core2.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex", + to: "/apex/art_boot_images/javalib/arm/boot.vdex", + }, + { + from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex", + to: "/apex/art_boot_images/javalib/arm/boot-core2.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat", + to: "/apex/art_boot_images/javalib/arm/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat", + to: "/apex/art_boot_images/javalib/arm/boot-core2.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + { + archType: android.X86_64, + dexLocations: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, + dexLocationsDeps: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, + imagePathOnHost: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art", + imagePathOnDevice: "/system/framework/x86_64/boot.art", + imagesDeps: []string{ + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art", + to: "/apex/art_boot_images/javalib/x86_64/boot.art", + }, { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat", + to: "/apex/art_boot_images/javalib/x86_64/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art", + to: "/apex/art_boot_images/javalib/x86_64/boot-core2.art", + }, { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat", + to: "/apex/art_boot_images/javalib/x86_64/boot-core2.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex", + to: "/apex/art_boot_images/javalib/x86_64/boot.vdex", + }, + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex", + to: "/apex/art_boot_images/javalib/x86_64/boot-core2.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat", + to: "/apex/art_boot_images/javalib/x86_64/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat", + to: "/apex/art_boot_images/javalib/x86_64/boot-core2.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + { + archType: android.X86, + dexLocations: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, + dexLocationsDeps: []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"}, + imagePathOnHost: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art", + imagePathOnDevice: "/system/framework/x86/boot.art", + imagesDeps: []string{ + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art", + to: "/apex/art_boot_images/javalib/x86/boot.art", + }, { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat", + to: "/apex/art_boot_images/javalib/x86/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art", + to: "/apex/art_boot_images/javalib/x86/boot-core2.art", + }, { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat", + to: "/apex/art_boot_images/javalib/x86/boot-core2.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex", + to: "/apex/art_boot_images/javalib/x86/boot.vdex", + }, + { + from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex", + to: "/apex/art_boot_images/javalib/x86/boot-core2.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat", + to: "/apex/art_boot_images/javalib/x86/boot.oat", + }, + { + from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat", + to: "/apex/art_boot_images/javalib/x86/boot-core2.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + }, + } + + checkBootImageConfig(t, imageConfig, mutated, expected) +} + +// getFrameworkImageConfig gets the framework bootImageConfig that was created during the test. +func getFrameworkImageConfig(result *android.TestResult) *bootImageConfig { + pathCtx := &android.TestPathContext{TestResult: result} + imageConfig := defaultBootImageConfig(pathCtx) + return imageConfig +} + +// CheckFrameworkBootImageConfig checks the status of the fields of the bootImageConfig and +// bootImageVariant structures that are returned from defaultBootImageConfig. +// +// This is before any fields are mutated. +func CheckFrameworkBootImageConfig(t *testing.T, result *android.TestResult) { + checkFrameworkBootImageConfig(t, result, false, "") +} + +// checkFrameworkBootImageConfig checks the framework boot image. +// +// mutated is true if this is called after fields in the image have been mutated by the +// platform_bootclasspath and false otherwise. +func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mutated bool, expectedLicenseMetadataFile string) { + imageConfig := getFrameworkImageConfig(result) + + expected := &expectedConfig{ + name: "boot", + stem: "boot", + dir: "out/soong/test_device/dex_bootjars", + symbolsDir: "out/soong/test_device/dex_bootjars_unstripped", + installDirOnDevice: "system/framework", + installDirOnHost: "system/framework", + profileInstallPathInApex: "", + modules: android.CreateTestConfiguredJarList([]string{"platform:framework"}), + dexPaths: []string{"out/soong/test_device/dex_bootjars_input/framework.jar"}, + dexPathsDeps: []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar", "out/soong/test_device/dex_bootjars_input/framework.jar"}, + zip: "out/soong/test_device/dex_bootjars/boot.zip", + variants: []*expectedVariant{ + { + archType: android.Arm64, + dexLocations: []string{"/system/framework/framework.jar"}, + dexLocationsDeps: []string{ + "/apex/com.android.art/javalib/core1.jar", + "/apex/com.android.art/javalib/core2.jar", + "/system/framework/framework.jar", + }, + imagePathOnHost: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art", + imagePathOnDevice: "/system/framework/arm64/boot-framework.art", + imagesDeps: []string{ + "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art", + "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat", + "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex", + }, + primaryImages: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art", + primaryImagesDeps: []string{ + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art", + to: "/system/framework/arm64/boot-framework.art", + }, + { + from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat", + to: "/system/framework/arm64/boot-framework.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex", + to: "/system/framework/arm64/boot-framework.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat", + to: "/system/framework/arm64/boot-framework.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + { + archType: android.Arm, + dexLocations: []string{"/system/framework/framework.jar"}, + dexLocationsDeps: []string{ + "/apex/com.android.art/javalib/core1.jar", + "/apex/com.android.art/javalib/core2.jar", + "/system/framework/framework.jar", + }, + imagePathOnHost: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art", + imagePathOnDevice: "/system/framework/arm/boot-framework.art", + imagesDeps: []string{ + "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art", + "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat", + "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex", + }, + primaryImages: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art", + primaryImagesDeps: []string{ + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat", + "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art", + to: "/system/framework/arm/boot-framework.art", + }, + { + from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat", + to: "/system/framework/arm/boot-framework.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex", + to: "/system/framework/arm/boot-framework.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat", + to: "/system/framework/arm/boot-framework.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + { + archType: android.X86_64, + dexLocations: []string{"host/linux-x86/system/framework/framework.jar"}, + dexLocationsDeps: []string{ + "host/linux-x86/apex/com.android.art/javalib/core1.jar", + "host/linux-x86/apex/com.android.art/javalib/core2.jar", + "host/linux-x86/system/framework/framework.jar", + }, + imagePathOnHost: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art", + imagePathOnDevice: "/system/framework/x86_64/boot-framework.art", + imagesDeps: []string{ + "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art", + "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat", + "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex", + }, + primaryImages: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art", + primaryImagesDeps: []string{ + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art", + to: "/system/framework/x86_64/boot-framework.art", + }, + { + from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat", + to: "/system/framework/x86_64/boot-framework.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex", + to: "/system/framework/x86_64/boot-framework.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat", + to: "/system/framework/x86_64/boot-framework.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + { + archType: android.X86, + dexLocations: []string{"host/linux-x86/system/framework/framework.jar"}, + dexLocationsDeps: []string{ + "host/linux-x86/apex/com.android.art/javalib/core1.jar", + "host/linux-x86/apex/com.android.art/javalib/core2.jar", + "host/linux-x86/system/framework/framework.jar", + }, + imagePathOnHost: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art", + imagePathOnDevice: "/system/framework/x86/boot-framework.art", + imagesDeps: []string{ + "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art", + "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat", + "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex", + }, + primaryImages: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art", + primaryImagesDeps: []string{ + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat", + "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex", + }, + installs: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art", + to: "/system/framework/x86/boot-framework.art", + }, + { + from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat", + to: "/system/framework/x86/boot-framework.oat", + }, + }, + vdexInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex", + to: "/system/framework/x86/boot-framework.vdex", + }, + }, + unstrippedInstalls: []normalizedInstall{ + { + from: "out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat", + to: "/system/framework/x86/boot-framework.oat", + }, + }, + licenseMetadataFile: expectedLicenseMetadataFile, + }, + }, + profileInstalls: []normalizedInstall{ + {from: "out/soong/test_device/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"}, + {from: "out/soong/test_device/dex_bootjars/boot.prof", to: "/system/etc/boot-image.prof"}, + }, + profileLicenseMetadataFile: expectedLicenseMetadataFile, + } + + checkBootImageConfig(t, imageConfig, mutated, expected) +} + +// clearMutatedFields clears fields in the expectedConfig that correspond to fields in the +// bootImageConfig/bootImageVariant structs which are mutated outside the call to +// genBootImageConfigs. +// +// This allows the resulting expectedConfig struct to be compared against the values of those boot +// image structs immediately the call to genBootImageConfigs. If this is not called then the +// expectedConfig struct will expect the boot image structs to have been mutated by the ART +// bootclasspath_fragment and the platform_bootclasspath. +func clearMutatedFields(expected *expectedConfig) { + expected.profileInstalls = nil + expected.profileLicenseMetadataFile = "" + for _, variant := range expected.variants { + variant.installs = nil + variant.vdexInstalls = nil + variant.unstrippedInstalls = nil + variant.licenseMetadataFile = "" + } +} + +// checkBootImageConfig checks a boot image against the expected contents. +// +// If mutated is false then this will clear any mutated fields in the expected contents back to the +// zero value so that they will match the unmodified values in the boot image. +// +// It runs the checks in an image specific subtest of the current test. +func checkBootImageConfig(t *testing.T, imageConfig *bootImageConfig, mutated bool, expected *expectedConfig) { + if !mutated { + clearMutatedFields(expected) + } + + t.Run(imageConfig.name, func(t *testing.T) { + nestedCheckBootImageConfig(t, imageConfig, expected) + }) +} + +// nestedCheckBootImageConfig does the work of comparing the image against the expected values and +// is run in an image specific subtest. +func nestedCheckBootImageConfig(t *testing.T, imageConfig *bootImageConfig, expected *expectedConfig) { + android.AssertStringEquals(t, "name", expected.name, imageConfig.name) + android.AssertStringEquals(t, "stem", expected.stem, imageConfig.stem) + android.AssertPathRelativeToTopEquals(t, "dir", expected.dir, imageConfig.dir) + android.AssertPathRelativeToTopEquals(t, "symbolsDir", expected.symbolsDir, imageConfig.symbolsDir) + android.AssertStringEquals(t, "installDirOnDevice", expected.installDirOnDevice, imageConfig.installDirOnDevice) + android.AssertStringEquals(t, "installDirOnHost", expected.installDirOnHost, imageConfig.installDirOnHost) + android.AssertStringEquals(t, "profileInstallPathInApex", expected.profileInstallPathInApex, imageConfig.profileInstallPathInApex) + android.AssertDeepEquals(t, "modules", expected.modules, imageConfig.modules) + android.AssertPathsRelativeToTopEquals(t, "dexPaths", expected.dexPaths, imageConfig.dexPaths.Paths()) + android.AssertPathsRelativeToTopEquals(t, "dexPathsDeps", expected.dexPathsDeps, imageConfig.dexPathsDeps.Paths()) + // dexPathsByModule is just a different representation of the other information in the config. + android.AssertPathRelativeToTopEquals(t, "zip", expected.zip, imageConfig.zip) + assertInstallsEqual(t, "profileInstalls", expected.profileInstalls, imageConfig.profileInstalls) + android.AssertStringEquals(t, "profileLicenseMetadataFile", expected.profileLicenseMetadataFile, imageConfig.profileLicenseMetadataFile.RelativeToTop().String()) + + android.AssertIntEquals(t, "variant count", 4, len(imageConfig.variants)) + for i, variant := range imageConfig.variants { + expectedVariant := expected.variants[i] + t.Run(variant.target.Arch.ArchType.String(), func(t *testing.T) { + android.AssertDeepEquals(t, "archType", expectedVariant.archType, variant.target.Arch.ArchType) + android.AssertDeepEquals(t, "dexLocations", expectedVariant.dexLocations, variant.dexLocations) + android.AssertDeepEquals(t, "dexLocationsDeps", expectedVariant.dexLocationsDeps, variant.dexLocationsDeps) + android.AssertPathRelativeToTopEquals(t, "imagePathOnHost", expectedVariant.imagePathOnHost, variant.imagePathOnHost) + android.AssertStringEquals(t, "imagePathOnDevice", expectedVariant.imagePathOnDevice, variant.imagePathOnDevice) + android.AssertPathsRelativeToTopEquals(t, "imagesDeps", expectedVariant.imagesDeps, variant.imagesDeps.Paths()) + android.AssertPathRelativeToTopEquals(t, "primaryImages", expectedVariant.primaryImages, variant.primaryImages) + android.AssertPathsRelativeToTopEquals(t, "primaryImagesDeps", expectedVariant.primaryImagesDeps, variant.primaryImagesDeps) + assertInstallsEqual(t, "installs", expectedVariant.installs, variant.installs) + assertInstallsEqual(t, "vdexInstalls", expectedVariant.vdexInstalls, variant.vdexInstalls) + assertInstallsEqual(t, "unstrippedInstalls", expectedVariant.unstrippedInstalls, variant.unstrippedInstalls) + android.AssertStringEquals(t, "licenseMetadataFile", expectedVariant.licenseMetadataFile, variant.licenseMetadataFile.RelativeToTop().String()) + }) + } +} + +// CheckMutatedArtBootImageConfig checks the mutated fields in the bootImageConfig/Variant for ART. +func CheckMutatedArtBootImageConfig(t *testing.T, result *android.TestResult, expectedLicenseMetadataFile string) { + checkArtBootImageConfig(t, result, true, expectedLicenseMetadataFile) + + // Check the dexpreopt make vars. Do it in here as it depends on the expected license metadata + // file at the moment and it + checkDexpreoptMakeVars(t, result, expectedLicenseMetadataFile) +} + +// CheckMutatedFrameworkBootImageConfig checks the mutated fields in the bootImageConfig/Variant for framework. +func CheckMutatedFrameworkBootImageConfig(t *testing.T, result *android.TestResult, expectedLicenseMetadataFile string) { + checkFrameworkBootImageConfig(t, result, true, expectedLicenseMetadataFile) +} + +// checkDexpreoptMakeVars checks the DEXPREOPT_ prefixed make vars produced by dexpreoptBootJars +// singleton. +func checkDexpreoptMakeVars(t *testing.T, result *android.TestResult, expectedLicenseMetadataFile string) { + vars := result.MakeVarsForTesting(func(variable android.MakeVarVariable) bool { + return strings.HasPrefix(variable.Name(), "DEXPREOPT_") + }) + + out := &strings.Builder{} + for _, v := range vars { + fmt.Fprintf(out, "%s=%s\n", v.Name(), android.StringRelativeToTop(result.Config, v.Value())) + } + format := ` +DEXPREOPT_BOOTCLASSPATH_DEX_FILES=out/soong/test_device/dex_artjars_input/core1.jar out/soong/test_device/dex_artjars_input/core2.jar out/soong/test_device/dex_bootjars_input/framework.jar +DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS=/apex/com.android.art/javalib/core1.jar /apex/com.android.art/javalib/core2.jar /system/framework/framework.jar +DEXPREOPT_BOOT_JARS_MODULES=platform:framework +DEXPREOPT_GEN=out/host/linux-x86/bin/dexpreopt_gen +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/apex/art_boot_images/javalib/x86_64/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art:/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art:/system/framework/arm/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art:/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art:/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat +DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art:/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat +DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex +DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex +DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex +DEXPREOPT_IMAGE_DEPS_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex +DEXPREOPT_IMAGE_DEPS_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex +DEXPREOPT_IMAGE_DEPS_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex +DEXPREOPT_IMAGE_DEPS_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex +DEXPREOPT_IMAGE_DEPS_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex +DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm=%[1]s +DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s +DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s +DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86_64=%[1]s +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic +DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic +DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/system/framework/boot.art +DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art:/system/framework/boot-framework.art +DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTart=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art +DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/test_device/dex_bootjars/android/system/framework/boot-framework.art +DEXPREOPT_IMAGE_NAMES=art boot +DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/test_device/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/test_device/dex_bootjars/boot.prof:/system/etc/boot-image.prof +DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat +DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex:/system/framework/arm/boot-framework.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex:/system/framework/arm64/boot-framework.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex:/system/framework/x86/boot-framework.vdex +DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex:/system/framework/x86_64/boot-framework.vdex +DEXPREOPT_IMAGE_ZIP_art=out/soong/test_device/dex_artjars/art.zip +DEXPREOPT_IMAGE_ZIP_boot=out/soong/test_device/dex_bootjars/boot.zip +DEXPREOPT_IMAGE_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art +DEXPREOPT_IMAGE_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art +DEXPREOPT_IMAGE_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art +DEXPREOPT_IMAGE_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art +DEXPREOPT_IMAGE_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art +DEXPREOPT_IMAGE_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art +DEXPREOPT_IMAGE_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art +DEXPREOPT_IMAGE_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art +` + expected := strings.TrimSpace(fmt.Sprintf(format, expectedLicenseMetadataFile)) + actual := strings.TrimSpace(out.String()) + android.AssertStringEquals(t, "vars", expected, actual) +} diff --git a/java/droiddoc.go b/java/droiddoc.go index 9b1f43b4c..2173dae30 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -267,7 +267,7 @@ func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) - ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) + ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...) } } @@ -367,7 +367,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } else { panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName())) } - case libTag: + case libTag, sdkLibTag: if dep, ok := module.(SdkLibraryDependency); ok { deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { @@ -684,7 +684,7 @@ func javadocCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs andro outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand { cmd := rule.Command(). - BuiltTool("soong_javac_wrapper").Tool(config.JavadocCmd(ctx)). + BuiltTool("soong_javac_wrapper").Tool(android.PathForSource(ctx, "prebuilts/jdk/jdk11/linux-x86/bin/javadoc")). Flag(config.JavacVmFlags). FlagWithArg("-encoding ", "UTF-8"). FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "javadoc.rsp"), srcs). @@ -755,6 +755,7 @@ func dokkaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, return rule.Command(). BuiltTool("dokka"). Flag(config.JavacVmFlags). + Flag("-J--add-opens=java.base/java.lang=ALL-UNNAMED"). Flag(srcJarDir.String()). FlagWithInputList("-classpath ", dokkaClasspath, ":"). FlagWithArg("-format ", "dac"). diff --git a/java/droidstubs.go b/java/droidstubs.go index 12590ca50..5777b185c 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -17,6 +17,7 @@ package java import ( "fmt" "path/filepath" + "regexp" "strings" "github.com/google/blueprint/proptools" @@ -27,7 +28,7 @@ import ( ) // The values allowed for Droidstubs' Api_levels_sdk_type -var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib"} +var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"} func init() { RegisterStubsBuildComponents(android.InitRegistrationContext) @@ -133,7 +134,7 @@ type DroidstubsProperties struct { // the dirs which Metalava extracts API levels annotations from. Api_levels_annotations_dirs []string - // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system' and 'module-lib' for now; defaults to public. + // the sdk kind which Metalava extracts API levels annotations from. Supports 'public', 'system', 'module-lib' and 'system-server'; defaults to public. Api_levels_sdk_type *string // the filename which Metalava extracts API levels annotations from. Defaults to android.jar. @@ -142,6 +143,10 @@ type DroidstubsProperties struct { // if set to true, collect the values used by the Dev tools and // write them in files packaged with the SDK. Defaults to false. Write_sdk_values *bool + + // path or filegroup to file defining extension an SDK name <-> numerical ID mapping and + // what APIs exist in which SDKs; passed to metalava via --sdk-extensions-info + Extensions_info_file *string `android:"path"` } // Used by xsd_config @@ -398,9 +403,20 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") var dirs []string + var extensions_dir string ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { if t, ok := m.(*ExportedDroiddocDir); ok { + extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`) + + // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps; + // ideally this should be read from prebuiltApis.properties.Extensions_* for _, dep := range t.deps { + if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil { + if extensions_dir == "" { + extensions_dir = t.dir.String() + "/extensions" + } + cmd.Implicit(dep) + } if dep.Base() == filename { cmd.Implicit(dep) } @@ -429,6 +445,8 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an // for older releases. Similarly, module-lib falls back to system API. var sdkDirs []string switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") { + case "system-server": + sdkDirs = []string{"system-server", "module-lib", "system", "public"} case "module-lib": sdkDirs = []string{"module-lib", "system", "public"} case "system": @@ -445,6 +463,16 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename)) } } + + if d.properties.Extensions_info_file != nil { + if extensions_dir == "" { + ctx.ModuleErrorf("extensions_info_file set, but no SDK extension dirs found") + } + info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file) + cmd.Implicit(info_file) + cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir) + cmd.FlagWithArg("--sdk-extensions-info ", info_file.String()) + } } func metalavaUseRbe(ctx android.ModuleContext) bool { diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go index 9fdfddeb1..25f8c8667 100644 --- a/java/droidstubs_test.go +++ b/java/droidstubs_test.go @@ -122,7 +122,7 @@ func getAndroidJarPatternsForDroidstubs(t *testing.T, sdkType string) []string { "some-other-exported-dir", ], api_levels_annotations_enabled: true, - api_levels_sdk_type: "%s", + api_levels_sdk_type: "%s", } `, sdkType), map[string][]byte{ @@ -169,6 +169,21 @@ func TestModuleLibDroidstubs(t *testing.T) { }, patterns) } +func TestSystemServerDroidstubs(t *testing.T) { + patterns := getAndroidJarPatternsForDroidstubs(t, "system-server") + + android.AssertArrayString(t, "order of patterns", []string{ + "--android-jar-pattern somedir/%/system-server/android.jar", + "--android-jar-pattern someotherdir/%/system-server/android.jar", + "--android-jar-pattern somedir/%/module-lib/android.jar", + "--android-jar-pattern someotherdir/%/module-lib/android.jar", + "--android-jar-pattern somedir/%/system/android.jar", + "--android-jar-pattern someotherdir/%/system/android.jar", + "--android-jar-pattern somedir/%/public/android.jar", + "--android-jar-pattern someotherdir/%/public/android.jar", + }, patterns) +} + func TestDroidstubsSandbox(t *testing.T) { ctx, _ := testJavaWithFS(t, ` genrule { @@ -259,3 +274,33 @@ func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, m t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars) } } + +func TestDroidstubsWithSdkExtensions(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + droiddoc_exported_dir { + name: "sdk-dir", + path: "sdk", + } + + droidstubs { + name: "baz-stubs", + api_levels_annotations_dirs: ["sdk-dir"], + api_levels_annotations_enabled: true, + extensions_info_file: ":info-file", + } + + filegroup { + name: "info-file", + srcs: ["sdk/extensions/info.txt"], + } + `, + map[string][]byte{ + "sdk/extensions/1/public/some-mainline-module-stubs.jar": nil, + "sdk/extensions/info.txt": nil, + }) + m := ctx.ModuleForTests("baz-stubs", "android_common") + manifest := m.Output("metalava.sbox.textproto") + cmdline := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command) + android.AssertStringDoesContain(t, "sdk-extensions-root present", cmdline, "--sdk-extensions-root sdk/extensions") + android.AssertStringDoesContain(t, "sdk-extensions-info present", cmdline, "--sdk-extensions-info sdk/extensions/info.txt") +} diff --git a/java/fuzz.go b/java/fuzz.go index d0f369f2f..1d6b91346 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -15,6 +15,7 @@ package java import ( + "path/filepath" "sort" "strings" @@ -26,6 +27,11 @@ import ( "android/soong/fuzz" ) +const ( + hostString = "host" + targetString = "target" +) + type jniProperties struct { // list of jni libs Jni_libs []string @@ -39,8 +45,10 @@ func init() { } func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterModuleType("java_fuzz_host", FuzzFactory) - ctx.RegisterSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory) + ctx.RegisterModuleType("java_fuzz", JavaFuzzFactory) + ctx.RegisterModuleType("java_fuzz_host", JavaFuzzHostFactory) + ctx.RegisterSingletonType("java_fuzz_host_packaging", javaFuzzHostPackagingFactory) + ctx.RegisterSingletonType("java_fuzz_device_packaging", javaFuzzDevicePackagingFactory) } type JavaFuzzLibrary struct { @@ -55,11 +63,11 @@ type JavaFuzzLibrary struct { // sanitized for the given sanitizer or not. func (j *JavaFuzzLibrary) IsSanitizerEnabledForJni(ctx android.BaseModuleContext, sanitizerName string) bool { // TODO: once b/231370928 is resolved, please uncomment the loop - // for _, s := range j.jniProperties.Sanitizers { - // if sanitizerName == s { - // return true - // } - // } + // for _, s := range j.jniProperties.Sanitizers { + // if sanitizerName == s { + // return true + // } + // } return false } @@ -72,7 +80,6 @@ func (j *JavaFuzzLibrary) DepsMutator(mctx android.BottomUpMutatorContext) { // this will be used by the ingestion pipeline to determine the version // of jazzer to add to the fuzzer package j.fuzzPackagedModule.FuzzProperties.Fuzz_config.IsJni = proptools.BoolPtr(true) - for _, target := range mctx.MultiTargets() { sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) mctx.AddFarVariationDependencies(sharedLibVariations, cc.JniFuzzLibTag, j.jniProperties.Jni_libs...) @@ -91,17 +98,28 @@ func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) if j.fuzzPackagedModule.FuzzProperties.Dictionary != nil { j.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *j.fuzzPackagedModule.FuzzProperties.Dictionary) } - if j.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil { configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json") android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String()) j.fuzzPackagedModule.Config = configPath } - ctx.VisitDirectDepsWithTag(cc.JniFuzzLibTag, func(dep android.Module) { + _, sharedDeps := cc.CollectAllSharedDependencies(ctx) + + for _, dep := range sharedDeps { sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo) if sharedLibInfo.SharedLibrary != nil { - libPath := android.PathForModuleOut(ctx, sharedLibInfo.SharedLibrary.Base()) + // The .class jars are output in slightly different locations + // relative to the jni libs. Therefore, for consistency across + // host and device fuzzers of jni lib location, we save it in a + // native_libs directory. + var relPath string + if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" { + relPath = filepath.Join("lib64", sharedLibInfo.SharedLibrary.Base()) + } else { + relPath = filepath.Join("lib", sharedLibInfo.SharedLibrary.Base()) + } + libPath := android.PathForModuleOut(ctx, relPath) ctx.Build(pctx, android.BuildParams{ Rule: android.Cp, Input: sharedLibInfo.SharedLibrary, @@ -111,18 +129,17 @@ func (j *JavaFuzzLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) } else { ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) } - }) + } j.Library.GenerateAndroidBuildActions(ctx) } -// java_fuzz builds and links sources into a `.jar` file for the host. +// java_fuzz_host builds and links sources into a `.jar` file for the host. // // By default, a java_fuzz produces a `.jar` file containing `.class` files. // This jar is not suitable for installing on a device. -func FuzzFactory() android.Module { +func JavaFuzzHostFactory() android.Module { module := &JavaFuzzLibrary{} - module.addHostProperties() module.AddProperties(&module.jniProperties) module.Module.properties.Installable = proptools.BoolPtr(true) @@ -141,23 +158,54 @@ func FuzzFactory() android.Module { ctx.AppendProperties(&disableLinuxBionic) }) - module.initModuleAndImport(module) - android.InitSdkAwareModule(module) - InitJavaModuleMultiTargets(module, android.HostSupported) + InitJavaModuleMultiTargets(module, android.HostSupportedNoCross) return module } -// Responsible for generating rules that package fuzz targets into -// their architecture & target/host specific zip file. -type javaFuzzPackager struct { +// java_fuzz builds and links sources into a `.jar` file for the device. +// This generates .class files in a jar which can then be instrumented before +// fuzzing in Android Runtime (ART: Android OS on emulator or device) +func JavaFuzzFactory() android.Module { + module := &JavaFuzzLibrary{} + module.addHostAndDeviceProperties() + module.AddProperties(&module.jniProperties) + module.Module.properties.Installable = proptools.BoolPtr(true) + module.AddProperties(&module.fuzzPackagedModule.FuzzProperties) + module.Module.dexpreopter.isTest = true + module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + InitJavaModuleMultiTargets(module, android.DeviceSupported) + return module +} + +// Responsible for generating rules that package host fuzz targets into +// a zip file. +type javaFuzzHostPackager struct { + fuzz.FuzzPackager +} + +// Responsible for generating rules that package device fuzz targets into +// a zip file. +type javaFuzzDevicePackager struct { fuzz.FuzzPackager } -func javaFuzzPackagingFactory() android.Singleton { - return &javaFuzzPackager{} +func javaFuzzHostPackagingFactory() android.Singleton { + return &javaFuzzHostPackager{} } -func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { +func javaFuzzDevicePackagingFactory() android.Singleton { + return &javaFuzzDevicePackager{} +} + +func (s *javaFuzzHostPackager) GenerateBuildActions(ctx android.SingletonContext) { + generateBuildActions(&s.FuzzPackager, hostString, ctx) +} + +func (s *javaFuzzDevicePackager) GenerateBuildActions(ctx android.SingletonContext) { + generateBuildActions(&s.FuzzPackager, targetString, ctx) +} + +func generateBuildActions(s *fuzz.FuzzPackager, hostOrTargetString string, ctx android.SingletonContext) { // Map between each architecture + host/device combination. archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) @@ -171,8 +219,14 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { return } - if javaFuzzModule.Target().HostCross { - return + if hostOrTargetString == hostString { + if !javaFuzzModule.Host() { + return + } + } else if hostOrTargetString == targetString { + if javaFuzzModule.Host() || javaFuzzModule.Target().HostCross { + return + } } fuzzModuleValidator := fuzz.FuzzModule{ @@ -185,12 +239,7 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { return } - hostOrTargetString := "target" - if javaFuzzModule.Host() { - hostOrTargetString = "host" - } archString := javaFuzzModule.Arch().ArchType.String() - archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} @@ -201,7 +250,7 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder) // Add .jar - files = append(files, fuzz.FileToZip{javaFuzzModule.outputFile, ""}) + files = append(files, fuzz.FileToZip{javaFuzzModule.implementationJarFile, ""}) // Add jni .so files for _, fPath := range javaFuzzModule.jniFilePaths { @@ -217,12 +266,22 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { s.CreateFuzzPackage(ctx, archDirs, fuzz.Java, pctx) } -func (s *javaFuzzPackager) MakeVars(ctx android.MakeVarsContext) { +func (s *javaFuzzHostPackager) MakeVars(ctx android.MakeVarsContext) { + packages := s.Packages.Strings() + sort.Strings(packages) + + ctx.Strict("SOONG_JAVA_FUZZ_HOST_PACKAGING_ARCH_MODULES", strings.Join(packages, " ")) + + // Preallocate the slice of fuzz targets to minimize memory allocations. + s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_HOST_TARGETS") +} + +func (s *javaFuzzDevicePackager) MakeVars(ctx android.MakeVarsContext) { packages := s.Packages.Strings() sort.Strings(packages) - ctx.Strict("SOONG_JAVA_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " ")) + ctx.Strict("SOONG_JAVA_FUZZ_DEVICE_PACKAGING_ARCH_MODULES", strings.Join(packages, " ")) // Preallocate the slice of fuzz targets to minimize memory allocations. - s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_TARGETS") + s.PreallocateSlice(ctx, "ALL_JAVA_FUZZ_DEVICE_TARGETS") } diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 7b678037c..5474ae11e 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -594,6 +594,23 @@ func (i *HiddenAPIInfo) FlagSubset() SignatureCsvSubset { var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{}) +// HiddenAPIInfoForSdk contains information provided by the hidden API processing for use +// by the sdk snapshot. +// +// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API +// processing. +type HiddenAPIInfoForSdk struct { + // FlagFilesByCategory maps from the flag file category to the paths containing information for + // that category. + FlagFilesByCategory FlagFilesByCategory + + // The output from the hidden API processing needs to be made available to other modules. + HiddenAPIFlagOutput +} + +// Provides hidden API info for the sdk snapshot. +var HiddenAPIInfoForSdkProvider = blueprint.NewProvider(HiddenAPIInfoForSdk{}) + // ModuleStubDexJars contains the stub dex jars provided by a single module. // // It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See @@ -1024,8 +1041,11 @@ func (s SignatureCsvSubsets) RelativeToTop() []string { // patterns that will select a subset of the monolithic flags. func buildRuleSignaturePatternsFile( ctx android.ModuleContext, flagsPath android.Path, - splitPackages []string, packagePrefixes []string, singlePackages []string) android.Path { - patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv") + splitPackages []string, packagePrefixes []string, singlePackages []string, + suffix string) android.Path { + hiddenApiSubDir := "modular-hiddenapi" + suffix + + patternsFile := android.PathForModuleOut(ctx, hiddenApiSubDir, "signature-patterns.csv") // Create a rule to validate the output from the following rule. rule := android.NewRuleBuilder(pctx, ctx) @@ -1042,7 +1062,7 @@ func buildRuleSignaturePatternsFile( FlagForEachArg("--package-prefix ", packagePrefixes). FlagForEachArg("--single-package ", singlePackages). FlagWithOutput("--output ", patternsFile) - rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns") + rule.Build("hiddenAPISignaturePatterns"+suffix, "hidden API signature patterns"+suffix) return patternsFile } @@ -1116,8 +1136,8 @@ func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name strin return validFile } -// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the -// bootclasspath and then encode the flags into the boot dex files. +// hiddenAPIFlagRulesForBootclasspathFragment will generate all the flags for a fragment of the +// bootclasspath. // // It takes: // * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind. @@ -1130,31 +1150,27 @@ func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name strin // * metadata.csv // * index.csv // * all-flags.csv -// * encoded boot dex files -func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { - hiddenApiSubDir := "modular-hiddenapi" - - // Gather information about the boot dex files for the boot libraries provided by this fragment. - bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents) +func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput { + hiddenApiSubDir := "modular-hiddenapi" + suffix // Generate the stub-flags.csv. stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv") - buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil) + buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile"+suffix, "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil) // Extract the classes jars from the contents. classesJars := extractClassesJarsFromModules(contents) // Generate the set of flags from the annotations in the source code. annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv") - buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV) + buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags"+suffix, classesJars, stubFlagsCSV, annotationFlagsCSV) // Generate the metadata from the annotations in the source code. metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv") - buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV) + buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata"+suffix, classesJars, stubFlagsCSV, metadataCSV) // Generate the index file from the CSV files in the classes jars. indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv") - buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV) + buildRuleToGenerateIndex(ctx, "modular hiddenapi index"+suffix, classesJars, indexCSV) // Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files // containing dex signatures of all the removed APIs. In the monolithic files that is done by @@ -1162,59 +1178,60 @@ func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents // signatures, see the combined-removed-dex module. This does that automatically by using the // *removed.txt files retrieved from the java_sdk_library modules that are specified in the // stub_libs and contents properties of a bootclasspath_fragment. - removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles) + removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, suffix, input.RemovedTxtFiles) // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex // files. allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv") - buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures) - - // Encode the flags into the boot dex files. - encodedBootDexJarsByModule := map[string]android.Path{} - outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath - for _, name := range android.SortedStringKeys(bootDexInfoByModule) { - bootDexInfo := bootDexInfoByModule[name] - unencodedDex := bootDexInfo.path - encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir) - encodedBootDexJarsByModule[name] = encodedDex - } + buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags"+suffix, "modular hiddenapi all flags"+suffix, allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures) // Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be // compared against the monolithic stub flags. filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv") - buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags", - "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV, + buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags"+suffix, + "modular hiddenapi filtered stub flags"+suffix, stubFlagsCSV, filteredStubFlagsCSV, HIDDENAPI_STUB_FLAGS_IMPL_FLAGS) // Generate the filtered-flags.csv file which contains the filtered flags that will be compared // against the monolithic flags. filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv") - buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags", - "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV, + buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags"+suffix, + "modular hiddenapi filtered flags"+suffix, allFlagsCSV, filteredFlagsCSV, HIDDENAPI_FLAGS_CSV_IMPL_FLAGS) // Store the paths in the info for use by other modules and sdk snapshot generation. - output := HiddenAPIOutput{ - HiddenAPIFlagOutput: HiddenAPIFlagOutput{ - AnnotationFlagsPath: annotationFlagsCSV, - MetadataPath: metadataCSV, - IndexPath: indexCSV, - StubFlagsPath: stubFlagsCSV, - AllFlagsPath: allFlagsCSV, - FilteredStubFlagsPath: filteredStubFlagsCSV, - FilteredFlagsPath: filteredFlagsCSV, - }, - EncodedBootDexFilesByModule: encodedBootDexJarsByModule, + return HiddenAPIFlagOutput{ + AnnotationFlagsPath: annotationFlagsCSV, + MetadataPath: metadataCSV, + IndexPath: indexCSV, + StubFlagsPath: stubFlagsCSV, + AllFlagsPath: allFlagsCSV, + FilteredStubFlagsPath: filteredStubFlagsCSV, + FilteredFlagsPath: filteredFlagsCSV, + } +} + +// hiddenAPIEncodeRulesForBootclasspathFragment generates rules to encode hidden API flags into the +// dex jars in bootDexInfoByModule. +func hiddenAPIEncodeRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, allFlagsCSV android.Path) bootDexJarByModule { + // Encode the flags into the boot dex files. + encodedBootDexJarsByModule := bootDexJarByModule{} + outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath + for _, name := range android.SortedStringKeys(bootDexInfoByModule) { + bootDexInfo := bootDexInfoByModule[name] + unencodedDex := bootDexInfo.path + encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir) + encodedBootDexJarsByModule[name] = encodedDex } - return &output + return encodedBootDexJarsByModule } -func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath { +func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix string, removedTxtFiles android.Paths) android.OptionalPath { if len(removedTxtFiles) == 0 { return android.OptionalPath{} } - output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt") + output := android.PathForModuleOut(ctx, "module-hiddenapi"+suffix, "removed-dex-signatures.txt") rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). @@ -1222,7 +1239,7 @@ func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedT Flag("--no-banner"). Inputs(removedTxtFiles). FlagWithOutput("--dex-api ", output) - rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures") + rule.Build("modular-hiddenapi-removed-dex-signatures"+suffix, "modular hiddenapi removed dex signatures"+suffix) return android.OptionalPathForPath(output) } diff --git a/java/jacoco.go b/java/jacoco.go index e11c2ce69..f8012b852 100644 --- a/java/jacoco.go +++ b/java/jacoco.go @@ -47,6 +47,34 @@ var ( "strippedJar", "stripSpec", "tmpDir", "tmpJar") ) +func jacocoDepsMutator(ctx android.BottomUpMutatorContext) { + type instrumentable interface { + shouldInstrument(ctx android.BaseModuleContext) bool + shouldInstrumentInApex(ctx android.BaseModuleContext) bool + setInstrument(value bool) + } + + j, ok := ctx.Module().(instrumentable) + if !ctx.Module().Enabled() || !ok { + return + } + + if j.shouldInstrumentInApex(ctx) { + j.setInstrument(true) + } + + if j.shouldInstrument(ctx) && ctx.ModuleName() != "jacocoagent" { + // We can use AddFarVariationDependencies here because, since this dep + // is added as libs only (i.e. a compiletime CLASSPATH entry only), + // the first variant of jacocoagent is sufficient to prevent + // compile time errors. + // At this stage in the build, AddVariationDependencies is not always + // able to procure a variant of jacocoagent that matches the calling + // module. + ctx.AddFarVariationDependencies(ctx.Module().Target().Variations(), libTag, "jacocoagent") + } +} + // Instruments a jar using the Jacoco command line interface. Uses stripSpec to extract a subset // of the classes in inputJar into strippedJar, instruments strippedJar into tmpJar, and then // combines the classes in tmpJar with inputJar (preferring the instrumented classes in tmpJar) diff --git a/java/java.go b/java/java.go index 0251b5754..5091d26a2 100644 --- a/java/java.go +++ b/java/java.go @@ -66,6 +66,8 @@ func registerJavaBuildComponents(ctx android.RegistrationContext) { // to support the checks in dexpreoptDisabled(). ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel() + // needs access to ApexInfoProvider which is available after variant creation + ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel() }) ctx.RegisterSingletonType("logtags", LogtagsSingleton) @@ -346,6 +348,7 @@ var ( dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} staticLibTag = dependencyTag{name: "staticlib"} libTag = dependencyTag{name: "javalib", runtimeLinked: true} + sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true} java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} pluginTag = dependencyTag{name: "plugin", toolchain: true} errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true} @@ -372,7 +375,7 @@ var ( ) func IsLibDepTag(depTag blueprint.DependencyTag) bool { - return depTag == libTag + return depTag == libTag || depTag == sdkLibTag } func IsStaticLibDepTag(depTag blueprint.DependencyTag) bool { @@ -418,6 +421,7 @@ type jniLib struct { target android.Target coverageFile android.OptionalPath unstrippedFile android.Path + partition string } func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext, d dexer) { @@ -425,7 +429,7 @@ func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext, if sdkDep.useModule { ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) - ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) + ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...) if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...) } @@ -1652,7 +1656,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) switch tag { - case libTag: + case libTag, sdkLibTag: flags.classpath = append(flags.classpath, dep.HeaderJars...) flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...) case staticLibTag: @@ -1662,7 +1666,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } else if dep, ok := module.(SdkLibraryDependency); ok { switch tag { - case libTag: + case libTag, sdkLibTag: flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) } } @@ -2176,7 +2180,7 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, } depTag := ctx.OtherModuleDependencyTag(depModule) - if depTag == libTag { + if IsLibDepTag(depTag) { // Ok, propagate <uses-library> through non-static library dependencies. } else if tag, ok := depTag.(usesLibraryDependencyTag); ok && tag.sdkVersion == dexpreopt.AnySdkVersion { // Ok, propagate <uses-library> through non-compatibility <uses-library> dependencies. diff --git a/java/java_test.go b/java/java_test.go index 7f0cea718..d2373e349 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -588,8 +588,8 @@ func TestPrebuilts(t *testing.T) { sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output fooLibrary := fooModule.Module().(*Library) - assertDeepEquals(t, "foo java sources incorrect", - []string{"a.java"}, fooLibrary.compiledJavaSrcs.Strings()) + assertDeepEquals(t, "foo unique sources incorrect", + []string{"a.java"}, fooLibrary.uniqueSrcFiles.Strings()) assertDeepEquals(t, "foo java source jars incorrect", []string{".intermediates/stubs-source/android_common/stubs-source-stubs.srcjar"}, diff --git a/java/lint.go b/java/lint.go index 931820d74..fcd6d31ff 100644 --- a/java/lint.go +++ b/java/lint.go @@ -473,20 +473,23 @@ func (l *linter) lint(ctx android.ModuleContext) { cmd.FlagWithOutput("--write-reference-baseline ", baseline) - cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)") - - rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) - - // The HTML output contains a date, remove it to make the output deterministic. - rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html) + cmd.Text("; EXITCODE=$?; ") // The sources in the sandbox may have been modified by --apply-suggestions, zip them up and - // export them out of the sandbox. - rule.Command().BuiltTool("soong_zip"). + // export them out of the sandbox. Do this before exiting so that the suggestions exit even after + // a fatal error. + cmd.BuiltTool("soong_zip"). FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")). FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))). FlagWithInput("-r ", srcsList) + cmd.Text("; if [ $EXITCODE != 0 ]; then if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit $EXITCODE; fi") + + rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) + + // The HTML output contains a date, remove it to make the output deterministic. + rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html) + rule.Build("lint", "lint") l.outputs = lintOutputs{ diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt index 01e7e6e75..519a702ef 100644 --- a/java/lint_defaults.txt +++ b/java/lint_defaults.txt @@ -39,6 +39,7 @@ # Downgrade existing errors to warnings --warning_check AppCompatResource # 55 occurences in 10 modules --warning_check AppLinkUrlError # 111 occurences in 53 modules +--warning_check BinderGetCallingInMainThread --warning_check ByteOrderMark # 2 occurences in 2 modules --warning_check DuplicateActivity # 3 occurences in 3 modules --warning_check DuplicateDefinition # 3623 occurences in 48 modules @@ -91,6 +92,7 @@ --warning_check StringFormatInvalid # 148 occurences in 11 modules --warning_check StringFormatMatches # 4800 occurences in 30 modules --warning_check UnknownId # 8 occurences in 7 modules +--warning_check UnspecifiedImmutableFlag --warning_check ValidFragment # 12 occurences in 5 modules --warning_check ValidRestrictions # 5 occurences in 1 modules --warning_check WebViewLayout # 3 occurences in 1 modules diff --git a/java/lint_test.go b/java/lint_test.go index 456e6ba73..62450d573 100644 --- a/java/lint_test.go +++ b/java/lint_test.go @@ -271,7 +271,7 @@ func TestJavaLintDatabaseSelectionPublicFiltered(t *testing.T) { "a.java", ], min_sdk_version: "29", - sdk_version: "module_current", + sdk_version: "XXX", lint: { strict_updatability_linting: true, }, diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 24f8253ae..f0de7a4d8 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -436,10 +436,10 @@ func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android. profile := bootImageProfileRule(ctx, imageConfig) // Build boot image files for the android variants. - androidBootImageFilesByArch := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) + androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) // Zip the android variant boot image files up. - buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFilesByArch) + buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch) // Build boot image files for the host variants. There are use directly by ART host side tests. buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 944970783..c6acd55e5 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -255,12 +255,11 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { if p.properties.Extensions_dir != nil { extensionApiFiles := globExtensionDirs(mctx, p, "api/*.txt") for k, v := range getLatest(extensionApiFiles) { - if v.version > mctx.Config().PlatformBaseSdkExtensionVersion() { - if _, exists := latest[k]; !exists { - mctx.ModuleErrorf("Module %v finalized for extension %d but never during an API level; likely error", v.module, v.version) - } - latest[k] = v + if _, exists := latest[k]; !exists { + mctx.ModuleErrorf("Module %v finalized for extension %d but never during an API level; likely error", v.module, v.version) } + // The extension version is always at least as new as the last sdk int version (potentially identical) + latest[k] = v } } diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go index 75422ad45..2b8435325 100644 --- a/java/prebuilt_apis_test.go +++ b/java/prebuilt_apis_test.go @@ -61,7 +61,7 @@ func TestPrebuiltApis_SystemModulesCreation(t *testing.T) { } func TestPrebuiltApis_WithExtensions(t *testing.T) { - runTestWithBaseExtensionLevel := func(v int) (foo_input string, bar_input string) { + runTestWithBaseExtensionLevel := func(v int) (foo_input, bar_input, baz_input string) { result := android.GroupFixturePreparers( prepareForJavaTest, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -69,7 +69,7 @@ func TestPrebuiltApis_WithExtensions(t *testing.T) { }), FixtureWithPrebuiltApisAndExtensions(map[string][]string{ "31": {"foo"}, - "32": {"foo", "bar"}, + "32": {"foo", "bar", "baz"}, "current": {"foo", "bar"}, }, map[string][]string{ "1": {"foo"}, @@ -78,15 +78,24 @@ func TestPrebuiltApis_WithExtensions(t *testing.T) { ).RunTest(t) foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String() bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String() + baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String() return } - // Here, the base extension level is 1, so extension level 2 is the latest - foo_input, bar_input := runTestWithBaseExtensionLevel(1) - android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input) - android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input) + // Extension 2 is the latest for both foo and bar, finalized after the base extension version. + foo_input, bar_input, baz_input := runTestWithBaseExtensionLevel(1) + android.AssertStringEquals(t, "Expected latest foo = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input) + android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input) + android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input) - // Here, the base extension level is 2, so 2 is not later than 32. - foo_input, bar_input = runTestWithBaseExtensionLevel(2) - android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/foo.txt", foo_input) - android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/bar.txt", bar_input) + // Extension 2 is the latest for both foo and bar, finalized together with 32 + foo_input, bar_input, baz_input = runTestWithBaseExtensionLevel(2) + android.AssertStringEquals(t, "Expected latest foo = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input) + android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input) + android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input) + + // Extension 3 is the current extension, but it has not yet been finalized. + foo_input, bar_input, baz_input = runTestWithBaseExtensionLevel(3) + android.AssertStringEquals(t, "Expected latest foo = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input) + android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input) + android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input) } diff --git a/java/resourceshrinker.go b/java/resourceshrinker.go new file mode 100644 index 000000000..6d5960157 --- /dev/null +++ b/java/resourceshrinker.go @@ -0,0 +1,43 @@ +// Copyright 2022 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" + + "github.com/google/blueprint" +) + +var shrinkResources = pctx.AndroidStaticRule("shrinkResources", + blueprint.RuleParams{ + Command: `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources`, + CommandDeps: []string{"${config.ResourceShrinkerCmd}"}, + }, "raw_resources") + +func ShrinkResources(ctx android.ModuleContext, apk android.Path, outputFile android.WritablePath) { + protoFile := android.PathForModuleOut(ctx, apk.Base()+".proto.apk") + aapt2Convert(ctx, protoFile, apk, "proto") + strictModeFile := android.PathForSource(ctx, "prebuilts/cmdline-tools/shrinker.xml") + protoOut := android.PathForModuleOut(ctx, apk.Base()+".proto.out.apk") + ctx.Build(pctx, android.BuildParams{ + Rule: shrinkResources, + Input: protoFile, + Output: protoOut, + Args: map[string]string{ + "raw_resources": strictModeFile.String(), + }, + }) + aapt2Convert(ctx, outputFile, protoOut, "binary") +} diff --git a/java/robolectric.go b/java/robolectric.go index 71ffdb175..b6116ec9d 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -23,6 +23,7 @@ import ( "android/soong/android" "android/soong/java/config" "android/soong/tradefed" + "github.com/google/blueprint/proptools" ) @@ -166,7 +167,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) instrumentedApp.implementationAndResourcesJar, } - for _, dep := range ctx.GetDirectDepsWithTag(libTag) { + handleLibDeps := func(dep android.Module) { m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) r.libs = append(r.libs, ctx.OtherModuleName(dep)) if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) { @@ -174,15 +175,22 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } } + for _, dep := range ctx.GetDirectDepsWithTag(libTag) { + handleLibDeps(dep) + } + for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) { + handleLibDeps(dep) + } + r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base()) TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{}, false, nil, nil) // TODO: this could all be removed if tradefed was used as the test runner, it will find everything // annotated as a test and run it. - for _, src := range r.compiledJavaSrcs { + for _, src := range r.uniqueSrcFiles { s := src.Rel() - if !strings.HasSuffix(s, "Test.java") { + if !strings.HasSuffix(s, "Test.java") && !strings.HasSuffix(s, "Test.kt") { continue } else if strings.HasSuffix(s, "/BaseRobolectricTest.java") { continue diff --git a/java/rro.go b/java/rro.go index c12e748c6..9d0667cf0 100644 --- a/java/rro.go +++ b/java/rro.go @@ -142,11 +142,15 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC aaptLinkFlags = append(aaptLinkFlags, "--rename-overlay-target-package "+*r.overridableProperties.Target_package_name) } - r.aapt.buildActions(ctx, r, nil, nil, aaptLinkFlags...) + if r.overridableProperties.Category != nil { + aaptLinkFlags = append(aaptLinkFlags, + "--rename-overlay-category "+*r.overridableProperties.Category) + } + r.aapt.buildActions(ctx, r, nil, nil, false, aaptLinkFlags...) // Sign the built package _, _, certificates := collectAppDeps(ctx, r, false, false) - certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx) + r.certificate, certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx) signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk") var lineageFile android.Path if lineage := String(r.properties.Lineage); lineage != "" { @@ -156,7 +160,6 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion) SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion) - r.certificate = certificates[0] r.outputFile = signed partition := rroPartition(ctx) @@ -221,6 +224,9 @@ type OverridableRuntimeResourceOverlayProperties struct { // the target package name of this overlay app. The target package name in the manifest file is used if one was not given. Target_package_name *string + + // the rro category of this overlay. The category in the manifest file is used if one was not given. + Category *string } type OverrideRuntimeResourceOverlay struct { diff --git a/java/rro_test.go b/java/rro_test.go index 00ba5ba11..8067a4703 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -201,6 +201,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { base: "foo_overlay", package_name: "com.android.bar.overlay", target_package_name: "com.android.bar", + category: "mycategory", } `) @@ -212,6 +213,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { targetVariant string packageFlag string targetPackageFlag string + categoryFlag string }{ { variantName: "android_common", @@ -228,6 +230,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { targetVariant: "android_common_bar", packageFlag: "com.android.bar.overlay", targetPackageFlag: "com.android.bar", + categoryFlag: "mycategory", }, } for _, expected := range expectedVariants { @@ -249,6 +252,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "") checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-category", expected.categoryFlag) } } diff --git a/java/sdk_library.go b/java/sdk_library.go index 8f499b101..fad1df77c 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -65,8 +65,27 @@ type apiScope struct { name string // The api scope that this scope extends. + // + // This organizes the scopes into an extension hierarchy. + // + // If set this means that the API provided by this scope includes the API provided by the scope + // set in this field. extends *apiScope + // The next api scope that a library that uses this scope can access. + // + // This organizes the scopes into an access hierarchy. + // + // If set this means that a library that can access this API can also access the API provided by + // the scope set in this field. + // + // A module that sets sdk_version: "<scope>_current" should have access to the <scope> API of + // every java_sdk_library that it depends on. If the library does not provide an API for <scope> + // then it will traverse up this access hierarchy to find an API that it does provide. + // + // If this is not set then it defaults to the scope set in extends. + canAccess *apiScope + // The legacy enabled status for a specific scope can be dependent on other // properties that have been specified on the library so it is provided by // a function that can determine the status by examining those properties. @@ -107,7 +126,7 @@ type apiScope struct { // The scope specific prefix to add to the api file base of "current.txt" or "removed.txt". apiFilePrefix string - // The scope specific prefix to add to the sdk library module name to construct a scope specific + // The scope specific suffix to add to the sdk library module name to construct a scope specific // module name. moduleSuffix string @@ -193,6 +212,11 @@ func initApiScope(scope *apiScope) *apiScope { } } + // By default, a library that can access a scope can also access the scope it extends. + if scope.canAccess == nil { + scope.canAccess = scope.extends + } + // Escape any special characters in the arguments. This is needed because droidstubs // passes these directly to the shell command. scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs) @@ -310,6 +334,14 @@ var ( apiScopeSystemServer = initApiScope(&apiScope{ name: "system-server", extends: apiScopePublic, + + // The system-server scope can access the module-lib scope. + // + // A module that provides a system-server API is appended to the standard bootclasspath that is + // used by the system server. So, it should be able to access module-lib APIs provided by + // libraries on the bootclasspath. + canAccess: apiScopeModuleLib, + // The system-server scope is disabled by default in legacy mode. // // Enabling this would break existing usages. @@ -539,7 +571,7 @@ type sdkLibraryProperties struct { } // TODO: determines whether to create HTML doc or not - //Html_doc *bool + // Html_doc *bool } // Paths to outputs from java_sdk_library and java_sdk_library_import. @@ -926,7 +958,7 @@ func (c *commonToSdkLibraryAndImport) findScopePaths(scope *apiScope) *scopePath // If this does not support the requested api scope then find the closest available // scope it does support. Returns nil if no such scope is available. func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *scopePaths { - for s := scope; s != nil; s = s.extends { + for s := scope; s != nil; s = s.canAccess { if paths := c.findScopePaths(s); paths != nil { return paths } @@ -1354,7 +1386,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Provide additional information for inclusion in an sdk's generated .info file. additionalSdkInfo := map[string]interface{}{} additionalSdkInfo["dist_stem"] = module.distStem() - baseModuleName := module.BaseModuleName() + baseModuleName := module.distStem() scopes := map[string]interface{}{} additionalSdkInfo["scopes"] = scopes for scope, scopePaths := range module.scopePaths { @@ -2236,8 +2268,9 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl Sdk_version *string Libs []string Jars []string - Prefer *bool Compile_dex *bool + + android.UserSuppliedPrebuiltProperties }{} props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) props.Sdk_version = scopeProperties.Sdk_version @@ -2247,7 +2280,7 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl props.Jars = scopeProperties.Jars // The imports are preferred if the java_sdk_library_import is preferred. - props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) + props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) // The imports need to be compiled to dex if the java_sdk_library_import requests it. compileDex := module.properties.Compile_dex @@ -2261,16 +2294,18 @@ func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.Defaultabl func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { props := struct { - Name *string - Srcs []string - Prefer *bool + Name *string + Srcs []string + + android.UserSuppliedPrebuiltProperties }{} props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope)) props.Srcs = scopeProperties.Stub_srcs - mctx.CreateModule(PrebuiltStubsSourcesFactory, &props) // The stubs source is preferred if the java_sdk_library_import is preferred. - props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer()) + props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) + + mctx.CreateModule(PrebuiltStubsSourcesFactory, &props) } // Add the dependencies on the child module in the component deps mutator so that it @@ -2904,6 +2939,18 @@ var javaSdkLibrarySdkMemberType = &sdkLibrarySdkMemberType{ type sdkLibrarySdkMemberProperties struct { android.SdkMemberPropertiesBase + // Stem name for files in the sdk snapshot. + // + // This is used to construct the path names of various sdk library files in the sdk snapshot to + // make sure that they match the finalized versions of those files in prebuilts/sdk. + // + // This property is marked as keep so that it will be kept in all instances of this struct, will + // not be cleared but will be copied to common structs. That is needed because this field is used + // to construct many file names for other parts of this struct and so it needs to be present in + // all structs. If it was not marked as keep then it would be cleared in some structs and so would + // be unavailable for generating file names if there were other properties that were still set. + Stem string `sdk:"keep"` + // Scope to per scope properties. Scopes map[*apiScope]*scopeProperties @@ -2965,6 +3012,9 @@ type scopeProperties struct { func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { sdk := variant.(*SdkLibrary) + // Copy the stem name for files in the sdk snapshot. + s.Stem = sdk.distStem() + s.Scopes = make(map[*apiScope]*scopeProperties) for _, apiScope := range allApiScopes { paths := sdk.findScopePaths(apiScope) @@ -3017,6 +3067,8 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo propertySet.AddProperty("permitted_packages", s.Permitted_packages) } + stem := s.Stem + for _, apiScope := range allApiScopes { if properties, ok := s.Scopes[apiScope]; ok { scopeSet := propertySet.AddPropertySet(apiScope.propertyName) @@ -3025,7 +3077,7 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo var jars []string for _, p := range properties.Jars { - dest := filepath.Join(scopeDir, ctx.Name()+"-stubs.jar") + dest := filepath.Join(scopeDir, stem+"-stubs.jar") ctx.SnapshotBuilder().CopyToSnapshot(p, dest) jars = append(jars, dest) } @@ -3033,31 +3085,31 @@ func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberCo if ctx.SdkModuleContext().Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_USE_SRCJAR") { // Copy the stubs source jar into the snapshot zip as is. - srcJarSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".srcjar") + srcJarSnapshotPath := filepath.Join(scopeDir, stem+".srcjar") ctx.SnapshotBuilder().CopyToSnapshot(properties.StubsSrcJar, srcJarSnapshotPath) scopeSet.AddProperty("stub_srcs", []string{srcJarSnapshotPath}) } else { // Merge the stubs source jar into the snapshot zip so that when it is unpacked // the source files are also unpacked. - snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources") + snapshotRelativeDir := filepath.Join(scopeDir, stem+"_stub_sources") ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir) scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir}) } if properties.CurrentApiFile != nil { - currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(ctx.Name()) + currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(stem) ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath) scopeSet.AddProperty("current_api", currentApiSnapshotPath) } if properties.RemovedApiFile != nil { - removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(ctx.Name()) + removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(stem) ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath) scopeSet.AddProperty("removed_api", removedApiSnapshotPath) } if properties.AnnotationsZip != nil { - annotationsSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"_annotations.zip") + annotationsSnapshotPath := filepath.Join(scopeDir, stem+"_annotations.zip") ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath) scopeSet.AddProperty("annotations", annotationsSnapshotPath) } diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 805bc226f..096bca8a1 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -18,6 +18,7 @@ import ( "fmt" "path/filepath" "regexp" + "strings" "testing" "android/soong/android" @@ -699,6 +700,80 @@ func TestJavaSdkLibrary_SystemServer(t *testing.T) { `) } +func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo-public", "foo-system", "foo-module-lib", "foo-system-server"), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo-public", + srcs: ["a.java"], + api_packages: ["foo"], + public: { + enabled: true, + }, + } + + java_sdk_library { + name: "foo-system", + srcs: ["a.java"], + api_packages: ["foo"], + system: { + enabled: true, + }, + } + + java_sdk_library { + name: "foo-module-lib", + srcs: ["a.java"], + api_packages: ["foo"], + system: { + enabled: true, + }, + module_lib: { + enabled: true, + }, + } + + java_sdk_library { + name: "foo-system-server", + srcs: ["a.java"], + api_packages: ["foo"], + system_server: { + enabled: true, + }, + } + + java_library { + name: "bar", + srcs: ["a.java"], + libs: ["foo-public", "foo-system", "foo-module-lib", "foo-system-server"], + sdk_version: "system_server_current", + } + `) + + stubsPath := func(name string, scope *apiScope) string { + name = scope.stubsLibraryModuleName(name) + return fmt.Sprintf("out/soong/.intermediates/%[1]s/android_common/turbine-combined/%[1]s.jar", name) + } + + // The bar library should depend on the highest (where system server is highest and public is + // lowest) API scopes provided by each of the foo-* modules. The highest API scope provided by the + // foo-<x> module is <x>. + barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac") + stubLibraries := []string{ + stubsPath("foo-public", apiScopePublic), + stubsPath("foo-system", apiScopeSystem), + stubsPath("foo-module-lib", apiScopeModuleLib), + stubsPath("foo-system-server", apiScopeSystemServer), + } + expectedPattern := fmt.Sprintf(`^-classpath .*:\Q%s\E$`, strings.Join(stubLibraries, ":")) + if expected, actual := expectedPattern, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + t.Errorf("expected pattern %q to match %#q", expected, actual) + } +} + func TestJavaSdkLibrary_MissingScope(t *testing.T) { prepareForJavaTest. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)). @@ -875,11 +950,12 @@ func TestJavaSdkLibraryImport_WithSource(t *testing.T) { }) } -func TestJavaSdkLibraryImport_Preferred(t *testing.T) { +func testJavaSdkLibraryImport_Preferred(t *testing.T, prefer string, preparer android.FixturePreparer) { result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("sdklib"), + preparer, ).RunTestWithBp(t, ` java_sdk_library { name: "sdklib", @@ -893,11 +969,37 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) { java_sdk_library_import { name: "sdklib", - prefer: true, + `+prefer+` public: { jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", }, } + + java_library { + name: "combined", + static_libs: [ + "sdklib.stubs", + ], + java_resources: [ + ":sdklib.stubs.source", + ":sdklib{.public.api.txt}", + ":sdklib{.public.removed-api.txt}", + ":sdklib{.public.annotations.zip}", + ], + sdk_version: "none", + system_modules: "none", + } + + java_library { + name: "public", + srcs: ["a.java"], + libs: ["sdklib"], + sdk_version: "current", + } `) CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{ @@ -913,9 +1015,48 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) { CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{ `dex2oatd`, `prebuilt_sdklib.stubs`, + `prebuilt_sdklib.stubs.source`, `sdklib.impl`, `sdklib.xml`, }) + + // Make sure that dependencies on child modules use the prebuilt when preferred. + CheckModuleDependencies(t, result.TestContext, "combined", "android_common", []string{ + // Each use of :sdklib{...} adds a dependency onto prebuilt_sdklib. + `prebuilt_sdklib`, + `prebuilt_sdklib`, + `prebuilt_sdklib`, + `prebuilt_sdklib.stubs`, + `prebuilt_sdklib.stubs.source`, + }) + + // Make sure that dependencies on sdklib that resolve to one of the child libraries use the + // prebuilt library. + public := result.ModuleForTests("public", "android_common") + rule := public.Output("javac/public.jar") + inputs := rule.Implicits.Strings() + expected := "out/soong/.intermediates/prebuilt_sdklib.stubs/android_common/combined/sdklib.stubs.jar" + if !android.InList(expected, inputs) { + t.Errorf("expected %q to contain %q", inputs, expected) + } +} + +func TestJavaSdkLibraryImport_Preferred(t *testing.T) { + t.Run("prefer", func(t *testing.T) { + testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer) + }) + + t.Run("use_source_config_var", func(t *testing.T) { + testJavaSdkLibraryImport_Preferred(t, + "use_source_config_var: {config_namespace: \"acme\", var_name: \"use_source\"},", + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.VendorVars = map[string]map[string]string{ + "acme": { + "use_source": "false", + }, + } + })) + }) } func TestJavaSdkLibraryEnforce(t *testing.T) { diff --git a/java/testing.go b/java/testing.go index 511cc5ddb..49430ee05 100644 --- a/java/testing.go +++ b/java/testing.go @@ -59,11 +59,9 @@ var PrepareForTestWithJavaBuildComponents = android.GroupFixturePreparers( }.AddToFixture(), ) -// Test fixture preparer that will define all default java modules except the -// fake_tool_binary for dex2oatd. -var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixturePreparers( - // Make sure that all the module types used in the defaults are registered. - PrepareForTestWithJavaBuildComponents, +var prepareForTestWithFrameworkDeps = android.GroupFixturePreparers( + // The java default module definitions. + android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()), // Additional files needed when test disallows non-existent source. android.MockFS{ // Needed for framework-res @@ -77,8 +75,14 @@ var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixtu "build/make/core/proguard.flags": nil, "build/make/core/proguard_basic_keeps.flags": nil, }.AddToFixture(), - // The java default module definitions. - android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()), +) + +// Test fixture preparer that will define all default java modules except the +// fake_tool_binary for dex2oatd. +var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixturePreparers( + // Make sure that all the module types used in the defaults are registered. + PrepareForTestWithJavaBuildComponents, + prepareForTestWithFrameworkDeps, // Add dexpreopt compat libs (android.test.base, etc.) and a fake dex2oatd module. dexpreopt.PrepareForTestWithDexpreoptCompatLibs, ) @@ -141,6 +145,30 @@ var PrepareForTestWithPrebuiltsOfCurrentApi = FixtureWithPrebuiltApis(map[string "30": {}, }) +var prepareForTestWithFrameworkJacocoInstrumentation = android.GroupFixturePreparers( + android.FixtureMergeEnv(map[string]string{ + "EMMA_INSTRUMENT_FRAMEWORK": "true", + }), + PrepareForTestWithJacocoInstrumentation, +) + +// PrepareForTestWithJacocoInstrumentation creates a mock jacocoagent library that can be +// depended on as part of the build process for instrumented Java modules. +var PrepareForTestWithJacocoInstrumentation = android.GroupFixturePreparers( + android.FixtureMergeEnv(map[string]string{ + "EMMA_INSTRUMENT": "true", + }), + android.FixtureAddFile("jacocoagent/Test.java", nil), + android.FixtureAddFile("jacocoagent/Android.bp", []byte(` + java_library { + name: "jacocoagent", + host_supported: true, + srcs: ["Test.java"], + sdk_version: "current", + } + `)), +) + // FixtureWithPrebuiltApis creates a preparer that will define prebuilt api modules for the // specified releases and modules. // @@ -365,6 +393,7 @@ func gatherRequiredDepsForTest() string { aidl: { export_include_dirs: ["framework/aidl"], }, + compile_dex: true, } android_app { |