diff options
| author | George Zacharia <george.zcharia@gmail.com> | 2024-06-30 21:31:39 +0530 |
|---|---|---|
| committer | George Zacharia <george.zcharia@gmail.com> | 2024-06-30 21:31:39 +0530 |
| commit | 5cf52b53bd3c1ffdf1f0b505b08cd9765ad1cc0d (patch) | |
| tree | 612a855b839f086862ec76805da2547c94eef94c /apex | |
| parent | e867a64ffb8fc36f0e39c3a4fe5b98104bffda2f (diff) | |
| parent | 8bf89894cce3b5387e548a325febf7029828875c (diff) | |
Merge tag 'android-14.0.0_r50' of https://android.googlesource.com/platform/build/soong into u14.0
Android 14.0.0 Release 50 (AP2A.240605.024)
Diffstat (limited to 'apex')
| -rw-r--r-- | apex/androidmk.go | 9 | ||||
| -rw-r--r-- | apex/apex.go | 226 | ||||
| -rw-r--r-- | apex/apex_singleton.go | 2 | ||||
| -rw-r--r-- | apex/apex_test.go | 1072 | ||||
| -rw-r--r-- | apex/bootclasspath_fragment_test.go | 52 | ||||
| -rw-r--r-- | apex/builder.go | 52 | ||||
| -rw-r--r-- | apex/classpath_element_test.go | 16 | ||||
| -rw-r--r-- | apex/deapexer.go | 10 | ||||
| -rw-r--r-- | apex/dexpreopt_bootjars_test.go | 163 | ||||
| -rw-r--r-- | apex/platform_bootclasspath_test.go | 42 | ||||
| -rw-r--r-- | apex/prebuilt.go | 179 | ||||
| -rw-r--r-- | apex/systemserver_classpath_fragment_test.go | 30 | ||||
| -rw-r--r-- | apex/vndk.go | 44 | ||||
| -rw-r--r-- | apex/vndk_test.go | 60 |
14 files changed, 1374 insertions, 583 deletions
diff --git a/apex/androidmk.go b/apex/androidmk.go index bc68ad36b..619be8dc4 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -124,6 +124,10 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st pathForSymbol := filepath.Join("$(PRODUCT_OUT)", "apex", apexBundleName, fi.installDir) modulePath := pathForSymbol fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath) + // AconfigUpdateAndroidMkData may have added elements to Extra. Process them here. + for _, extra := range apexAndroidMkData.Extra { + extra(w, fi.builtFile) + } // For non-flattend APEXes, the merged notice file is attached to the APEX itself. // We don't need to have notice file for the individual modules in it. Otherwise, @@ -229,6 +233,7 @@ func (a *apexBundle) writeRequiredModules(w io.Writer, moduleNames []string) { func (a *apexBundle) androidMkForType() android.AndroidMkData { return android.AndroidMkData{ + // While we do not provide a value for `Extra`, AconfigUpdateAndroidMkData may add some, which we must honor. Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { moduleNames := []string{} if a.installable() { @@ -269,6 +274,10 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { android.AndroidMkEmitAssignList(w, "LOCAL_OVERRIDES_MODULES", a.overridableProperties.Overrides) a.writeRequiredModules(w, moduleNames) + // AconfigUpdateAndroidMkData may have added elements to Extra. Process them here. + for _, extra := range data.Extra { + extra(w, a.outputFile) + } fmt.Fprintln(w, "include $(BUILD_PREBUILT)") fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String()) diff --git a/apex/apex.go b/apex/apex.go index 1be41c0f2..993c0f319 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -18,13 +18,11 @@ package apex import ( "fmt" - "log" "path/filepath" "regexp" "sort" "strings" - "android/soong/aconfig" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -236,6 +234,9 @@ type ApexNativeDependencies struct { // List of filesystem images that are embedded inside this APEX bundle. Filesystems []string + // List of prebuilt_etcs that are embedded inside this APEX bundle. + Prebuilts []string + // List of native libraries to exclude from this APEX. Exclude_native_shared_libs []string @@ -253,6 +254,9 @@ type ApexNativeDependencies struct { // List of filesystem images to exclude from this APEX bundle. Exclude_filesystems []string + + // List of prebuilt_etcs to exclude from this APEX bundle. + Exclude_prebuilts []string } // Merge combines another ApexNativeDependencies into this one @@ -263,6 +267,7 @@ func (a *ApexNativeDependencies) Merge(b ApexNativeDependencies) { a.Binaries = append(a.Binaries, b.Binaries...) a.Tests = append(a.Tests, b.Tests...) a.Filesystems = append(a.Filesystems, b.Filesystems...) + a.Prebuilts = append(a.Prebuilts, b.Prebuilts...) a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...) a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...) @@ -270,6 +275,7 @@ func (a *ApexNativeDependencies) Merge(b ApexNativeDependencies) { a.Exclude_binaries = append(a.Exclude_binaries, b.Exclude_binaries...) a.Exclude_tests = append(a.Exclude_tests, b.Exclude_tests...) a.Exclude_filesystems = append(a.Exclude_filesystems, b.Exclude_filesystems...) + a.Exclude_prebuilts = append(a.Exclude_prebuilts, b.Exclude_prebuilts...) } type apexMultilibProperties struct { @@ -481,6 +487,9 @@ type apexBundle struct { javaApisUsedByModuleFile android.ModuleOutPath aconfigFiles []android.Path + + // Single aconfig "cache file" merged from this module and all dependencies. + mergedAconfigFiles map[string]android.Paths } // apexFileClass represents a type of file that can be included in APEX. @@ -712,6 +721,8 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeM android.RemoveListFromList(nativeModules.Rust_dyn_libs, nativeModules.Exclude_rust_dyn_libs)...) ctx.AddFarVariationDependencies(target.Variations(), fsTag, android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...) + ctx.AddFarVariationDependencies(target.Variations(), prebuiltTag, + android.RemoveListFromList(nativeModules.Prebuilts, nativeModules.Exclude_prebuilts)...) } func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) { @@ -720,7 +731,7 @@ func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) { // getImageVariationPair returns a pair for the image variation name as its // prefix and suffix. The prefix indicates whether it's core/vendor/product and the -// suffix indicates the vndk version when it's vendor or product. +// suffix indicates the vndk version for vendor/product if vndk is enabled. // getImageVariation can simply join the result of this function to get the // image variation name. func (a *apexBundle) getImageVariationPair(deviceConfig android.DeviceConfig) (string, string) { @@ -728,8 +739,8 @@ func (a *apexBundle) getImageVariationPair(deviceConfig android.DeviceConfig) (s return cc.VendorVariationPrefix, a.vndkVersion(deviceConfig) } - var prefix string - var vndkVersion string + prefix := android.CoreVariation + vndkVersion := "" if deviceConfig.VndkVersion() != "" { if a.SocSpecific() || a.DeviceSpecific() { prefix = cc.VendorVariationPrefix @@ -738,15 +749,18 @@ func (a *apexBundle) getImageVariationPair(deviceConfig android.DeviceConfig) (s prefix = cc.ProductVariationPrefix vndkVersion = deviceConfig.PlatformVndkVersion() } + } else { + if a.SocSpecific() || a.DeviceSpecific() { + prefix = cc.VendorVariation + } else if a.ProductSpecific() { + prefix = cc.ProductVariation + } } if vndkVersion == "current" { vndkVersion = deviceConfig.PlatformVndkVersion() } - if vndkVersion != "" { - return prefix, vndkVersion - } - return android.CoreVariation, "" // The usual case + return prefix, vndkVersion } // getImageVariation returns the image variant name for this apexBundle. In most cases, it's simply @@ -827,10 +841,12 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { } addDependenciesForNativeModules(ctx, deps, target, imageVariation) - ctx.AddFarVariationDependencies([]blueprint.Variation{ - {Mutator: "os", Variation: target.OsVariation()}, - {Mutator: "arch", Variation: target.ArchVariation()}, - }, shBinaryTag, a.properties.Sh_binaries...) + if isPrimaryAbi { + ctx.AddFarVariationDependencies([]blueprint.Variation{ + {Mutator: "os", Variation: target.OsVariation()}, + {Mutator: "arch", Variation: target.ArchVariation()}, + }, shBinaryTag, a.properties.Sh_binaries...) + } } // Common-arch dependencies come next @@ -912,13 +928,7 @@ type DCLAInfo struct { ProvidedLibs []string } -var DCLAInfoProvider = blueprint.NewMutatorProvider(DCLAInfo{}, "apex_info") - -type ApexBundleInfo struct { - Contents *android.ApexContents -} - -var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_info") +var DCLAInfoProvider = blueprint.NewMutatorProvider[DCLAInfo]("apex_info") var _ ApexInfoMutator = (*apexBundle)(nil) @@ -993,10 +1003,8 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { } } - //TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated. if useVndk && mctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" { - log.Print("Libbinder is linked from Vendor APEX ", a.Name(), " with module ", parent.Name()) - return false + mctx.ModuleErrorf("Module %s in the vendor APEX %s should not use libbinder. Use libbinder_ndk instead.", parent.Name(), a.Name()) } // By default, all the transitive dependencies are collected, unless filtered out @@ -1020,7 +1028,7 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { // The membership information is saved for later access apexContents := android.NewApexContents(contents) - mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{ + android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{ Contents: apexContents, }) @@ -1058,7 +1066,7 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { }) if a.dynamic_common_lib_apex() { - mctx.SetProvider(DCLAInfoProvider, DCLAInfo{ + android.SetProvider(mctx, DCLAInfoProvider, DCLAInfo{ ProvidedLibs: a.properties.Native_shared_libs, }) } @@ -1137,15 +1145,43 @@ func enforceAppUpdatability(mctx android.TopDownMutatorContext) { // Skip these mainline modules for now var ( skipStrictUpdatabilityLintAllowlist = []string{ + // go/keep-sorted start + "PackageManagerTestApex", + "com.android.adservices", + "com.android.appsearch", "com.android.art", "com.android.art.debug", + "com.android.btservices", + "com.android.cellbroadcast", + "com.android.configinfrastructure", "com.android.conscrypt", + "com.android.extservices", + "com.android.extservices_tplus", + "com.android.healthfitness", + "com.android.ipsec", "com.android.media", - // test apexes + "com.android.mediaprovider", + "com.android.ondevicepersonalization", + "com.android.os.statsd", + "com.android.permission", + "com.android.profiling", + "com.android.rkpd", + "com.android.scheduling", + "com.android.tethering", + "com.android.uwb", + "com.android.wifi", "test_com.android.art", + "test_com.android.cellbroadcast", "test_com.android.conscrypt", + "test_com.android.extservices", + "test_com.android.ipsec", "test_com.android.media", + "test_com.android.mediaprovider", + "test_com.android.os.statsd", + "test_com.android.permission", + "test_com.android.wifi", "test_jitzygote_com.android.art", + // go/keep-sorted end } // TODO: b/215736885 Remove this list @@ -1201,10 +1237,10 @@ func apexTestForMutator(mctx android.BottomUpMutatorContext) { if _, ok := mctx.Module().(android.ApexModule); ok { var contents []*android.ApexContents for _, testFor := range mctx.GetDirectDepsWithTag(testForTag) { - abInfo := mctx.OtherModuleProvider(testFor, ApexBundleInfoProvider).(ApexBundleInfo) + abInfo, _ := android.OtherModuleProvider(mctx, testFor, android.ApexBundleInfoProvider) contents = append(contents, abInfo.Contents) } - mctx.SetProvider(android.ApexTestForInfoProvider, android.ApexTestForInfo{ + android.SetProvider(mctx, android.ApexTestForInfoProvider, android.ApexTestForInfo{ ApexContents: contents, }) } @@ -1376,7 +1412,7 @@ func (a *apexBundle) TaggedOutputs() map[string]android.Paths { var _ cc.Coverage = (*apexBundle)(nil) // Implements cc.Coverage -func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool { +func (a *apexBundle) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool { return ctx.DeviceConfig().NativeCoverageEnabled() } @@ -1465,7 +1501,7 @@ func (a *apexBundle) libs_to_trim(ctx android.ModuleContext) []string { panic(fmt.Errorf("expected exactly at most one dcla dependency, got %d", len(dclaModules))) } if len(dclaModules) > 0 { - DCLAInfo := ctx.OtherModuleProvider(dclaModules[0], DCLAInfoProvider).(DCLAInfo) + DCLAInfo, _ := android.OtherModuleProvider(ctx, dclaModules[0], DCLAInfoProvider) return DCLAInfo.ProvidedLibs } return []string{} @@ -1625,7 +1661,7 @@ func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.Platform type javaModule interface { android.Module BaseModuleName() string - DexJarBuildPath() java.OptionalDexJarPath + DexJarBuildPath(ctx android.ModuleErrorfContext) java.OptionalDexJarPath JacocoReportClassesFile() android.Path LintDepSets() java.LintDepSets Stem() string @@ -1639,7 +1675,7 @@ var _ javaModule = (*java.SdkLibraryImport)(nil) // apexFileForJavaModule creates an apexFile for a java module's dex implementation jar. func apexFileForJavaModule(ctx android.BaseModuleContext, module javaModule) apexFile { - return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath().PathOrNil()) + return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath(ctx).PathOrNil()) } // apexFileForJavaModuleWithFile creates an apexFile for a java module with the supplied file. @@ -1782,7 +1818,7 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.Paylo return false } - ai := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo) + ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider) externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants) // Visit actually @@ -2035,8 +2071,10 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, return true // track transitive dependencies case *java.AndroidAppImport: vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...) + addAconfigFiles(vctx, ctx, child) case *java.AndroidTestHelperApp: vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...) + addAconfigFiles(vctx, ctx, child) case *java.AndroidAppSet: appDir := "app" if ap.Privileged() { @@ -2050,6 +2088,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap) af.certificate = java.PresignedCertificate vctx.filesInfo = append(vctx.filesInfo, af) + addAconfigFiles(vctx, ctx, child) default: ctx.PropertyErrorf("apps", "%q is not an android_app module", depName) } @@ -2081,6 +2120,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, for _, etcFile := range filesToCopy { vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile)) } + addAconfigFiles(vctx, ctx, child) } else { ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName) } @@ -2104,6 +2144,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, af := apexFileForExecutable(ctx, ccTest) af.class = nativeTest vctx.filesInfo = append(vctx.filesInfo, af) + addAconfigFiles(vctx, ctx, child) } return true // track transitive dependencies } else { @@ -2145,14 +2186,10 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, return false } - //TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated. - if ch.UseVndk() && ctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" { - return false - } af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs) af.transitiveDep = true - abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo) + abInfo, _ := android.ModuleProvider(ctx, android.ApexBundleInfoProvider) if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) { // If the dependency is a stubs lib, don't include it in this APEX, // but make sure that the lib is installed on the device. @@ -2193,11 +2230,13 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, } vctx.filesInfo = append(vctx.filesInfo, af) + addAconfigFiles(vctx, ctx, child) return true // track transitive dependencies } else if rm, ok := child.(*rust.Module); ok { af := apexFileForRustLibrary(ctx, rm) af.transitiveDep = true vctx.filesInfo = append(vctx.filesInfo, af) + addAconfigFiles(vctx, ctx, child) return true // track transitive dependencies } } else if cc.IsTestPerSrcDepTag(depTag) { @@ -2229,6 +2268,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, af := apexFileForRustLibrary(ctx, rustm) af.transitiveDep = true vctx.filesInfo = append(vctx.filesInfo, af) + addAconfigFiles(vctx, ctx, child) return true // track transitive dependencies } } else if rust.IsRlibDepTag(depTag) { @@ -2247,6 +2287,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, return false } vctx.filesInfo = append(vctx.filesInfo, af) + addAconfigFiles(vctx, ctx, child) return true // track transitive dependencies default: ctx.PropertyErrorf("bootclasspath_fragments", @@ -2261,6 +2302,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil { vctx.filesInfo = append(vctx.filesInfo, *profileAf) } + addAconfigFiles(vctx, ctx, child) return true // track transitive dependencies default: ctx.PropertyErrorf("systemserverclasspath_fragments", @@ -2277,7 +2319,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, } func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) { - dep := ctx.OtherModuleProvider(module, aconfig.TransitiveDeclarationsInfoProvider).(aconfig.TransitiveDeclarationsInfo) + dep, _ := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider) if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil { vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...) } @@ -2359,6 +2401,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } } + android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles) //////////////////////////////////////////////////////////////////////////////////////////// // 3) some fields in apexBundle struct are configured @@ -2376,12 +2419,31 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.buildApex(ctx) a.buildApexDependencyInfo(ctx) a.buildLintReports(ctx) + + // Set a provider for dexpreopt of bootjars + a.provideApexExportsInfo(ctx) +} + +// Set a provider containing information about the jars and .prof provided by the apex +// Apexes built from source retrieve this information by visiting `bootclasspath_fragments` +// Used by dex_bootjars to generate the boot image +func (a *apexBundle) provideApexExportsInfo(ctx android.ModuleContext) { + ctx.VisitDirectDepsWithTag(bcpfTag, func(child android.Module) { + if info, ok := android.OtherModuleProvider(ctx, child, java.BootclasspathFragmentApexContentInfoProvider); ok { + exports := android.ApexExportsInfo{ + ApexName: a.ApexVariationName(), + ProfilePathOnHost: info.ProfilePathOnHost(), + LibraryNameToDexJarPathOnHost: info.DexBootJarPathMap(), + } + android.SetProvider(ctx, android.ApexExportsInfoProvider, exports) + } + }) } // apexBootclasspathFragmentFiles returns the list of apexFile structures defining the files that // the bootclasspath_fragment contributes to the apex. func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.Module) []apexFile { - bootclasspathFragmentInfo := ctx.OtherModuleProvider(module, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo) + bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, module, java.BootclasspathFragmentApexContentInfoProvider) var filesToAdd []apexFile // Add classpaths.proto config. @@ -2430,7 +2492,7 @@ func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint. // apexClasspathFragmentProtoFile returns *apexFile structure defining the classpath.proto config that // the module contributes to the apex; or nil if the proto config was not generated. func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) *apexFile { - info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo) + info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider) if !info.ClasspathFragmentProtoGenerated { return nil } @@ -2442,7 +2504,7 @@ func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint. // apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment // content module, i.e. a library that is part of the bootclasspath. func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule blueprint.Module, javaModule javaModule) apexFile { - bootclasspathFragmentInfo := ctx.OtherModuleProvider(fragmentModule, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo) + bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragmentModule, java.BootclasspathFragmentApexContentInfoProvider) // Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the // hidden API encpding. @@ -2499,6 +2561,9 @@ func BundleFactory() android.Module { type Defaults struct { android.ModuleBase android.DefaultsModuleBase + + // Single aconfig "cache file" merged from this module and all dependencies. + mergedAconfigFiles map[string]android.Paths } // apex_defaults provides defaultable properties to other apex modules. @@ -2521,6 +2586,10 @@ type OverrideApex struct { android.OverrideModuleBase } +func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { + android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles) +} + func (o *OverrideApex) GenerateAndroidBuildActions(_ android.ModuleContext) { // All the overrides happen in the base module. } @@ -2594,7 +2663,7 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext return } - abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo) + abInfo, _ := android.ModuleProvider(ctx, android.ApexBundleInfoProvider) a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { if ccm, ok := to.(*cc.Module); ok { @@ -2655,7 +2724,7 @@ func (a *apexBundle) checkUpdatable(ctx android.ModuleContext) { func (a *apexBundle) checkClasspathFragments(ctx android.ModuleContext) { ctx.VisitDirectDeps(func(module android.Module) { if tag := ctx.OtherModuleDependencyTag(module); tag == bcpfTag || tag == sscpfTag { - info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo) + info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider) if !info.ClasspathFragmentProtoGenerated { ctx.OtherModuleErrorf(module, "is included in updatable apex %v, it must not set generate_classpaths_proto to false", ctx.ModuleName()) } @@ -2840,77 +2909,8 @@ func makeApexAvailableBaseline() map[string][]string { // // Module separator // - m["com.android.mediaprovider"] = []string{ - "MediaProvider", - "MediaProviderGoogle", - "fmtlib_ndk", - "libbase_ndk", - "libfuse", - "libfuse_jni", - } - // - // Module separator - // m["com.android.runtime"] = []string{ - "libdebuggerd", - "libdebuggerd_common_headers", - "libdebuggerd_handler_core", - "libdl_static", - "libjemalloc5", - "liblinker_main", - "liblinker_malloc", - "liblzma", - "libprocinfo", - "libpropertyinfoparser", - "libscudo", - "libsystemproperties", - "libtombstoned_client_static", - "libunwindstack", "libz", - "libziparchive", - } - // - // Module separator - // - m["com.android.tethering"] = []string{ - "android.hardware.tetheroffload.config-V1.0-java", - "android.hardware.tetheroffload.control-V1.0-java", - "net-utils-framework-common", - } - // - // Module separator - // - m["com.android.wifi"] = []string{ - "PlatformProperties", - "android.hardware.wifi-V1.0-java", - "android.hardware.wifi-V1.0-java-constants", - "android.hardware.wifi-V1.1-java", - "android.hardware.wifi-V1.2-java", - "android.hardware.wifi-V1.3-java", - "android.hardware.wifi-V1.4-java", - "android.hardware.wifi.hostapd-V1.0-java", - "android.hardware.wifi.hostapd-V1.1-java", - "android.hardware.wifi.hostapd-V1.2-java", - "android.hardware.wifi.supplicant-V1.0-java", - "android.hardware.wifi.supplicant-V1.1-java", - "android.hardware.wifi.supplicant-V1.2-java", - "android.hardware.wifi.supplicant-V1.3-java", - "bouncycastle-unbundled", - "framework-wifi-util-lib", - "ksoap2", - "libnanohttpd", - "wifi-lite-protos", - "wifi-nano-protos", - "wifi-service-pre-jarjar", - } - // - // Module separator - // - m[android.AvailableToAnyApex] = []string{ - "libprofile-clang-extras", - "libprofile-clang-extras_ndk", - "libprofile-extras", - "libprofile-extras_ndk", } return m } diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go index a63344fc1..25c0cc444 100644 --- a/apex/apex_singleton.go +++ b/apex/apex_singleton.go @@ -83,7 +83,7 @@ func (s *apexDepsInfoSingleton) GenerateBuildActions(ctx android.SingletonContex updatableFlatLists := android.Paths{} ctx.VisitAllModules(func(module android.Module) { if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok { - apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) + apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider) if path := binaryInfo.FlatListPath(); path != nil { if binaryInfo.Updatable() || apexInfo.Updatable { updatableFlatLists = append(updatableFlatLists, path) diff --git a/apex/apex_test.go b/apex/apex_test.go index abf6b1534..9dc77c28d 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -790,6 +790,79 @@ func TestApexManifestMinSdkVersion(t *testing.T) { } } +func TestApexWithDessertSha(t *testing.T) { + ctx := testApex(t, ` + apex_defaults { + name: "my_defaults", + key: "myapex.key", + product_specific: true, + file_contexts: ":my-file-contexts", + updatable: false, + } + apex { + name: "myapex_30", + min_sdk_version: "30", + defaults: ["my_defaults"], + } + + apex { + name: "myapex_current", + min_sdk_version: "current", + defaults: ["my_defaults"], + } + + apex { + name: "myapex_none", + defaults: ["my_defaults"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + filegroup { + name: "my-file-contexts", + srcs: ["product_specific_file_contexts"], + } + `, withFiles(map[string][]byte{ + "product_specific_file_contexts": nil, + }), android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.Unbundled_build = proptools.BoolPtr(true) + variables.Always_use_prebuilt_sdks = proptools.BoolPtr(false) + }), android.FixtureMergeEnv(map[string]string{ + "UNBUNDLED_BUILD_TARGET_SDK_WITH_DESSERT_SHA": "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456", + })) + + testCases := []struct { + module string + minSdkVersion string + }{ + { + module: "myapex_30", + minSdkVersion: "30", + }, + { + module: "myapex_current", + minSdkVersion: "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456", + }, + { + module: "myapex_none", + minSdkVersion: "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456", + }, + } + for _, tc := range testCases { + module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module) + args := module.Rule("apexRule").Args + optFlags := args["opt_flags"] + if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) { + t.Errorf("%s: Expected min_sdk_version=%s, got: %s", tc.module, tc.minSdkVersion, optFlags) + } + } +} + func TestFileContexts(t *testing.T) { for _, vendor := range []bool{true, false} { prop := "" @@ -1455,6 +1528,7 @@ func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) { name: "libc", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], stubs: { versions: ["1"] }, @@ -1469,6 +1543,7 @@ func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) { name: "libclang_rt.hwasan", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], srcs: [""], @@ -1511,6 +1586,7 @@ func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) { name: "libc", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], stubs: { versions: ["1"] }, @@ -1521,6 +1597,7 @@ func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) { name: "libclang_rt.hwasan", no_libcrt: true, nocrt: true, + no_crt_pad_segment: true, stl: "none", system_shared_libs: [], srcs: [""], @@ -3725,7 +3802,7 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var } func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) { - deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Rule("deapexer") + deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex") outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1) if deapexer.Output != nil { outputs = append(outputs, deapexer.Output.String()) @@ -3768,13 +3845,6 @@ func TestVndkApexCurrent(t *testing.T) { "lib64/libvndk.so", "lib64/libvndksp.so"), }, - { - vndkVersion: "", - expectedFiles: append(commonFiles, - // Legacy VNDK APEX contains only VNDK-SP files (of core variant) - "lib/libvndksp.so", - "lib64/libvndksp.so"), - }, } for _, tc := range testCases { t.Run("VNDK.current with DeviceVndkVersion="+tc.vndkVersion, func(t *testing.T) { @@ -4976,6 +5046,7 @@ func TestApexWithShBinary(t *testing.T) { key: "myapex.key", sh_binaries: ["myscript"], updatable: false, + compile_multilib: "both", } apex_key { @@ -5355,6 +5426,13 @@ func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) { ).RunTest(t) } +// A minimal context object for use with DexJarBuildPath +type moduleErrorfTestCtx struct { +} + +func (ctx moduleErrorfTestCtx) ModuleErrorf(format string, args ...interface{}) { +} + // These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the // propagation of paths to dex implementation jars from the former to the latter. func TestPrebuiltExportDexImplementationJars(t *testing.T) { @@ -5364,10 +5442,10 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { t.Helper() // Make sure the import has been given the correct path to the dex jar. p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency) - dexJarBuildPath := p.DexJarBuildPath().PathOrNil() + dexJarBuildPath := p.DexJarBuildPath(moduleErrorfTestCtx{}).PathOrNil() stem := android.RemoveOptionalPrebuiltPrefix(name) android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.", - ".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", + ".intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar", android.NormalizePathForTesting(dexJarBuildPath)) } @@ -5421,8 +5499,8 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) { // Make sure that dexpreopt can access dex implementation files from the prebuilt. ctx := testDexpreoptWithApexes(t, bp, "", transform) - deapexerName := deapexerModuleName("myapex") - android.AssertStringEquals(t, "APEX module name from deapexer name", "myapex", apexModuleName(deapexerName)) + deapexerName := deapexerModuleName("prebuilt_myapex") + android.AssertStringEquals(t, "APEX module name from deapexer name", "prebuilt_myapex", apexModuleName(deapexerName)) // Make sure that the deapexer has the correct input APEX. deapexer := ctx.ModuleForTests(deapexerName, "android_common") @@ -5645,8 +5723,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -5723,8 +5801,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -5737,7 +5815,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module() overrideNames := []string{ - "", + "myapex", "myjavalib.myapex", "libfoo.myapex", "libbar.myapex", @@ -5912,8 +5990,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -6109,8 +6187,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) - checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Verify the correct module jars contribute to the hiddenapi index file. checkHiddenAPIIndexFromClassesInputs(t, ctx, ``) @@ -6120,6 +6198,84 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv `) }) + + t.Run("Co-existing unflagged apexes should create a duplicate module error", func(t *testing.T) { + bp := ` + // Source + apex { + name: "myapex", + enabled: false, + key: "myapex.key", + bootclasspath_fragments: ["my-bootclasspath-fragment"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + // Prebuilt + prebuilt_apex { + name: "myapex.v1", + source_apex_name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + prefer: true, + } + prebuilt_apex { + name: "myapex.v2", + source_apex_name: "myapex", + arch: { + arm64: { + src: "myapex-arm64.apex", + }, + arm: { + src: "myapex-arm.apex", + }, + }, + exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + prefer: true, + } + + prebuilt_bootclasspath_fragment { + name: "my-bootclasspath-fragment", + contents: ["libfoo", "libbar"], + apex_available: ["myapex"], + hidden_api: { + annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", + metadata: "my-bootclasspath-fragment/metadata.csv", + index: "my-bootclasspath-fragment/index.csv", + stub_flags: "my-bootclasspath-fragment/stub-flags.csv", + all_flags: "my-bootclasspath-fragment/all-flags.csv", + }, + prefer: true, + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: ["myapex"], + prefer: true, + } + java_import { + name: "libbar", + jars: ["libbar.jar"], + apex_available: ["myapex"], + prefer: true, + } + ` + + testDexpreoptWithApexes(t, bp, "Multiple prebuilt modules prebuilt_myapex.v1 and prebuilt_myapex.v2 have been marked as preferred for this source module", preparer, fragment) + }) + } func TestApexWithTests(t *testing.T) { @@ -8313,9 +8469,9 @@ func TestAppSetBundlePrebuilt(t *testing.T) { ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress) // Check that the extractor produces the correct output file from the correct input file. - extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks" + extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks" - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings()) @@ -8340,10 +8496,10 @@ func TestApexSetApksModuleAssignment(t *testing.T) { } `) - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") // Check that the extractor produces the correct apks file from the input module - extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.apks" + extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.apks" extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings()) @@ -8408,30 +8564,39 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { preparers := android.GroupFixturePreparers( java.PrepareForTestWithJavaDefaultModules, + prepareForTestWithBootclasspathFragment, + dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:libfoo"), PrepareForTestWithApexBuildComponents, ). ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.myapex and com.mycompany.android.myapex")) + "Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art")) bpBase := ` apex_set { - name: "com.android.myapex", + name: "com.android.art", installable: true, - exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], set: "myapex.apks", } apex_set { - name: "com.mycompany.android.myapex", - apex_name: "com.android.myapex", + name: "com.mycompany.android.art", + apex_name: "com.android.art", installable: true, - exported_bootclasspath_fragments: ["my-bootclasspath-fragment"], + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], set: "company-myapex.apks", } prebuilt_bootclasspath_fragment { - name: "my-bootclasspath-fragment", - apex_available: ["com.android.myapex"], + name: "art-bootclasspath-fragment", + apex_available: ["com.android.art"], + hidden_api: { + annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", + metadata: "my-bootclasspath-fragment/metadata.csv", + index: "my-bootclasspath-fragment/index.csv", + stub_flags: "my-bootclasspath-fragment/stub-flags.csv", + all_flags: "my-bootclasspath-fragment/all-flags.csv", + }, %s } ` @@ -8441,7 +8606,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { java_import { name: "libfoo", jars: ["libfoo.jar"], - apex_available: ["com.android.myapex"], + apex_available: ["com.android.art"], } `) }) @@ -8453,7 +8618,8 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { public: { jars: ["libbar.jar"], }, - apex_available: ["com.android.myapex"], + shared_library: false, + apex_available: ["com.android.art"], } `) }) @@ -8468,7 +8634,8 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) { public: { jars: ["libbar.jar"], }, - apex_available: ["com.android.myapex"], + shared_library: false, + apex_available: ["com.android.art"], } `) }) @@ -8480,6 +8647,8 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) { PrepareForTestWithApexBuildComponents, ) + errCtx := moduleErrorfTestCtx{} + bpBase := ` apex_set { name: "com.android.myapex", @@ -8528,8 +8697,8 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) { module := result.Module("libfoo", "android_common_com.android.myapex") usesLibraryDep := module.(java.UsesLibraryDependency) android.AssertPathRelativeToTopEquals(t, "dex jar path", - "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", - usesLibraryDep.DexJarBuildPath().Path()) + "out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", + usesLibraryDep.DexJarBuildPath(errCtx).Path()) }) t.Run("java_sdk_library_import", func(t *testing.T) { @@ -8551,8 +8720,8 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) { module := result.Module("libfoo", "android_common_com.android.myapex") usesLibraryDep := module.(java.UsesLibraryDependency) android.AssertPathRelativeToTopEquals(t, "dex jar path", - "out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", - usesLibraryDep.DexJarBuildPath().Path()) + "out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", + usesLibraryDep.DexJarBuildPath(errCtx).Path()) }) t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) { @@ -9124,7 +9293,7 @@ func TestApexSet(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") // Check extract_apks tool parameters. extractedApex := m.Output("extracted/myapex.apks") @@ -9165,7 +9334,7 @@ func TestApexSet_NativeBridge(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex.apex.extractor", "android_common") + m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common") // Check extract_apks tool parameters. No native bridge arch expected extractedApex := m.Output("extracted/myapex.apks") @@ -10175,188 +10344,196 @@ func ensureDoesNotContainRequiredDeps(t *testing.T, ctx *android.TestContext, mo } } -// TODO(b/193460475): Re-enable this test -//func TestApexStrictUpdtabilityLint(t *testing.T) { -// bpTemplate := ` -// apex { -// name: "myapex", -// key: "myapex.key", -// java_libs: ["myjavalib"], -// updatable: %v, -// min_sdk_version: "29", -// } -// apex_key { -// name: "myapex.key", -// } -// java_library { -// name: "myjavalib", -// srcs: ["MyClass.java"], -// apex_available: [ "myapex" ], -// lint: { -// strict_updatability_linting: %v, -// }, -// sdk_version: "current", -// min_sdk_version: "29", -// } -// ` -// fs := android.MockFS{ -// "lint-baseline.xml": nil, -// } -// -// testCases := []struct { -// testCaseName string -// apexUpdatable bool -// javaStrictUpdtabilityLint bool -// lintFileExists bool -// disallowedFlagExpected bool -// }{ -// { -// testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd", -// apexUpdatable: true, -// javaStrictUpdtabilityLint: true, -// lintFileExists: false, -// disallowedFlagExpected: false, -// }, -// { -// testCaseName: "non-updatable apex respects strict_updatability of javalib", -// apexUpdatable: false, -// javaStrictUpdtabilityLint: false, -// lintFileExists: true, -// disallowedFlagExpected: false, -// }, -// { -// testCaseName: "non-updatable apex respects strict updatability of javalib", -// apexUpdatable: false, -// javaStrictUpdtabilityLint: true, -// lintFileExists: true, -// disallowedFlagExpected: true, -// }, -// { -// testCaseName: "updatable apex sets strict updatability of javalib to true", -// apexUpdatable: true, -// javaStrictUpdtabilityLint: false, // will be set to true by mutator -// lintFileExists: true, -// disallowedFlagExpected: true, -// }, -// } -// -// for _, testCase := range testCases { -// bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint) -// fixtures := []android.FixturePreparer{} -// if testCase.lintFileExists { -// fixtures = append(fixtures, fs.AddToFixture()) -// } -// -// result := testApex(t, bp, fixtures...) -// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") -// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto")) -// disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") -// -// if disallowedFlagActual != testCase.disallowedFlagExpected { -// t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) -// } -// } -//} -// -//func TestUpdatabilityLintSkipLibcore(t *testing.T) { -// bp := ` -// apex { -// name: "myapex", -// key: "myapex.key", -// java_libs: ["myjavalib"], -// updatable: true, -// min_sdk_version: "29", -// } -// apex_key { -// name: "myapex.key", -// } -// java_library { -// name: "myjavalib", -// srcs: ["MyClass.java"], -// apex_available: [ "myapex" ], -// sdk_version: "current", -// min_sdk_version: "29", -// } -// ` -// -// testCases := []struct { -// testCaseName string -// moduleDirectory string -// disallowedFlagExpected bool -// }{ -// { -// testCaseName: "lintable module defined outside libcore", -// moduleDirectory: "", -// disallowedFlagExpected: true, -// }, -// { -// testCaseName: "lintable module defined in libcore root directory", -// moduleDirectory: "libcore/", -// disallowedFlagExpected: false, -// }, -// { -// testCaseName: "lintable module defined in libcore child directory", -// moduleDirectory: "libcore/childdir/", -// disallowedFlagExpected: true, -// }, -// } -// -// for _, testCase := range testCases { -// lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "") -// bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp) -// result := testApex(t, "", lintFileCreator, bpFileCreator) -// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") -// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto")) -// cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory) -// disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags) -// -// if disallowedFlagActual != testCase.disallowedFlagExpected { -// t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) -// } -// } -//} -// -//// checks transtive deps of an apex coming from bootclasspath_fragment -//func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) { -// bp := ` -// apex { -// name: "myapex", -// key: "myapex.key", -// bootclasspath_fragments: ["mybootclasspathfragment"], -// updatable: true, -// min_sdk_version: "29", -// } -// apex_key { -// name: "myapex.key", -// } -// bootclasspath_fragment { -// name: "mybootclasspathfragment", -// contents: ["myjavalib"], -// apex_available: ["myapex"], -// hidden_api: { -// split_packages: ["*"], -// }, -// } -// java_library { -// name: "myjavalib", -// srcs: ["MyClass.java"], -// apex_available: [ "myapex" ], -// sdk_version: "current", -// min_sdk_version: "29", -// compile_dex: true, -// } -// ` -// fs := android.MockFS{ -// "lint-baseline.xml": nil, -// } -// -// result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture()) -// myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") -// sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto")) -// if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") { -// t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command) -// } -//} +func TestApexStrictUpdtabilityLint(t *testing.T) { + bpTemplate := ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["myjavalib"], + updatable: %v, + min_sdk_version: "29", + } + apex_key { + name: "myapex.key", + } + java_library { + name: "myjavalib", + srcs: ["MyClass.java"], + apex_available: [ "myapex" ], + lint: { + strict_updatability_linting: %v, + %s + }, + sdk_version: "current", + min_sdk_version: "29", + } + ` + fs := android.MockFS{ + "lint-baseline.xml": nil, + } + + testCases := []struct { + testCaseName string + apexUpdatable bool + javaStrictUpdtabilityLint bool + lintFileExists bool + disallowedFlagExpected bool + }{ + { + testCaseName: "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd", + apexUpdatable: true, + javaStrictUpdtabilityLint: true, + lintFileExists: false, + disallowedFlagExpected: false, + }, + { + testCaseName: "non-updatable apex respects strict_updatability of javalib", + apexUpdatable: false, + javaStrictUpdtabilityLint: false, + lintFileExists: true, + disallowedFlagExpected: false, + }, + { + testCaseName: "non-updatable apex respects strict updatability of javalib", + apexUpdatable: false, + javaStrictUpdtabilityLint: true, + lintFileExists: true, + disallowedFlagExpected: true, + }, + { + testCaseName: "updatable apex sets strict updatability of javalib to true", + apexUpdatable: true, + javaStrictUpdtabilityLint: false, // will be set to true by mutator + lintFileExists: true, + disallowedFlagExpected: true, + }, + } + + for _, testCase := range testCases { + fixtures := []android.FixturePreparer{} + baselineProperty := "" + if testCase.lintFileExists { + fixtures = append(fixtures, fs.AddToFixture()) + baselineProperty = "baseline_filename: \"lint-baseline.xml\"" + } + bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint, baselineProperty) + + result := testApex(t, bp, fixtures...) + myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") + sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto")) + disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") + + if disallowedFlagActual != testCase.disallowedFlagExpected { + t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) + } + } +} + +func TestUpdatabilityLintSkipLibcore(t *testing.T) { + bp := ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["myjavalib"], + updatable: true, + min_sdk_version: "29", + } + apex_key { + name: "myapex.key", + } + java_library { + name: "myjavalib", + srcs: ["MyClass.java"], + apex_available: [ "myapex" ], + sdk_version: "current", + min_sdk_version: "29", + lint: { + baseline_filename: "lint-baseline.xml", + } + } + ` + + testCases := []struct { + testCaseName string + moduleDirectory string + disallowedFlagExpected bool + }{ + { + testCaseName: "lintable module defined outside libcore", + moduleDirectory: "", + disallowedFlagExpected: true, + }, + { + testCaseName: "lintable module defined in libcore root directory", + moduleDirectory: "libcore/", + disallowedFlagExpected: false, + }, + { + testCaseName: "lintable module defined in libcore child directory", + moduleDirectory: "libcore/childdir/", + disallowedFlagExpected: true, + }, + } + + for _, testCase := range testCases { + lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "") + bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp) + result := testApex(t, "", lintFileCreator, bpFileCreator) + myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") + sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto")) + cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory) + disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags) + + if disallowedFlagActual != testCase.disallowedFlagExpected { + t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command) + } + } +} + +// checks transtive deps of an apex coming from bootclasspath_fragment +func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) { + bp := ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: ["mybootclasspathfragment"], + updatable: true, + min_sdk_version: "29", + } + apex_key { + name: "myapex.key", + } + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: ["myjavalib"], + apex_available: ["myapex"], + hidden_api: { + split_packages: ["*"], + }, + } + java_library { + name: "myjavalib", + srcs: ["MyClass.java"], + apex_available: [ "myapex" ], + sdk_version: "current", + min_sdk_version: "29", + compile_dex: true, + lint: { + baseline_filename: "lint-baseline.xml", + } + } + ` + fs := android.MockFS{ + "lint-baseline.xml": nil, + } + + result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture()) + myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") + sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto")) + if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") { + t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command) + } +} // updatable apexes should propagate updatable=true to its apps func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) { @@ -10947,25 +11124,23 @@ func TestAconfigFilesJavaDeps(t *testing.T) { mod := ctx.ModuleForTests("myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) - if len(copyCmds) != 5 { + if len(copyCmds) != 8 { t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s) } - ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex$") + ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$") + ensureMatches(t, copyCmds[5], "^cp -f .*/package.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[6], "^cp -f .*/flag.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[7], "^cp -f .*/flag.val .*/image.apex/etc$") - combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") - s = " " + combineAconfigRule.Args["cache_files"] - aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] - if len(aconfigArgs) != 2 { - t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s) + inputs := []string{ + "my_aconfig_declarations_foo/intermediate.pb", + "my_aconfig_declarations_bar/intermediate.pb", } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_bar/intermediate.pb") - - buildParams := combineAconfigRule.BuildParams - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_bar/intermediate.pb") - ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") + VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") + VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val") } func TestAconfigFilesJavaAndCcDeps(t *testing.T) { @@ -11073,30 +11248,24 @@ func TestAconfigFilesJavaAndCcDeps(t *testing.T) { mod := ctx.ModuleForTests("myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) - if len(copyCmds) != 9 { - t.Fatalf("Expected 9 commands, got %d in:\n%s", len(copyCmds), s) + if len(copyCmds) != 12 { + t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s) } - ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex$") - - combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") - s = " " + combineAconfigRule.Args["cache_files"] - aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] - if len(aconfigArgs) != 3 { - t.Fatalf("Expected 3 commands, got %d in:\n%s", len(aconfigArgs), s) - } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/aconfig_merged.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_baz/intermediate.pb") + ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$") + ensureMatches(t, copyCmds[9], "^cp -f .*/package.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[10], "^cp -f .*/flag.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[11], "^cp -f .*/flag.val .*/image.apex/etc$") - buildParams := combineAconfigRule.BuildParams - if len(buildParams.Inputs) != 3 { - t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs)) + inputs := []string{ + "my_aconfig_declarations_foo/intermediate.pb", + "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb", + "my_aconfig_declarations_baz/intermediate.pb", } - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/aconfig_merged.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_baz/intermediate.pb") - ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") + VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") + VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val") } func TestAconfigFilesRustDeps(t *testing.T) { @@ -11220,28 +11389,45 @@ func TestAconfigFilesRustDeps(t *testing.T) { mod := ctx.ModuleForTests("myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) - if len(copyCmds) != 23 { - t.Fatalf("Expected 23 commands, got %d in:\n%s", len(copyCmds), s) + if len(copyCmds) != 26 { + t.Fatalf("Expected 26 commands, got %d in:\n%s", len(copyCmds), s) } - ensureMatches(t, copyCmds[22], "^cp -f .*/aconfig_flags.pb .*/image.apex$") + ensureMatches(t, copyCmds[22], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$") + ensureMatches(t, copyCmds[23], "^cp -f .*/package.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[24], "^cp -f .*/flag.map .*/image.apex/etc$") + ensureMatches(t, copyCmds[25], "^cp -f .*/flag.val .*/image.apex/etc$") - combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") - s = " " + combineAconfigRule.Args["cache_files"] + inputs := []string{ + "my_aconfig_declarations_foo/intermediate.pb", + "my_aconfig_declarations_bar/intermediate.pb", + "my_aconfig_declarations_baz/intermediate.pb", + "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb", + } + VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") + VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map") + VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val") +} + +func VerifyAconfigRule(t *testing.T, mod *android.TestingModule, desc string, inputs []string, output string, container string, file_type string) { + aconfigRule := mod.Description(desc) + s := " " + aconfigRule.Args["cache_files"] aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] - if len(aconfigArgs) != 2 { - t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s) + if len(aconfigArgs) != len(inputs) { + t.Fatalf("Expected %d commands, got %d in:\n%s", len(inputs), len(aconfigArgs), s) } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, aconfigArgs, "my_rust_binary/android_arm64_armv8-a_apex10000/aconfig_merged.pb") - buildParams := combineAconfigRule.BuildParams - if len(buildParams.Inputs) != 2 { - t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs)) + ensureEquals(t, container, aconfigRule.Args["container"]) + ensureEquals(t, file_type, aconfigRule.Args["file_type"]) + + buildParams := aconfigRule.BuildParams + for _, input := range inputs { + android.EnsureListContainsSuffix(t, aconfigArgs, input) + android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), input) } - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_rust_binary/android_arm64_armv8-a_apex10000/aconfig_merged.pb") - ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") + + ensureContains(t, buildParams.Output.String(), output) } func TestAconfigFilesOnlyMatchCurrentApex(t *testing.T) { @@ -11404,3 +11590,343 @@ func TestAconfigFilesRemoveDuplicates(t *testing.T) { android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") } + +// Test that the boot jars come from the _selected_ apex prebuilt +// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config +func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { + checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) { + t.Helper() + s := ctx.ModuleForTests("dex_bootjars", "android_common") + foundLibfooJar := false + base := stem + ".jar" + for _, output := range s.AllOutputs() { + if filepath.Base(output) == base { + foundLibfooJar = true + buildRule := s.Output(output) + android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String()) + } + } + if !foundLibfooJar { + t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs())) + } + } + + // Check that the boot jars of the selected apex are run through boot_jars_package_check + // This validates that the jars on the bootclasspath do not contain packages outside an allowlist + checkBootJarsPackageCheck := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) { + platformBcp := ctx.ModuleForTests("platform-bootclasspath", "android_common") + bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check") + android.AssertStringMatches(t, "Could not find the correct boot dex jar in package check rule", bootJarsCheckRule.RuleParams.Command, "build/soong/scripts/check_boot_jars/package_allowed_list.txt.*"+expectedBootJar) + } + + // Check that the boot jars used to generate the monolithic hiddenapi flags come from the selected apex + checkBootJarsForMonolithicHiddenapi := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) { + monolithicHiddenapiFlagsCmd := ctx.ModuleForTests("platform-bootclasspath", "android_common").Output("out/soong/hiddenapi/hiddenapi-stub-flags.txt").RuleParams.Command + android.AssertStringMatches(t, "Could not find the correct boot dex jar in monolithic hiddenapi flags generation command", monolithicHiddenapiFlagsCmd, "--boot-dex="+expectedBootJar) + } + + bp := ` + // Source APEX. + + java_library { + name: "framework-foo", + srcs: ["foo.java"], + installable: true, + apex_available: [ + "com.android.foo", + ], + } + + bootclasspath_fragment { + name: "foo-bootclasspath-fragment", + contents: ["framework-foo"], + apex_available: [ + "com.android.foo", + ], + hidden_api: { + split_packages: ["*"], + }, + } + + apex_key { + name: "com.android.foo.key", + public_key: "com.android.foo.avbpubkey", + private_key: "com.android.foo.pem", + } + + apex { + name: "com.android.foo", + key: "com.android.foo.key", + bootclasspath_fragments: ["foo-bootclasspath-fragment"], + updatable: false, + } + + // Prebuilt APEX. + + java_sdk_library_import { + name: "framework-foo", + public: { + jars: ["foo.jar"], + }, + apex_available: ["com.android.foo"], + shared_library: false, + } + + prebuilt_bootclasspath_fragment { + name: "foo-bootclasspath-fragment", + contents: ["framework-foo"], + hidden_api: { + annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", + metadata: "my-bootclasspath-fragment/metadata.csv", + index: "my-bootclasspath-fragment/index.csv", + stub_flags: "my-bootclasspath-fragment/stub-flags.csv", + all_flags: "my-bootclasspath-fragment/all-flags.csv", + }, + apex_available: [ + "com.android.foo", + ], + } + + prebuilt_apex { + name: "com.android.foo", + apex_name: "com.android.foo", + src: "com.android.foo-arm.apex", + exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"], + } + + // Another Prebuilt ART APEX + prebuilt_apex { + name: "com.android.foo.v2", + apex_name: "com.android.foo", // Used to determine the API domain + src: "com.android.foo-arm.apex", + exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"], + } + + // APEX contribution modules + + apex_contributions { + name: "foo.source.contributions", + api_domain: "com.android.foo", + contents: ["com.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.contributions", + api_domain: "com.android.foo", + contents: ["prebuilt_com.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.v2.contributions", + api_domain: "com.android.foo", + contents: ["com.android.foo.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator + } + ` + + testCases := []struct { + desc string + selectedApexContributions string + expectedBootJar string + }{ + { + desc: "Source apex com.android.foo is selected, bootjar should come from source java library", + selectedApexContributions: "foo.source.contributions", + expectedBootJar: "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar", + }, + { + desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt", + selectedApexContributions: "foo.prebuilt.contributions", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar", + }, + { + desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt", + selectedApexContributions: "foo.prebuilt.v2.contributions", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar", + }, + } + + fragment := java.ApexVariantReference{ + Apex: proptools.StringPtr("com.android.foo"), + Module: proptools.StringPtr("foo-bootclasspath-fragment"), + } + + for _, tc := range testCases { + preparer := android.GroupFixturePreparers( + java.FixtureConfigureApexBootJars("com.android.foo:framework-foo"), + android.FixtureMergeMockFs(map[string][]byte{ + "system/sepolicy/apex/com.android.foo-file_contexts": nil, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions, + } + }), + ) + ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment) + checkBootDexJarPath(t, ctx, "framework-foo", tc.expectedBootJar) + checkBootJarsPackageCheck(t, ctx, tc.expectedBootJar) + checkBootJarsForMonolithicHiddenapi(t, ctx, tc.expectedBootJar) + } +} + +// Test that product packaging installs the selected mainline module (either source or a specific prebuilt) +// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config +func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) { + // check that the LOCAL_MODULE in the generated mk file matches the name used in PRODUCT_PACKAGES + // Since the name used in PRODUCT_PACKAGES does not contain prebuilt_ prefix, LOCAL_MODULE should not contain any prefix either + checkLocalModuleName := func(t *testing.T, ctx *android.TestContext, soongApexModuleName string, expectedLocalModuleName string) { + // Variations are created based on apex_name + entries := android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests(soongApexModuleName, "android_common_com.android.foo").Module()) + android.AssertStringEquals(t, "LOCAL_MODULE of the prebuilt apex must match the name listed in PRODUCT_PACKAGES", expectedLocalModuleName, entries[0].EntryMap["LOCAL_MODULE"][0]) + } + // for a mainline module family, check that only the flagged soong module is visible to make + checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) { + variation := func(moduleName string) string { + ret := "android_common_com.android.foo" + if moduleName == "com.google.android.foo" { + ret = "android_common_com.google.android.foo_com.android.foo" + } + return ret + } + + visibleModule := ctx.ModuleForTests(visibleModuleName, variation(visibleModuleName)).Module() + android.AssertBoolEquals(t, "Apex "+visibleModuleName+" selected using apex_contributions should be visible to make", false, visibleModule.IsHideFromMake()) + + for _, hiddenModuleName := range hiddenModuleNames { + hiddenModule := ctx.ModuleForTests(hiddenModuleName, variation(hiddenModuleName)).Module() + android.AssertBoolEquals(t, "Apex "+hiddenModuleName+" not selected using apex_contributions should be hidden from make", true, hiddenModule.IsHideFromMake()) + + } + } + + bp := ` + apex_key { + name: "com.android.foo.key", + public_key: "com.android.foo.avbpubkey", + private_key: "com.android.foo.pem", + } + + // AOSP source apex + apex { + name: "com.android.foo", + key: "com.android.foo.key", + updatable: false, + } + + // Google source apex + override_apex { + name: "com.google.android.foo", + base: "com.android.foo", + key: "com.android.foo.key", + } + + // Prebuilt Google APEX. + + prebuilt_apex { + name: "com.google.android.foo", + apex_name: "com.android.foo", + src: "com.android.foo-arm.apex", + prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present + } + + // Another Prebuilt Google APEX + prebuilt_apex { + name: "com.google.android.foo.v2", + apex_name: "com.android.foo", + source_apex_name: "com.google.android.foo", // source_apex_name becomes LOCAL_MODULE in the generated mk file + src: "com.android.foo-arm.apex", + prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present + } + + // APEX contribution modules + + apex_contributions { + name: "foo.source.contributions", + api_domain: "com.android.foo", + contents: ["com.google.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.contributions", + api_domain: "com.android.foo", + contents: ["prebuilt_com.google.android.foo"], + } + + apex_contributions { + name: "foo.prebuilt.v2.contributions", + api_domain: "com.android.foo", + contents: ["prebuilt_com.google.android.foo.v2"], + } + + // This is an incompatible module because it selects multiple versions of the same mainline module + apex_contributions { + name: "foo.prebuilt.duplicate.contributions", + api_domain: "com.android.foo", + contents: [ + "prebuilt_com.google.android.foo", + "prebuilt_com.google.android.foo.v2", + ], + } + ` + + testCases := []struct { + desc string + selectedApexContributions string + expectedVisibleModuleName string + expectedHiddenModuleNames []string + expectedError string + }{ + { + desc: "Source apex is selected, prebuilts should be hidden from make", + selectedApexContributions: "foo.source.contributions", + expectedVisibleModuleName: "com.google.android.foo", + expectedHiddenModuleNames: []string{"prebuilt_com.google.android.foo", "prebuilt_com.google.android.foo.v2"}, + }, + { + desc: "Prebuilt apex prebuilt_com.android.foo is selected, source and the other prebuilt should be hidden from make", + selectedApexContributions: "foo.prebuilt.contributions", + expectedVisibleModuleName: "prebuilt_com.google.android.foo", + expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo.v2"}, + }, + { + desc: "Prebuilt apex prebuilt_com.android.fooi.v2 is selected, source and the other prebuilt should be hidden from make", + selectedApexContributions: "foo.prebuilt.v2.contributions", + expectedVisibleModuleName: "prebuilt_com.google.android.foo.v2", + expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo"}, + }, + { + desc: "Multiple versions of a prebuilt apex is selected in the same release config", + selectedApexContributions: "foo.prebuilt.duplicate.contributions", + expectedError: "Found duplicate variations of the same module in apex_contributions: prebuilt_com.google.android.foo and prebuilt_com.google.android.foo.v2", + }, + } + + for _, tc := range testCases { + preparer := android.GroupFixturePreparers( + android.FixtureMergeMockFs(map[string][]byte{ + "system/sepolicy/apex/com.android.foo-file_contexts": nil, + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions, + } + }), + ) + if tc.expectedError != "" { + preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(tc.expectedError)) + testApex(t, bp, preparer) + return + } + ctx := testApex(t, bp, preparer) + + // Check that the LOCAL_MODULE of the two prebuilts is com.android.foo + // This ensures that product packaging can pick them for installation if it has been flagged by apex_contributions + checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo", "com.google.android.foo") + checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo.v2", "com.google.android.foo") + + // Check that + // 1. The contents of the selected apex_contributions are visible to make + // 2. The rest of the apexes in the mainline module family (source or other prebuilt) is hidden from make + checkHideFromMake(t, ctx, tc.expectedVisibleModuleName, tc.expectedHiddenModuleNames) + } +} diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index 43be310bb..778c20a56 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -53,7 +53,11 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) { java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"), java.FixtureConfigureApexBootJars("someapex:foo", "someapex:bar"), prepareForTestWithArtApex, - + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true", + } + }), java.PrepareForTestWithJavaSdkLibraryFiles, java.FixtureWithLastReleaseApis("foo", "baz"), ).RunTestWithBp(t, ` @@ -152,11 +156,11 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) { // Check stub dex paths exported by art. artFragment := result.Module("art-bootclasspath-fragment", "android_common") - artInfo := result.ModuleProvider(artFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo) + artInfo, _ := android.SingletonModuleProvider(result, artFragment, java.HiddenAPIInfoProvider) - bazPublicStubs := "out/soong/.intermediates/baz.stubs/android_common/dex/baz.stubs.jar" - bazSystemStubs := "out/soong/.intermediates/baz.stubs.system/android_common/dex/baz.stubs.system.jar" - bazTestStubs := "out/soong/.intermediates/baz.stubs.test/android_common/dex/baz.stubs.test.jar" + bazPublicStubs := "out/soong/.intermediates/baz.stubs.exportable/android_common/dex/baz.stubs.exportable.jar" + bazSystemStubs := "out/soong/.intermediates/baz.stubs.exportable.system/android_common/dex/baz.stubs.exportable.system.jar" + bazTestStubs := "out/soong/.intermediates/baz.stubs.exportable.test/android_common/dex/baz.stubs.exportable.test.jar" checkAPIScopeStubs("art", artInfo, java.PublicHiddenAPIScope, bazPublicStubs) checkAPIScopeStubs("art", artInfo, java.SystemHiddenAPIScope, bazSystemStubs) @@ -165,10 +169,10 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) { // Check stub dex paths exported by other. otherFragment := result.Module("other-bootclasspath-fragment", "android_common") - otherInfo := result.ModuleProvider(otherFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo) + otherInfo, _ := android.SingletonModuleProvider(result, otherFragment, java.HiddenAPIInfoProvider) - fooPublicStubs := "out/soong/.intermediates/foo.stubs/android_common/dex/foo.stubs.jar" - fooSystemStubs := "out/soong/.intermediates/foo.stubs.system/android_common/dex/foo.stubs.system.jar" + fooPublicStubs := "out/soong/.intermediates/foo.stubs.exportable/android_common/dex/foo.stubs.exportable.jar" + fooSystemStubs := "out/soong/.intermediates/foo.stubs.exportable.system/android_common/dex/foo.stubs.exportable.system.jar" checkAPIScopeStubs("other", otherInfo, java.PublicHiddenAPIScope, bazPublicStubs, fooPublicStubs) checkAPIScopeStubs("other", otherInfo, java.SystemHiddenAPIScope, bazSystemStubs, fooSystemStubs) @@ -312,6 +316,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ `art-bootclasspath-fragment`, `com.android.art.key`, + `dex2oatd`, }) // Make sure that the source bootclasspath_fragment copies its dex files to the predefined @@ -374,7 +379,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"), ).RunTest(t) - ensureExactDeapexedContents(t, result.TestContext, "com.android.art", "android_common", []string{ + ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common", []string{ "etc/boot-image.prof", "javalib/bar.jar", "javalib/foo.jar", @@ -383,6 +388,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ `art-bootclasspath-fragment`, `com.android.art.key`, + `dex2oatd`, `prebuilt_com.android.art`, }) @@ -529,14 +535,16 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,")) java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ - `com.android.art.apex.selector`, + `dex2oatd`, `prebuilt_art-bootclasspath-fragment`, + `prebuilt_com.android.art.apex.selector`, + `prebuilt_com.android.art.deapexer`, }) java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{ - `com.android.art.deapexer`, `dex2oatd`, `prebuilt_bar`, + `prebuilt_com.android.art.deapexer`, `prebuilt_foo`, }) @@ -546,7 +554,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { t.Run("enabled alternative APEX", func(t *testing.T) { preparers.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - "Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art")). + "Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art")). RunTestWithBp(t, fmt.Sprintf(bp, "")) }) } @@ -644,6 +652,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { }) java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{ + `dex2oatd`, `myapex.key`, `mybootclasspathfragment`, }) @@ -655,7 +664,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { // Make sure that the fragment provides the hidden API encoded dex jars to the APEX. fragment := result.Module("mybootclasspathfragment", "android_common_apex10000") - info := result.ModuleProvider(fragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo) + info, _ := android.SingletonModuleProvider(result, fragment, java.BootclasspathFragmentApexContentInfoProvider) checkFragmentExportedDexJar := func(name string, expectedDexJar string) { module := result.Module(name, "android_common_apex10000") @@ -675,7 +684,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { func getDexJarPath(result *android.TestResult, name string) string { module := result.Module(name, "android_common") - return module.(java.UsesLibraryDependency).DexJarBuildPath().Path().RelativeToTop().String() + return module.(java.UsesLibraryDependency).DexJarBuildPath(moduleErrorfTestCtx{}).Path().RelativeToTop().String() } // TestBootclasspathFragment_HiddenAPIList checks to make sure that the correct parameters are @@ -694,6 +703,11 @@ func TestBootclasspathFragment_HiddenAPIList(t *testing.T) { java.PrepareForTestWithJavaSdkLibraryFiles, java.FixtureWithLastReleaseApis("foo", "quuz"), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true", + } + }), ).RunTestWithBp(t, ` apex { name: "com.android.art", @@ -805,11 +819,11 @@ func TestBootclasspathFragment_HiddenAPIList(t *testing.T) { "foo", }) - fooStubs := getDexJarPath(result, "foo.stubs") - quuzPublicStubs := getDexJarPath(result, "quuz.stubs") - quuzSystemStubs := getDexJarPath(result, "quuz.stubs.system") - quuzTestStubs := getDexJarPath(result, "quuz.stubs.test") - quuzModuleLibStubs := getDexJarPath(result, "quuz.stubs.module_lib") + fooStubs := getDexJarPath(result, "foo.stubs.exportable") + quuzPublicStubs := getDexJarPath(result, "quuz.stubs.exportable") + quuzSystemStubs := getDexJarPath(result, "quuz.stubs.exportable.system") + quuzTestStubs := getDexJarPath(result, "quuz.stubs.exportable.test") + quuzModuleLibStubs := getDexJarPath(result, "quuz.stubs.exportable.module_lib") // Make sure that the fragment uses the quuz stub dex jars when generating the hidden API flags. fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000") diff --git a/apex/builder.go b/apex/builder.go index 30788630b..6ad282ab6 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -85,6 +85,18 @@ func init() { pctx.HostBinToolVariable("aconfig", "aconfig") } +type createStorageStruct struct { + Output_file string + Desc string + File_type string +} + +var createStorageInfo = []createStorageStruct{ + {"package.map", "create_aconfig_package_map_file", "package_map"}, + {"flag.map", "create_aconfig_flag_map_file", "flag_map"}, + {"flag.val", "create_aconfig_flag_val_file", "flag_val"}, +} + var ( apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{ Command: `rm -f $out && ${jsonmodify} $in ` + @@ -633,6 +645,7 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin") defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"} + aconfigDest := imageDir.Join(ctx, "etc").String() if len(a.aconfigFiles) > 0 { apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb") ctx.Build(pctx, android.BuildParams{ @@ -645,9 +658,28 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { }, }) - copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+imageDir.String()) + copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+aconfigDest) implicitInputs = append(implicitInputs, apexAconfigFile) - defaultReadOnlyFiles = append(defaultReadOnlyFiles, apexAconfigFile.Base()) + defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+apexAconfigFile.Base()) + + for _, info := range createStorageInfo { + outputFile := android.PathForModuleOut(ctx, info.Output_file) + ctx.Build(pctx, android.BuildParams{ + Rule: aconfig.CreateStorageRule, + Inputs: a.aconfigFiles, + Output: outputFile, + Description: info.Desc, + Args: map[string]string{ + "container": ctx.ModuleName(), + "file_type": info.File_type, + "cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "), + }, + }) + + copyCommands = append(copyCommands, "cp -f "+outputFile.String()+" "+aconfigDest) + implicitInputs = append(implicitInputs, outputFile) + defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+outputFile.Base()) + } } //////////////////////////////////////////////////////////////////////////////////// @@ -695,18 +727,20 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() { minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() - if java.UseApiFingerprint(ctx) { - minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) - implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) + if useApiFingerprint, fingerprintMinSdkVersion, fingerprintDeps := + java.UseApiFingerprint(ctx); useApiFingerprint { + minSdkVersion = fingerprintMinSdkVersion + implicitInputs = append(implicitInputs, fingerprintDeps) } } // apex module doesn't have a concept of target_sdk_version, hence for the time // being targetSdkVersion == default targetSdkVersion of the branch. targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()) - if java.UseApiFingerprint(ctx) { - targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String()) - implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx)) + if useApiFingerprint, fingerprintTargetSdkVersion, fingerprintDeps := + java.UseApiFingerprint(ctx); useApiFingerprint { + targetSdkVersion = fingerprintTargetSdkVersion + implicitInputs = append(implicitInputs, fingerprintDeps) } optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion) optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion) @@ -910,7 +944,7 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { var validations android.Paths validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath)) // TODO(b/279688635) deapexer supports [ext4] - if suffix == imageApexSuffix && ext4 == a.payloadFsType { + if !a.testApex && suffix == imageApexSuffix && ext4 == a.payloadFsType { validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath)) } if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 { diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go index 9142eed99..b9a91982a 100644 --- a/apex/classpath_element_test.go +++ b/apex/classpath_element_test.go @@ -20,7 +20,6 @@ import ( "android/soong/android" "android/soong/java" - "github.com/google/blueprint" ) // Contains tests for java.CreateClasspathElements logic from java/classpath_element.go that @@ -28,19 +27,12 @@ import ( // testClasspathElementContext is a ClasspathElementContext suitable for use in tests. type testClasspathElementContext struct { + android.OtherModuleProviderContext testContext *android.TestContext module android.Module errs []error } -func (t *testClasspathElementContext) OtherModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool { - return t.testContext.ModuleHasProvider(module, provider) -} - -func (t *testClasspathElementContext) OtherModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} { - return t.testContext.ModuleProvider(module, provider) -} - func (t *testClasspathElementContext) ModuleErrorf(fmt string, args ...interface{}) { t.errs = append(t.errs, t.testContext.ModuleErrorf(t.module, fmt, args...)) } @@ -238,7 +230,11 @@ func TestCreateClasspathElements(t *testing.T) { } newCtx := func() *testClasspathElementContext { - return &testClasspathElementContext{testContext: result.TestContext, module: bootclasspath} + return &testClasspathElementContext{ + OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(), + testContext: result.TestContext, + module: bootclasspath, + } } // Verify that CreateClasspathElements works when given valid input. diff --git a/apex/deapexer.go b/apex/deapexer.go index 3b7c77dc9..a6731080c 100644 --- a/apex/deapexer.go +++ b/apex/deapexer.go @@ -53,6 +53,10 @@ type DeapexerProperties struct { // all architectures, e.g. java. CommonModules []string + // List of modules that use an embedded .prof to guide optimization of the equivalent dexpreopt artifact + // This is a subset of CommonModules + DexpreoptProfileGuidedModules []string + // List of files exported from the .apex file by this module // // Each entry is a path from the apex root, e.g. javalib/core-libart.jar. @@ -98,6 +102,7 @@ func privateDeapexerFactory() android.Module { func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) { // Add dependencies from the java modules to which this exports files from the `.apex` file onto // this module so that they can access the `DeapexerInfo` object that this provides. + // TODO: b/308174306 - Once all the mainline modules have been flagged, drop this dependency edge for _, lib := range p.properties.CommonModules { dep := prebuiltApexExportedModuleName(ctx, lib) ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep) @@ -126,8 +131,9 @@ func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) { // apex relative path to extracted file path available for other modules. if len(exports) > 0 { // Make the information available for other modules. - di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports) - ctx.SetProvider(android.DeapexerProvider, di) + di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports, p.properties.CommonModules) + di.AddDexpreoptProfileGuidedExportedModuleNames(p.properties.DexpreoptProfileGuidedModules...) + android.SetProvider(ctx, android.DeapexerProvider, di) // Create a sorted list of the files that this exports. exportedPaths = android.SortedUniquePaths(exportedPaths) diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go index 2e828cade..7a17f501c 100644 --- a/apex/dexpreopt_bootjars_test.go +++ b/apex/dexpreopt_bootjars_test.go @@ -164,6 +164,7 @@ func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) { "out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar", "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof", "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", + "out/soong/dexpreopt/uffd_gc_flag.txt", } expectedOutputs := []string{ @@ -199,8 +200,9 @@ func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) { "out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar", - "out/soong/.intermediates/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof", + "out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof", "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", + "out/soong/dexpreopt/uffd_gc_flag.txt", } expectedOutputs := []string{ @@ -252,3 +254,162 @@ func TestDexpreoptBootZip(t *testing.T) { testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, false) } + +// Multiple ART apexes might exist in the tree. +// The profile should correspond to the apex selected using release build flags +func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) { + ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art" + bp := ` + // Platform. + + platform_bootclasspath { + name: "platform-bootclasspath", + fragments: [ + { + apex: "com.android.art", + module: "art-bootclasspath-fragment", + }, + ], + } + + // Source ART APEX. + + java_library { + name: "core-oj", + srcs: ["core-oj.java"], + installable: true, + apex_available: [ + "com.android.art", + ], + } + + bootclasspath_fragment { + name: "art-bootclasspath-fragment", + image_name: "art", + contents: ["core-oj"], + apex_available: [ + "com.android.art", + ], + hidden_api: { + split_packages: ["*"], + }, + } + + apex_key { + name: "com.android.art.key", + public_key: "com.android.art.avbpubkey", + private_key: "com.android.art.pem", + } + + apex { + name: "com.android.art", + key: "com.android.art.key", + bootclasspath_fragments: ["art-bootclasspath-fragment"], + updatable: false, + } + + // Prebuilt ART APEX. + + java_import { + name: "core-oj", + jars: ["core-oj.jar"], + apex_available: [ + "com.android.art", + ], + } + + prebuilt_bootclasspath_fragment { + name: "art-bootclasspath-fragment", + image_name: "art", + contents: ["core-oj"], + hidden_api: { + annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", + metadata: "my-bootclasspath-fragment/metadata.csv", + index: "my-bootclasspath-fragment/index.csv", + stub_flags: "my-bootclasspath-fragment/stub-flags.csv", + all_flags: "my-bootclasspath-fragment/all-flags.csv", + }, + apex_available: [ + "com.android.art", + ], + } + + prebuilt_apex { + name: "com.android.art", + apex_name: "com.android.art", + src: "com.android.art-arm.apex", + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], + } + + // Another Prebuilt ART APEX + prebuilt_apex { + name: "com.android.art.v2", + apex_name: "com.android.art", // Used to determine the API domain + src: "com.android.art-arm.apex", + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], + } + + // APEX contribution modules + + apex_contributions { + name: "art.source.contributions", + api_domain: "com.android.art", + contents: ["com.android.art"], + } + + apex_contributions { + name: "art.prebuilt.contributions", + api_domain: "com.android.art", + contents: ["prebuilt_com.android.art"], + } + + apex_contributions { + name: "art.prebuilt.v2.contributions", + api_domain: "com.android.art", + contents: ["com.android.art.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator + } + + ` + + testCases := []struct { + desc string + selectedArtApexContributions string + expectedProfile string + }{ + { + desc: "Source apex com.android.art is selected, profile should come from source java library", + selectedArtApexContributions: "art.source.contributions", + expectedProfile: "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof", + }, + { + desc: "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt", + selectedArtApexContributions: "art.prebuilt.contributions", + expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof", + }, + { + desc: "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt", + selectedArtApexContributions: "art.prebuilt.v2.contributions", + expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof", + }, + } + for _, tc := range testCases { + result := android.GroupFixturePreparers( + java.PrepareForTestWithDexpreopt, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.FixtureConfigureBootJars("com.android.art:core-oj"), + PrepareForTestWithApexBuildComponents, + prepareForTestWithArtApex, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_APEX_CONTRIBUTIONS_ART": tc.selectedArtApexContributions, + } + }), + ).RunTestWithBp(t, bp) + + dexBootJars := result.ModuleForTests("dex_bootjars", "android_common") + rule := dexBootJars.Output(ruleFile) + + inputs := rule.Implicits.Strings() + android.AssertStringListContains(t, tc.desc, inputs, tc.expectedProfile) + } +} diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go index 05bb13689..2be9c10e1 100644 --- a/apex/platform_bootclasspath_test.go +++ b/apex/platform_bootclasspath_test.go @@ -86,6 +86,7 @@ func TestPlatformBootclasspath_Fragments(t *testing.T) { "bar-fragment", ], updatable: false, + min_sdk_version: "30", // R } apex_key { @@ -138,6 +139,7 @@ func TestPlatformBootclasspath_Fragments(t *testing.T) { sdk_version: "none", compile_dex: true, permitted_packages: ["bar"], + min_sdk_version: "30", // R } java_sdk_library { @@ -152,22 +154,22 @@ func TestPlatformBootclasspath_Fragments(t *testing.T) { ).RunTest(t) pbcp := result.Module("platform-bootclasspath", "android_common") - info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo) + info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider) for _, category := range java.HiddenAPIFlagFileCategories { - name := category.PropertyName + name := category.PropertyName() message := fmt.Sprintf("category %s", name) filename := strings.ReplaceAll(name, "_", "-") expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)} android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category]) } - android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths) - android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/metadata.csv"}, info.MetadataPaths) - android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/index.csv"}, info.IndexPaths) + android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths) + android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/metadata.csv"}, info.MetadataPaths) + android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/index.csv"}, info.IndexPaths) - android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) - android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) } // TestPlatformBootclasspath_LegacyPrebuiltFragment verifies that the @@ -234,7 +236,7 @@ func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) { ) pbcp := result.Module("myplatform-bootclasspath", "android_common") - info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo) + info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider) android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) @@ -252,6 +254,11 @@ func TestPlatformBootclasspathDependencies(t *testing.T) { java.FixtureWithLastReleaseApis("foo"), java.PrepareForTestWithDexpreopt, dexpreopt.FixtureDisableDexpreoptBootImages(false), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildFlags = map[string]string{ + "RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true", + } + }), ).RunTestWithBp(t, ` apex { name: "com.android.art", @@ -382,11 +389,14 @@ func TestPlatformBootclasspathDependencies(t *testing.T) { // Make sure that the myplatform-bootclasspath has the correct dependencies. CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ + // source vs prebuilt selection metadata module + `platform:all_apex_contributions`, + // The following are stubs. - `platform:android_stubs_current`, - `platform:android_system_stubs_current`, - `platform:android_test_stubs_current`, - `platform:legacy.core.platform.api.stubs`, + `platform:android_stubs_current_exportable`, + `platform:android_system_stubs_current_exportable`, + `platform:android_test_stubs_current_exportable`, + `platform:legacy.core.platform.api.stubs.exportable`, // Needed for generating the boot image. `platform:dex2oatd`, @@ -419,6 +429,9 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { java.PrepareForTestWithJavaSdkLibraryFiles, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) + variables.BuildFlags = map[string]string{ + "RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true", + } }), java.FixtureWithPrebuiltApis(map[string][]string{ "current": {}, @@ -534,13 +547,16 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { // Make sure that the myplatform-bootclasspath has the correct dependencies. CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ + // source vs prebuilt selection metadata module + `platform:all_apex_contributions`, + // The following are stubs. "platform:prebuilt_sdk_public_current_android", "platform:prebuilt_sdk_system_current_android", "platform:prebuilt_sdk_test_current_android", // Not a prebuilt as no prebuilt existed when it was added. - "platform:legacy.core.platform.api.stubs", + "platform:legacy.core.platform.api.stubs.exportable", // The platform_bootclasspath intentionally adds dependencies on both source and prebuilt // modules when available as it does not know which one will be preferred. diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 7d339d54e..cebbae9a6 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -22,6 +22,7 @@ import ( "strings" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java" "android/soong/provenance" @@ -50,6 +51,7 @@ type prebuilt interface { type prebuiltCommon struct { android.ModuleBase + java.Dexpreopter prebuilt android.Prebuilt // Properties common to both prebuilt_apex and apex_set. @@ -85,6 +87,12 @@ type PrebuiltCommonProperties struct { // device (/apex/<apex_name>). If unspecified, follows the name property. Apex_name *string + // Name of the source APEX that gets shadowed by this prebuilt + // e.g. com.mycompany.android.myapex + // If unspecified, follows the naming convention that the source apex of + // the prebuilt is Name() without "prebuilt_" prefix + Source_apex_name *string + ForceDisable bool `blueprint:"mutated"` // whether the extracted apex file is installable. @@ -124,7 +132,11 @@ func (p *prebuiltCommon) initPrebuiltCommon(module android.Module, properties *P } func (p *prebuiltCommon) ApexVariationName() string { - return proptools.StringDefault(p.prebuiltCommonProperties.Apex_name, p.ModuleBase.BaseModuleName()) + return proptools.StringDefault(p.prebuiltCommonProperties.Apex_name, p.BaseModuleName()) +} + +func (p *prebuiltCommon) BaseModuleName() string { + return proptools.StringDefault(p.prebuiltCommonProperties.Source_apex_name, p.ModuleBase.BaseModuleName()) } func (p *prebuiltCommon) Prebuilt() *android.Prebuilt { @@ -170,50 +182,46 @@ func (p *prebuiltCommon) installable() bool { return proptools.BoolDefault(p.prebuiltCommonProperties.Installable, true) } -// initApexFilesForAndroidMk initializes the prebuiltCommon.apexFilesForAndroidMk field from the -// modules that this depends upon. +// To satisfy java.DexpreopterInterface +func (p *prebuiltCommon) IsInstallable() bool { + return p.installable() +} + +// initApexFilesForAndroidMk initializes the prebuiltCommon.requiredModuleNames field with the install only deps of the prebuilt apex func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) { - // Walk the dependencies of this module looking for the java modules that it exports. - ctx.WalkDeps(func(child, parent android.Module) bool { - tag := ctx.OtherModuleDependencyTag(child) + // If this apex contains a system server jar, then the dexpreopt artifacts should be added as required + for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() { + p.requiredModuleNames = append(p.requiredModuleNames, install.FullModuleName()) + } +} - name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) - if java.IsBootclasspathFragmentContentDepTag(tag) || - java.IsSystemServerClasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag { - // If the exported java module provides a dex jar path then add it to the list of apexFiles. - path := child.(interface { - DexJarBuildPath() java.OptionalDexJarPath - }).DexJarBuildPath() - if path.IsSet() { - af := apexFile{ - module: child, - moduleDir: ctx.OtherModuleDir(child), - androidMkModuleName: name, - builtFile: path.Path(), - class: javaSharedLib, - } - if module, ok := child.(java.DexpreopterInterface); ok { - for _, install := range module.DexpreoptBuiltInstalledForApex() { - af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName()) - } - } - p.apexFilesForAndroidMk = append(p.apexFilesForAndroidMk, af) - } - } else if tag == exportedBootclasspathFragmentTag { - _, ok := child.(*java.PrebuiltBootclasspathFragmentModule) - if !ok { - ctx.PropertyErrorf("exported_bootclasspath_fragments", "%q is not a prebuilt_bootclasspath_fragment module", name) - return false - } - // Visit the children of the bootclasspath_fragment. - return true - } else if tag == exportedSystemserverclasspathFragmentTag { - // Visit the children of the systemserver_fragment. - return true +// If this prebuilt has system server jar, create the rules to dexpreopt it and install it alongside the prebuilt apex +func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) { + // If this apex does not export anything, return + if !p.hasExportedDeps() { + return + } + // If this prebuilt apex has not been selected, return + if p.IsHideFromMake() { + return + } + // Use apex_name to determine the api domain of this prebuilt apex + apexName := p.ApexVariationName() + di, err := android.FindDeapexerProviderForModule(ctx) + if err != nil { + ctx.ModuleErrorf(err.Error()) + } + dc := dexpreopt.GetGlobalConfig(ctx) + systemServerJarList := dc.AllApexSystemServerJars(ctx) + + for i := 0; i < systemServerJarList.Len(); i++ { + sscpApex := systemServerJarList.Apex(i) + sscpJar := systemServerJarList.Jar(i) + if apexName != sscpApex { + continue } - - return false - }) + p.Dexpreopter.DexpreoptPrebuiltApexSystemServerJars(ctx, sscpJar, di) + } } func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) { @@ -232,6 +240,7 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries { OutputFile: android.OptionalPathForPath(p.outputApex), Include: "$(BUILD_PREBUILT)", Host_required: p.hostRequired, + OverrideName: p.BaseModuleName(), ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetString("LOCAL_MODULE_PATH", p.installDir.String()) @@ -248,6 +257,11 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries { }, } + // Add the dexpreopt artifacts to androidmk + for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() { + entriesList = append(entriesList, install.ToMakeEntries()) + } + // Iterate over the apexFilesForAndroidMk list and create an AndroidMkEntries struct for each // file. This provides similar behavior to that provided in apexBundle.AndroidMk() as it makes the // apex specific variants of the exported java modules available for use from within make. @@ -428,7 +442,7 @@ func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) { // Create contents for the prebuilt_apex and store it away for later use. apexContents := android.NewApexContents(contents) - mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{ + android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{ Contents: apexContents, }) @@ -437,7 +451,7 @@ func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) { apexInfo := android.ApexInfo{ ApexVariationName: apexVariationName, InApexVariants: []string{apexVariationName}, - InApexModules: []string{p.ModuleBase.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix. + InApexModules: []string{p.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix. ApexContents: []*android.ApexContents{apexContents}, ForPrebuiltApex: true, } @@ -484,6 +498,9 @@ type Prebuilt struct { inputApex android.Path provenanceMetaDataFile android.OutputPath + + // Single aconfig "cache file" merged from this module and all dependencies. + mergedAconfigFiles map[string]android.Paths } type ApexFileProperties struct { @@ -612,6 +629,7 @@ func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutator // Compute the deapexer properties from the transitive dependencies of this module. commonModules := []string{} + dexpreoptProfileGuidedModules := []string{} exportedFiles := []string{} ctx.WalkDeps(func(child, parent android.Module) bool { tag := ctx.OtherModuleDependencyTag(child) @@ -621,13 +639,18 @@ func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutator return false } - name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) + name := java.ModuleStemForDeapexing(child) if _, ok := tag.(android.RequiresFilesFromPrebuiltApexTag); ok { commonModules = append(commonModules, name) - requiredFiles := child.(android.RequiredFilesFromPrebuiltApex).RequiredFilesFromPrebuiltApex(ctx) + extract := child.(android.RequiredFilesFromPrebuiltApex) + requiredFiles := extract.RequiredFilesFromPrebuiltApex(ctx) exportedFiles = append(exportedFiles, requiredFiles...) + if extract.UseProfileGuidedDexpreopt() { + dexpreoptProfileGuidedModules = append(dexpreoptProfileGuidedModules, name) + } + // Visit the dependencies of this module just in case they also require files from the // prebuilt apex. return true @@ -640,7 +663,8 @@ func (p *prebuiltCommon) createDeapexerModuleIfNeeded(ctx android.TopDownMutator deapexerProperties := &DeapexerProperties{ // Remove any duplicates from the common modules lists as a module may be included via a direct // dependency as well as transitive ones. - CommonModules: android.SortedUniqueStrings(commonModules), + CommonModules: android.SortedUniqueStrings(commonModules), + DexpreoptProfileGuidedModules: android.SortedUniqueStrings(dexpreoptProfileGuidedModules), } // Populate the exported files property in a fixed order. @@ -740,13 +764,11 @@ var _ prebuiltApexModuleCreator = (*Prebuilt)(nil) // V V V // selector <--- deapexer <--- exported java lib func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) { - baseModuleName := p.BaseModuleName() - - apexSelectorModuleName := apexSelectorModuleName(baseModuleName) + apexSelectorModuleName := apexSelectorModuleName(p.Name()) createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties) apexFileSource := ":" + apexSelectorModuleName - p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource) + p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(p.Name()), apexFileSource) // Add a source reference to retrieve the selected apex from the selector module. p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource) @@ -756,12 +778,47 @@ func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { p.prebuiltApexContentsDeps(ctx) } +func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) { + if p.hasExportedDeps() { + // Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module + // The deapexer will return a provider that will be bubbled up to the rdeps of apexes (e.g. dex_bootjars) + ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.Name())) + } +} + var _ ApexInfoMutator = (*Prebuilt)(nil) func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) { p.apexInfoMutator(mctx) } +// Set a provider containing information about the jars and .prof provided by the apex +// Apexes built from prebuilts retrieve this information by visiting its internal deapexer module +// Used by dex_bootjars to generate the boot image +func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext) { + if !p.hasExportedDeps() { + // nothing to do + return + } + if di, err := android.FindDeapexerProviderForModule(ctx); err == nil { + javaModuleToDexPath := map[string]android.Path{} + for _, commonModule := range di.GetExportedModuleNames() { + if dex := di.PrebuiltExportPath(java.ApexRootRelativePathToJavaLib(commonModule)); dex != nil { + javaModuleToDexPath[commonModule] = dex + } + } + + exports := android.ApexExportsInfo{ + ApexName: p.ApexVariationName(), + ProfilePathOnHost: di.PrebuiltExportPath(java.ProfileInstallPathInApex), + LibraryNameToDexJarPathOnHost: javaModuleToDexPath, + } + android.SetProvider(ctx, android.ApexExportsInfoProvider, exports) + } else { + ctx.ModuleErrorf(err.Error()) + } +} + func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.apexKeysPath = writeApexKeys(ctx, p) // TODO(jungjw): Check the key validity. @@ -783,6 +840,12 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } + // dexpreopt any system server jars if present + p.dexpreoptSystemServerJars(ctx) + + // provide info used for generating the boot image + p.provideApexExportsInfo(ctx) + // Save the files that need to be made available to Make. p.initApexFilesForAndroidMk(ctx) @@ -797,6 +860,8 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks...) p.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, p.inputApex, p.installedFile) } + + android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles) } func (p *Prebuilt) ProvenanceMetaDataFile() android.OutputPath { @@ -957,13 +1022,11 @@ var _ prebuiltApexModuleCreator = (*ApexSet)(nil) // from those provided this creates an extractor module which extracts the appropriate .apex file // from the zip file containing them. func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) { - baseModuleName := a.BaseModuleName() - - apexExtractorModuleName := apexExtractorModuleName(baseModuleName) + apexExtractorModuleName := apexExtractorModuleName(a.Name()) createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties) apexFileSource := ":" + apexExtractorModuleName - a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource) + a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(a.Name()), apexFileSource) // After passing the arch specific src properties to the creating the apex selector module a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource) @@ -999,6 +1062,12 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } + // dexpreopt any system server jars if present + a.dexpreoptSystemServerJars(ctx) + + // provide info used for generating the boot image + a.provideApexExportsInfo(ctx) + // Save the files that need to be made available to Make. a.initApexFilesForAndroidMk(ctx) diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go index 40d05814e..f6c53b270 100644 --- a/apex/systemserver_classpath_fragment_test.go +++ b/apex/systemserver_classpath_fragment_test.go @@ -106,6 +106,7 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) { }) java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{ + `dex2oatd`, `myapex.key`, `mysystemserverclasspathfragment`, }) @@ -162,6 +163,7 @@ func TestSystemserverclasspathFragmentNoGeneratedProto(t *testing.T) { }) java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{ + `dex2oatd`, `myapex.key`, `mysystemserverclasspathfragment`, }) @@ -272,24 +274,26 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) { ctx := result.TestContext java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{ - `myapex.apex.selector`, + `dex2oatd`, + `prebuilt_myapex.apex.selector`, + `prebuilt_myapex.deapexer`, `prebuilt_mysystemserverclasspathfragment`, }) java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{ - `myapex.deapexer`, `prebuilt_bar`, `prebuilt_foo`, + `prebuilt_myapex.deapexer`, }) - ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{ + ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{ "javalib/foo.jar", "javalib/bar.jar", "javalib/bar.jar.prof", }) - assertProfileGuided(t, ctx, "foo", "android_common_myapex", false) - assertProfileGuided(t, ctx, "bar", "android_common_myapex", true) + assertProfileGuidedPrebuilt(t, ctx, "myapex", "foo", false) + assertProfileGuidedPrebuilt(t, ctx, "myapex", "bar", true) } func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) { @@ -428,19 +432,19 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) { ctx := result.TestContext java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{ - `myapex.deapexer`, `prebuilt_bar`, `prebuilt_foo`, + `prebuilt_myapex.deapexer`, }) - ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{ + ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{ "javalib/foo.jar", "javalib/bar.jar", "javalib/bar.jar.prof", }) - assertProfileGuided(t, ctx, "foo", "android_common_myapex", false) - assertProfileGuided(t, ctx, "bar", "android_common_myapex", true) + assertProfileGuidedPrebuilt(t, ctx, "myapex", "foo", false) + assertProfileGuidedPrebuilt(t, ctx, "myapex", "bar", true) } func assertProfileGuided(t *testing.T, ctx *android.TestContext, moduleName string, variant string, expected bool) { @@ -450,3 +454,11 @@ func assertProfileGuided(t *testing.T, ctx *android.TestContext, moduleName stri t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual) } } + +func assertProfileGuidedPrebuilt(t *testing.T, ctx *android.TestContext, apexName string, moduleName string, expected bool) { + dexpreopt := ctx.ModuleForTests(apexName, "android_common_"+apexName).Rule("dexpreopt." + moduleName) + actual := strings.Contains(dexpreopt.RuleParams.Command, "--profile-file=") + if expected != actual { + t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual) + } +} diff --git a/apex/vndk.go b/apex/vndk.go index 26c60edc8..377c1c014 100644 --- a/apex/vndk.go +++ b/apex/vndk.go @@ -65,24 +65,27 @@ func apexVndkMutator(mctx android.TopDownMutatorContext) { } vndkVersion := ab.vndkVersion(mctx.DeviceConfig()) - apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion) - if err != nil { - mctx.PropertyErrorf("vndk_version", "%s", err.Error()) - return - } - - targets := mctx.MultiTargets() - if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) && - vndkVersion != mctx.DeviceConfig().PlatformVndkVersion() { - // Disable VNDK APEXes for VNDK versions less than the minimum supported API - // level for the primary architecture. This validation is skipped if the VNDK - // version matches the platform VNDK version, which can occur when the device - // config targets the 'current' VNDK (see `vndkVersion`). - ab.Disable() - } - if proptools.String(ab.vndkProperties.Vndk_version) != "" && - apiLevel.GreaterThanOrEqualTo(android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())) { - ab.Disable() + if vndkVersion != "" { + apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion) + if err != nil { + mctx.PropertyErrorf("vndk_version", "%s", err.Error()) + return + } + + targets := mctx.MultiTargets() + if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) && + vndkVersion != mctx.DeviceConfig().PlatformVndkVersion() { + // Disable VNDK APEXes for VNDK versions less than the minimum supported API + // level for the primary architecture. This validation is skipped if the VNDK + // version matches the platform VNDK version, which can occur when the device + // config targets the 'current' VNDK (see `vndkVersion`). + ab.Disable() + } + if proptools.String(ab.vndkProperties.Vndk_version) != "" && + mctx.DeviceConfig().PlatformVndkVersion() != "" && + apiLevel.GreaterThanOrEqualTo(android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())) { + ab.Disable() + } } } } @@ -94,6 +97,11 @@ func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) { if vndkVersion == "" { vndkVersion = mctx.DeviceConfig().PlatformVndkVersion() } + + if vndkVersion == "" { + return + } + if vndkVersion == mctx.DeviceConfig().PlatformVndkVersion() { vndkVersion = "current" } else { diff --git a/apex/vndk_test.go b/apex/vndk_test.go index e2aee96e7..894aece9d 100644 --- a/apex/vndk_test.go +++ b/apex/vndk_test.go @@ -8,66 +8,6 @@ import ( "android/soong/android" ) -func TestVndkApexForVndkLite(t *testing.T) { - ctx := testApex(t, ` - apex_vndk { - name: "com.android.vndk.current", - key: "com.android.vndk.current.key", - updatable: false, - } - - apex_key { - name: "com.android.vndk.current.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - cc_library { - name: "libvndk", - srcs: ["mylib.cpp"], - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - }, - system_shared_libs: [], - stl: "none", - apex_available: [ "com.android.vndk.current" ], - } - - cc_library { - name: "libvndksp", - srcs: ["mylib.cpp"], - vendor_available: true, - product_available: true, - vndk: { - enabled: true, - support_system_process: true, - }, - system_shared_libs: [], - stl: "none", - apex_available: [ "com.android.vndk.current" ], - } - `+vndkLibrariesTxtFiles("current"), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.DeviceVndkVersion = proptools.StringPtr("") - variables.KeepVndk = proptools.BoolPtr(true) - }), - ) - // VNDK-Lite contains only core variants of VNDK-Sp libraries - ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{ - "lib/libvndksp.so", - "lib/libc++.so", - "lib64/libvndksp.so", - "lib64/libc++.so", - "etc/llndk.libraries.29.txt", - "etc/vndkcore.libraries.29.txt", - "etc/vndksp.libraries.29.txt", - "etc/vndkprivate.libraries.29.txt", - "etc/vndkproduct.libraries.29.txt", - }) -} - func TestVndkApexUsesVendorVariant(t *testing.T) { bp := ` apex_vndk { |
