Refactor dexpreopt for boot jars to make it flexible to config changes.

In the past, dexpreopt for boot jars was very inflexible, and it was
incredibly hard to make a change that is as simple as adding a jar to a
boot image. Boot image generation was handled by
"platform_bootclasspath" and "bootclasspath_fragment" separately. This
caused not only code duplication but also the inflexiblity as such a
design did not fit today's use cases, where a boot image may take jars
from multiple mainline modules and the platform, and a mainline module
can contribute to multiple boot images. The design casued a huge
maintenance burden as any change to the boot image cost multi-week
efforts.

In recent years, efforts have been made to improve this a bit by a bit.
This change is another step towards making dexpreopt reasonable.

After this change, all boot images are generated by "dex_bootjars",
which is in build/soong and is therefore available on both the full
source tree and the thin manifest (master-art). The change decouples
profile generation/extraction from boot image generation. Profiles for
mainline modules are still handled by "bootclasspath_fragment"
because they need to be packed into APEXes when building mainline
modules and extracted from APEXes whem building the system image from
prebuilt modules. Boot images are not handled by
"bootclasspath_fragment" anymore.

Bug: 290583827
Test: m (all existing tests are still passing)
Test: Manually checked that the boot images are exactly the same as
  before.
Change-Id: Ib5a5f401bee334ffcab5c26618e0c8888b84575a
This commit is contained in:
Jiakai Zhang 2023-07-13 11:03:38 +01:00
parent e3c11d0aad
commit cb13b5d1bd
10 changed files with 385 additions and 395 deletions

View file

@ -315,7 +315,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
// Make sure that the source bootclasspath_fragment copies its dex files to the predefined // Make sure that the source bootclasspath_fragment copies its dex files to the predefined
// locations for the art image. // locations for the art image.
module := result.ModuleForTests("art-bootclasspath-fragment", "android_common_apex10000") module := result.ModuleForTests("dex_bootjars", "android_common")
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
}) })
@ -386,7 +386,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
// Make sure that the prebuilt bootclasspath_fragment copies its dex files to the predefined // Make sure that the prebuilt bootclasspath_fragment copies its dex files to the predefined
// locations for the art image. // locations for the art image.
module := result.ModuleForTests("prebuilt_art-bootclasspath-fragment", "android_common_com.android.art") module := result.ModuleForTests("dex_bootjars", "android_common")
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
}) })
@ -537,7 +537,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
`prebuilt_foo`, `prebuilt_foo`,
}) })
module := result.ModuleForTests("art-bootclasspath-fragment", "android_common_com.android.art") module := result.ModuleForTests("dex_bootjars", "android_common")
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
}) })

View file

@ -138,8 +138,8 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu
prepareForTestWithArtApex, prepareForTestWithArtApex,
).RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt)) ).RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt))
platformBootclasspath := result.ModuleForTests("platform-bootclasspath", "android_common") dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
rule := platformBootclasspath.Output(ruleFile) rule := dexBootJars.Output(ruleFile)
inputs := rule.Implicits.Strings() inputs := rule.Implicits.Strings()
sort.Strings(inputs) sort.Strings(inputs)
@ -162,8 +162,8 @@ func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) {
"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar", "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/bar.jar",
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
"out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art/boot.prof", "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
"out/soong/.intermediates/platform-bootclasspath/android_common/boot/boot.prof", "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
} }
expectedOutputs := []string{ expectedOutputs := []string{
@ -200,7 +200,7 @@ func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) {
"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar", "out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.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/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
"out/soong/.intermediates/platform-bootclasspath/android_common/boot/boot.prof", "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
} }
expectedOutputs := []string{ expectedOutputs := []string{

View file

@ -185,6 +185,9 @@ var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathDependencyTag{}
// The tag used for dependencies onto bootclasspath_fragments. // The tag used for dependencies onto bootclasspath_fragments.
var bootclasspathFragmentDepTag = bootclasspathDependencyTag{name: "fragment"} var bootclasspathFragmentDepTag = bootclasspathDependencyTag{name: "fragment"}
// The tag used for dependencies onto platform_bootclasspath.
var platformBootclasspathDepTag = bootclasspathDependencyTag{name: "platform"}
// BootclasspathNestedAPIProperties defines properties related to the API provided by parts of the // BootclasspathNestedAPIProperties defines properties related to the API provided by parts of the
// bootclasspath that are nested within the main BootclasspathAPIProperties. // bootclasspath that are nested within the main BootclasspathAPIProperties.
type BootclasspathNestedAPIProperties struct { type BootclasspathNestedAPIProperties struct {

View file

@ -242,7 +242,7 @@ type BootclasspathFragmentModule struct {
modulePaths []string modulePaths []string
// Path to the boot image profile. // Path to the boot image profile.
profilePath android.Path profilePath android.WritablePath
} }
// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt // commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
@ -256,16 +256,6 @@ type commonBootclasspathFragment interface {
// versioned sdk. // versioned sdk.
produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
// produceBootImageFiles will attempt to produce rules to create the boot image files at the paths
// predefined in the bootImageConfig.
//
// If it could not create the files then it will return nil. Otherwise, it will return a map from
// android.ArchType to the predefined paths of the boot image files.
produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs
// getImageName returns the `image_name` property of this fragment.
getImageName() *string
// getProfilePath returns the path to the boot image profile. // getProfilePath returns the path to the boot image profile.
getProfilePath() android.Path getProfilePath() android.Path
} }
@ -295,9 +285,6 @@ func bootclasspathFragmentFactory() android.Module {
return return
} }
} }
// Initialize the contents property from the image_name.
bootclasspathFragmentInitContentsFromImage(ctx, m)
}) })
return m return m
} }
@ -308,9 +295,7 @@ func testBootclasspathFragmentFactory() android.Module {
return m return m
} }
// bootclasspathFragmentInitContentsFromImage will initialize the contents property from the image_name if func (m *BootclasspathFragmentModule) bootclasspathFragmentPropertyCheck(ctx android.EarlyModuleContext) {
// necessary.
func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) {
contents := m.properties.Contents contents := m.properties.Contents
if len(contents) == 0 { if len(contents) == 0 {
ctx.PropertyErrorf("contents", "required property is missing") ctx.PropertyErrorf("contents", "required property is missing")
@ -332,6 +317,18 @@ func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext,
// too early in the Soong processing for that to work. // too early in the Soong processing for that to work.
global := dexpreopt.GetGlobalConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx)
modules := global.ArtApexJars modules := global.ArtApexJars
configuredJars := modules.CopyOfJars()
// Skip the check if the configured jars list is empty as that is a common configuration when
// building targets that do not result in a system image.
if len(configuredJars) == 0 {
return
}
if !reflect.DeepEqual(configuredJars, contents) {
ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v",
configuredJars, contents)
}
// Make sure that the apex specified in the configuration is consistent and is one for which // Make sure that the apex specified in the configuration is consistent and is one for which
// this boot image is available. // this boot image is available.
@ -357,33 +354,6 @@ func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext,
} }
} }
// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this
// module (if any) matches the contents.
//
// This should be a noop as if image_name="art" then the contents will be set from the ArtApexJars
// config by bootclasspathFragmentInitContentsFromImage so it will be guaranteed to match. However,
// in future this will not be the case.
func (b *BootclasspathFragmentModule) bootclasspathImageNameContentsConsistencyCheck(ctx android.BaseModuleContext) {
imageName := proptools.String(b.properties.Image_name)
if imageName == "art" {
// Get the configuration for the art apex jars.
modules := b.getImageConfig(ctx).modules
configuredJars := modules.CopyOfJars()
// Skip the check if the configured jars list is empty as that is a common configuration when
// building targets that do not result in a system image.
if len(configuredJars) == 0 {
return
}
contents := b.properties.Contents
if !reflect.DeepEqual(configuredJars, contents) {
ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v",
configuredJars, contents)
}
}
}
var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{}) var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{})
// BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
@ -495,7 +465,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
// unused prebuilt that was created without instrumentation from breaking an instrumentation // unused prebuilt that was created without instrumentation from breaking an instrumentation
// build. // build.
if isActiveModule(ctx.Module()) { if isActiveModule(ctx.Module()) {
b.bootclasspathImageNameContentsConsistencyCheck(ctx) b.bootclasspathFragmentPropertyCheck(ctx)
} }
// Generate classpaths.proto config // Generate classpaths.proto config
@ -515,34 +485,15 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
// Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
// prebuilt which will not use the image config.
imageConfig := b.getImageConfig(ctx)
// Perform hidden API processing. // Perform hidden API processing.
hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
var bootImageFiles bootImageOutputs if android.IsModulePrebuilt(ctx.Module()) {
if imageConfig != nil { b.profilePath = ctx.Module().(*PrebuiltBootclasspathFragmentModule).produceBootImageProfile(ctx)
// Delegate the production of the boot image files to a module type specific method. } else {
common := ctx.Module().(commonBootclasspathFragment) b.profilePath = b.produceBootImageProfileFromSource(ctx, contents, hiddenAPIOutput.EncodedBootDexFilesByModule)
bootImageFiles = common.produceBootImageFiles(ctx, imageConfig) // Provide the apex content info. A prebuilt fragment cannot contribute to an apex.
b.profilePath = bootImageFiles.profile b.provideApexContentInfo(ctx, hiddenAPIOutput, b.profilePath)
if shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
// Zip the boot image files up, if available. This will generate the zip file in a
// predefined location.
buildBootImageZipInPredefinedLocation(ctx, imageConfig, bootImageFiles.byArch)
// Copy the dex jars of this fragment's content modules to their predefined locations.
copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule)
}
}
// A prebuilt fragment cannot contribute to an apex.
if !android.IsModulePrebuilt(ctx.Module()) {
// Provide the apex content info.
b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFiles)
} }
// In order for information about bootclasspath_fragment modules to be added to module-info.json // In order for information about bootclasspath_fragment modules to be added to module-info.json
@ -556,44 +507,37 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
} }
} }
// shouldCopyBootFilesToPredefinedLocations determines whether the current module should copy boot // getProfileProviderApex returns the name of the apex that provides a boot image profile, or an
// files, e.g. boot dex jars or boot image files, to the predefined location expected by the rest // empty string if this module should not provide a boot image profile.
// of the build. func (b *BootclasspathFragmentModule) getProfileProviderApex(ctx android.BaseModuleContext) string {
// // Only use the profile from the module that is preferred.
// This ensures that only a single module will copy its files to the image configuration. if !isActiveModule(ctx.Module()) {
func shouldCopyBootFilesToPredefinedLocations(ctx android.ModuleContext, imageConfig *bootImageConfig) bool { return ""
}
// Bootclasspath fragment modules that are for the platform do not produce boot related files. // Bootclasspath fragment modules that are for the platform do not produce boot related files.
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
if apexInfo.IsForPlatform() { for _, apex := range apexInfo.InApexVariants {
return false if isProfileProviderApex(ctx, apex) {
return apex
}
} }
// If the image configuration has no modules specified then it means that the build has been return ""
// configured to build something other than a boot image, e.g. an sdk, so do not try and copy the
// files.
if imageConfig.modules.Len() == 0 {
return false
}
// Only copy files from the module that is preferred.
return isActiveModule(ctx.Module())
} }
// provideApexContentInfo creates, initializes and stores the apex content info for use by other // provideApexContentInfo creates, initializes and stores the apex content info for use by other
// modules. // modules.
func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFiles bootImageOutputs) { func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, hiddenAPIOutput *HiddenAPIOutput, profile android.WritablePath) {
// Construct the apex content info from the config. // Construct the apex content info from the config.
info := BootclasspathFragmentApexContentInfo{ info := BootclasspathFragmentApexContentInfo{
// Populate the apex content info with paths to the dex jars. // Populate the apex content info with paths to the dex jars.
contentModuleDexJarPaths: hiddenAPIOutput.EncodedBootDexFilesByModule, contentModuleDexJarPaths: hiddenAPIOutput.EncodedBootDexFilesByModule,
} }
if imageConfig != nil { if profile != nil {
global := dexpreopt.GetGlobalConfig(ctx) info.profilePathOnHost = profile
if !global.DisableGenerateProfile { info.profileInstallPathInApex = profileInstallPathInApex
info.profilePathOnHost = bootImageFiles.profile
info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
}
} }
// Make the apex content info available for other modules. // Make the apex content info available for other modules.
@ -614,12 +558,12 @@ func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx and
} }
func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList { func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
if "art" == proptools.String(b.properties.Image_name) {
return b.getImageConfig(ctx).modules
}
global := dexpreopt.GetGlobalConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx)
if "art" == proptools.String(b.properties.Image_name) {
return global.ArtApexJars
}
possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag) possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
jars, unknown := global.ApexBootJars.Filter(possibleUpdatableModules) jars, unknown := global.ApexBootJars.Filter(possibleUpdatableModules)
@ -645,25 +589,6 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext)
return jars return jars
} }
func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
// Get a map of the image configs that are supported.
imageConfigs := genBootImageConfigs(ctx)
// Retrieve the config for this image.
imageNamePtr := b.properties.Image_name
if imageNamePtr == nil {
return nil
}
imageName := *imageNamePtr
imageConfig := imageConfigs[imageName]
if imageConfig == nil {
ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedKeys(imageConfigs), ", "))
return nil
}
return imageConfig
}
// generateHiddenAPIBuildActions generates all the hidden API related build rules. // generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput { func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput {
@ -846,48 +771,22 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC
return output return output
} }
// produceBootImageFiles builds the boot image files from the source if it is required. // produceBootImageProfileFromSource builds the boot image profile from the source if it is required.
func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { func (b *BootclasspathFragmentModule) produceBootImageProfileFromSource(ctx android.ModuleContext, contents []android.Module, modules bootDexJarByModule) android.WritablePath {
// Only generate the boot image if the configuration does not skip it. apex := b.getProfileProviderApex(ctx)
return b.generateBootImageBuildActions(ctx, imageConfig) if apex == "" {
} return nil
// generateBootImageBuildActions generates ninja rules to create the boot image if required for this
// module.
//
// If it could not create the files then it will return nil. Otherwise, it will return a map from
// android.ArchType to the predefined paths of the boot image files.
func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs {
global := dexpreopt.GetGlobalConfig(ctx)
if !shouldBuildBootImages(ctx.Config(), global) {
return bootImageOutputs{}
} }
// Bootclasspath fragment modules that are for the platform do not produce a boot image. dexPaths := make(android.Paths, 0, len(contents))
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) dexLocations := make([]string, 0, len(contents))
if apexInfo.IsForPlatform() { for _, module := range contents {
return bootImageOutputs{} dexPaths = append(dexPaths, modules[module.Name()])
dexLocations = append(dexLocations, filepath.Join("/", "apex", apex, "javalib", module.Name() + ".jar"))
} }
// Build a profile for the image config and then use that to build the boot image. // Build a profile for the modules in this fragment.
profile := bootImageProfileRule(ctx, imageConfig) return bootImageProfileRuleCommon(ctx, b.Name(), dexPaths, dexLocations)
// If dexpreopt of boot image jars should be skipped, generate only a profile.
if SkipDexpreoptBootJars(ctx) {
return bootImageOutputs{
profile: profile,
}
}
// Build boot image files for the host variants.
buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
// Build boot image files for the android variants.
bootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
// Return the boot image files for the android variants for inclusion in an APEX and to be zipped
// up for the dist.
return bootImageFiles
} }
func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries { func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries {
@ -910,10 +809,6 @@ func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntr
return entriesList return entriesList
} }
func (b *BootclasspathFragmentModule) getImageName() *string {
return b.properties.Image_name
}
func (b *BootclasspathFragmentModule) getProfilePath() android.Path { func (b *BootclasspathFragmentModule) getProfilePath() android.Path {
return b.profilePath return b.profilePath
} }
@ -1183,39 +1078,19 @@ func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx an
return &output return &output
} }
// produceBootImageFiles extracts the boot image files from the APEX if available. // produceBootImageProfile extracts the boot image profile from the APEX if available.
func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs { func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx android.ModuleContext) android.WritablePath {
if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) { // This module does not provide a boot image profile.
return bootImageOutputs{} if module.getProfileProviderApex(ctx) == "" {
return nil
} }
di := android.FindDeapexerProviderForModule(ctx) di := android.FindDeapexerProviderForModule(ctx)
if di == nil { if di == nil {
return bootImageOutputs{} // An error has been reported by FindDeapexerProviderForModule. return nil // An error has been reported by FindDeapexerProviderForModule.
} }
profile := (android.WritablePath)(nil) return di.PrebuiltExportPath(profileInstallPathInApex)
if imageConfig.profileInstallPathInApex != "" {
profile = di.PrebuiltExportPath(imageConfig.profileInstallPathInApex)
}
// Build the boot image files for the host variants. These are always built from the dex files
// provided by the contents of this module as prebuilt versions of the host boot image files are
// not available, i.e. there is no host specific prebuilt apex containing them. This has to be
// built without a profile as the prebuilt modules do not provide a profile.
buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
if profile == nil && imageConfig.isProfileGuided() {
ctx.ModuleErrorf("Unable to produce boot image files: profiles not found in the prebuilt apex")
return bootImageOutputs{}
}
// Build boot image files for the android variants from the dex files provided by the contents
// of this module.
return buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
}
func (b *PrebuiltBootclasspathFragmentModule) getImageName() *string {
return b.properties.Image_name
} }
func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path { func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
@ -1230,14 +1105,10 @@ var _ commonBootclasspathFragment = (*PrebuiltBootclasspathFragmentModule)(nil)
// If there is no image config associated with this fragment then it returns nil. Otherwise, it // If there is no image config associated with this fragment then it returns nil. Otherwise, it
// returns the files that are listed in the image config. // returns the files that are listed in the image config.
func (module *PrebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string { func (module *PrebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
imageConfig := module.getImageConfig(ctx) for _, apex := range module.ApexProperties.Apex_available {
if imageConfig != nil { if isProfileProviderApex(ctx, apex) {
files := []string{} return []string{profileInstallPathInApex}
if imageConfig.profileInstallPathInApex != "" {
// Add the boot image profile.
files = append(files, imageConfig.profileInstallPathInApex)
} }
return files
} }
return nil return nil
} }
@ -1253,9 +1124,5 @@ func prebuiltBootclasspathFragmentFactory() android.Module {
android.InitApexModule(m) android.InitApexModule(m)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon) android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
// Initialize the contents property from the image_name.
android.AddLoadHook(m, func(ctx android.LoadHookContext) {
bootclasspathFragmentInitContentsFromImage(ctx, &m.BootclasspathFragmentModule)
})
return m return m
} }

View file

@ -16,7 +16,6 @@ package java
import ( import (
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"android/soong/android" "android/soong/android"
@ -224,6 +223,11 @@ var artApexNames = []string{
"com.google.android.art.testing", "com.google.android.art.testing",
} }
var (
dexpreoptBootJarDepTag = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"}
dexBootJarsFragmentsKey = android.NewOnceKey("dexBootJarsFragments")
)
func init() { func init() {
RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext) RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
} }
@ -241,6 +245,9 @@ type bootImageConfig struct {
// Image name (used in directory names and ninja rule names). // Image name (used in directory names and ninja rule names).
name string name string
// If the module with the given name exists, this config is enabled.
enabledIfExists string
// Basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}. // Basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}.
stem string stem string
@ -257,10 +264,6 @@ type bootImageConfig struct {
// the location is relative to "/". // the location is relative to "/".
installDir string installDir string
// Install path of the boot image profile if it needs to be installed in the APEX, or empty if not
// needed.
profileInstallPathInApex string
// A list of (location, jar) pairs for the Java modules in this image. // A list of (location, jar) pairs for the Java modules in this image.
modules android.ConfiguredJarList modules android.ConfiguredJarList
@ -296,10 +299,9 @@ type bootImageConfig struct {
// The "--single-image" argument. // The "--single-image" argument.
singleImage bool singleImage bool
// Profiles imported from other boot image configs. Each element must represent a // Profiles imported from APEXes, in addition to the profile at the default path. Each entry must
// `bootclasspath_fragment` of an APEX (i.e., the `name` field of each element must refer to the // be the name of an APEX module.
// `image_name` property of a `bootclasspath_fragment`). profileImports []string
profileImports []*bootImageConfig
} }
// Target-dependent description of a boot image. // Target-dependent description of a boot image.
@ -458,18 +460,26 @@ func (image *bootImageConfig) isProfileGuided() bool {
return image.compilerFilter == "speed-profile" return image.compilerFilter == "speed-profile"
} }
func (image *bootImageConfig) isEnabled(ctx android.BaseModuleContext) bool {
return ctx.OtherModuleExists(image.enabledIfExists)
}
func dexpreoptBootJarsFactory() android.SingletonModule { func dexpreoptBootJarsFactory() android.SingletonModule {
m := &dexpreoptBootJars{} m := &dexpreoptBootJars{}
android.InitAndroidModule(m) android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
return m return m
} }
func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory) ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator).Parallel()
})
} }
func SkipDexpreoptBootJars(ctx android.PathContext) bool { func SkipDexpreoptBootJars(ctx android.PathContext) bool {
return dexpreopt.GetGlobalConfig(ctx).DisablePreoptBootImages global := dexpreopt.GetGlobalConfig(ctx)
return global.DisablePreoptBootImages || !shouldBuildBootImages(ctx.Config(), global)
} }
// Singleton module for generating boot image build rules. // Singleton module for generating boot image build rules.
@ -492,38 +502,90 @@ type dexpreoptBootJars struct {
dexpreoptConfigForMake android.WritablePath dexpreoptConfigForMake android.WritablePath
} }
// Provide paths to boot images for use by modules that depend upon them. func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) {
// if _, ok := ctx.Module().(*dexpreoptBootJars); !ok {
// The build rules are created in GenerateSingletonBuildActions(). return
func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) { }
// Placeholder for now.
if dexpreopt.IsDex2oatNeeded(ctx) {
// Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
// path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
dexpreopt.RegisterToolDeps(ctx)
}
imageConfigs := genBootImageConfigs(ctx)
for _, config := range imageConfigs {
if !config.isEnabled(ctx) {
continue
}
// For accessing the boot jars.
addDependenciesOntoBootImageModules(ctx, config.modules, dexpreoptBootJarDepTag)
}
if ctx.OtherModuleExists("platform-bootclasspath") {
// For accessing all bootclasspath fragments.
addDependencyOntoApexModulePair(ctx, "platform", "platform-bootclasspath", platformBootclasspathDepTag)
} else if ctx.OtherModuleExists("art-bootclasspath-fragment") {
// For accessing the ART bootclasspath fragment on a thin manifest (e.g., master-art) where
// platform-bootclasspath doesn't exist.
addDependencyOntoApexModulePair(ctx, "com.android.art", "art-bootclasspath-fragment", bootclasspathFragmentDepTag)
}
} }
// Generate build rules for boot images. func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.Module {
func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) { return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} {
if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil { fragments := make(map[string]android.Module)
// No module has enabled dexpreopting, so we assume there will be no boot image to make. ctx.WalkDeps(func(child, parent android.Module) bool {
return if !isActiveModule(child) {
} return false
d.dexpreoptConfigForMake = android.PathForOutput(ctx, getDexpreoptDirName(ctx), "dexpreopt.config") }
writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake) tag := ctx.OtherModuleDependencyTag(child)
if tag == platformBootclasspathDepTag {
return true
}
if tag == bootclasspathFragmentDepTag {
apexInfo := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
for _, apex := range apexInfo.InApexVariants {
fragments[apex] = child
}
return false
}
return false
})
return fragments
}).(map[string]android.Module)
}
global := dexpreopt.GetGlobalConfig(ctx) func getBootclasspathFragmentByApex(ctx android.ModuleContext, apexName string) android.Module {
if !shouldBuildBootImages(ctx.Config(), global) { return gatherBootclasspathFragments(ctx)[apexName]
return }
}
defaultImageConfig := defaultBootImageConfig(ctx) // GenerateAndroidBuildActions generates the build rules for boot images.
d.defaultBootImage = defaultImageConfig func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) {
imageConfigs := genBootImageConfigs(ctx) imageConfigs := genBootImageConfigs(ctx)
d.defaultBootImage = defaultBootImageConfig(ctx)
d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1) d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1)
for _, config := range imageConfigs { for _, name := range getImageNames() {
if config != defaultImageConfig { config := imageConfigs[name]
if config != d.defaultBootImage {
d.otherImages = append(d.otherImages, config) d.otherImages = append(d.otherImages, config)
} }
if !config.isEnabled(ctx) {
continue
}
generateBootImage(ctx, config)
if config == d.defaultBootImage {
bootFrameworkProfileRule(ctx, config)
}
} }
} }
// GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) {
d.dexpreoptConfigForMake = android.PathForOutput(ctx, getDexpreoptDirName(ctx), "dexpreopt.config")
writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
}
// shouldBuildBootImages determines whether boot images should be built. // shouldBuildBootImages determines whether boot images should be built.
func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig) bool { func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig) bool {
// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths // Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
@ -536,6 +598,101 @@ func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig
return true return true
} }
func generateBootImage(ctx android.ModuleContext, imageConfig *bootImageConfig) {
apexJarModulePairs := getModulesForImage(ctx, imageConfig)
// Copy module dex jars to their predefined locations.
bootDexJarsByModule := extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx, apexJarModulePairs)
copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule)
// Build a profile for the image config from the profile at the default path. The profile will
// then be used along with profiles imported from APEXes to build the boot image.
profile := bootImageProfileRule(ctx, imageConfig)
// If dexpreopt of boot image jars should be skipped, stop after generating a profile.
if SkipDexpreoptBootJars(ctx) {
return
}
// Build boot image files for the android variants.
androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
// Zip the android variant boot image files up.
buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch)
// Build boot image files for the host variants. There are use directly by ART host side tests.
buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
// Create a `dump-oat-<image-name>` rule that runs `oatdump` for debugging purposes.
dumpOatRules(ctx, imageConfig)
}
type apexJarModulePair struct {
apex string
jarModule android.Module
}
func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []apexJarModulePair {
modules := make([]apexJarModulePair, 0, imageConfig.modules.Len())
for i := 0; i < imageConfig.modules.Len(); i++ {
found := false
for _, module := range gatherApexModulePairDepsWithTag(ctx, dexpreoptBootJarDepTag) {
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
if name == imageConfig.modules.Jar(i) {
modules = append(modules, apexJarModulePair{
apex: imageConfig.modules.Apex(i),
jarModule: module,
})
found = true
break
}
}
if !found && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf(
"Boot image '%s' module '%s' not added as a dependency of dex_bootjars",
imageConfig.name,
imageConfig.modules.Jar(i))
return []apexJarModulePair{}
}
}
return modules
}
// extractEncodedDexJarsFromModulesOrBootclasspathFragments gets the hidden API encoded dex jars for
// the given modules.
func extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx android.ModuleContext, apexJarModulePairs []apexJarModulePair) bootDexJarByModule {
encodedDexJarsByModuleName := bootDexJarByModule{}
for _, pair := range apexJarModulePairs {
var path android.Path
if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) {
// This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API
// files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for
// a source APEX because there is no guarantee that it is the same as the jar packed into the
// APEX. In practice, they are the same when we are building from a full source tree, but they
// are different when we are building from a thin manifest (e.g., master-art), where there is
// no monolithic hidden API files at all.
path = retrieveEncodedBootDexJarFromModule(ctx, pair.jarModule)
} else {
// Use exactly the same jar that is packed into the APEX.
fragment := getBootclasspathFragmentByApex(ctx, pair.apex)
if fragment == nil {
ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+
"APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars",
pair.jarModule.Name(),
pair.apex)
}
bootclasspathFragmentInfo := ctx.OtherModuleProvider(fragment, BootclasspathFragmentApexContentInfoProvider).(BootclasspathFragmentApexContentInfo)
jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule)
if err != nil {
ctx.ModuleErrorf("%s", err)
}
path = jar
}
encodedDexJarsByModuleName.addPath(pair.jarModule, path)
}
return encodedDexJarsByModuleName
}
// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined // copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined
// paths in the global config. // paths in the global config.
func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) { func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
@ -686,10 +843,12 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
rule.Command().Text("rm").Flag("-f"). rule.Command().Text("rm").Flag("-f").
Flag(symbolsDir.Join(ctx, "*.art").String()). Flag(symbolsDir.Join(ctx, "*.art").String()).
Flag(symbolsDir.Join(ctx, "*.oat").String()). Flag(symbolsDir.Join(ctx, "*.oat").String()).
Flag(symbolsDir.Join(ctx, "*.vdex").String()).
Flag(symbolsDir.Join(ctx, "*.invocation").String()) Flag(symbolsDir.Join(ctx, "*.invocation").String())
rule.Command().Text("rm").Flag("-f"). rule.Command().Text("rm").Flag("-f").
Flag(outputDir.Join(ctx, "*.art").String()). Flag(outputDir.Join(ctx, "*.art").String()).
Flag(outputDir.Join(ctx, "*.oat").String()). Flag(outputDir.Join(ctx, "*.oat").String()).
Flag(outputDir.Join(ctx, "*.vdex").String()).
Flag(outputDir.Join(ctx, "*.invocation").String()) Flag(outputDir.Join(ctx, "*.invocation").String())
cmd := rule.Command() cmd := rule.Command()
@ -711,36 +870,31 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms). Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms).
Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx) Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx)
if profile != nil { if image.isProfileGuided() && !global.DisableGenerateProfile {
cmd.FlagWithInput("--profile-file=", profile) if profile != nil {
} cmd.FlagWithInput("--profile-file=", profile)
}
fragments := make(map[string]commonBootclasspathFragment) for _, apex := range image.profileImports {
ctx.VisitDirectDepsWithTag(bootclasspathFragmentDepTag, func(child android.Module) { fragment := getBootclasspathFragmentByApex(ctx, apex)
fragment := child.(commonBootclasspathFragment) if fragment == nil {
if fragment.getImageName() != nil && android.IsModulePreferred(child) { ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but a "+
fragments[*fragment.getImageName()] = fragment "bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+
"dependency of dex_bootjars",
image.name,
apex)
return bootImageVariantOutputs{}
}
importedProfile := fragment.(commonBootclasspathFragment).getProfilePath()
if importedProfile == nil {
ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+
"doesn't provide a profile",
image.name,
apex)
return bootImageVariantOutputs{}
}
cmd.FlagWithInput("--profile-file=", importedProfile)
} }
})
for _, profileImport := range image.profileImports {
fragment := fragments[profileImport.name]
if fragment == nil {
ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but a "+
"bootclasspath_fragment with image name '%[2]s' doesn't exist or is not added as a "+
"dependency of '%[1]s'",
image.name,
profileImport.name)
return bootImageVariantOutputs{}
}
if fragment.getProfilePath() == nil {
ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+
"doesn't provide a profile",
image.name,
profileImport.name)
return bootImageVariantOutputs{}
}
cmd.FlagWithInput("--profile-file=", fragment.getProfilePath())
} }
dirtyImageFile := "frameworks/base/config/dirty-image-objects" dirtyImageFile := "frameworks/base/config/dirty-image-objects"
@ -1059,11 +1213,9 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " ")) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " "))
ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(dexLocations, " ")) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(dexLocations, " "))
var imageNames []string
// The primary ART boot image is exposed to Make for testing (gtests) and benchmarking // The primary ART boot image is exposed to Make for testing (gtests) and benchmarking
// (golem) purposes. // (golem) purposes.
for _, current := range append(d.otherImages, image) { for _, current := range append(d.otherImages, image) {
imageNames = append(imageNames, current.name)
for _, variant := range current.variants { for _, variant := range current.variants {
suffix := "" suffix := ""
if variant.target.Os.Class == android.Host { if variant.target.Os.Class == android.Host {
@ -1084,8 +1236,6 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) {
ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICE"+current.name, strings.Join(imageLocationsOnDevice, ":")) ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICE"+current.name, strings.Join(imageLocationsOnDevice, ":"))
ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String()) ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
} }
// Ensure determinism. ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(getImageNames(), " "))
sort.Strings(imageNames)
ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
} }
} }

View file

@ -40,57 +40,68 @@ func dexpreoptTargets(ctx android.PathContext) []android.Target {
} }
var ( var (
bootImageConfigKey = android.NewOnceKey("bootImageConfig") bootImageConfigKey = android.NewOnceKey("bootImageConfig")
bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw") bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
artBootImageName = "art" frameworkBootImageName = "boot"
frameworkBootImageName = "boot" mainlineBootImageName = "mainline"
mainlineBootImageName = "mainline" bootImageStem = "boot"
bootImageStem = "boot" profileInstallPathInApex = "etc/boot-image.prof"
) )
// getImageNames returns an ordered list of image names. The order doesn't matter but needs to be
// deterministic. The names listed here must match the map keys returned by genBootImageConfigs.
func getImageNames() []string {
return []string{"art", "boot", "mainline"}
}
func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig { func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
return ctx.Config().Once(bootImageConfigRawKey, func() interface{} { return ctx.Config().Once(bootImageConfigRawKey, func() interface{} {
global := dexpreopt.GetGlobalConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx)
artBootImageName := "art" // Keep this local to avoid accidental references.
artModules := global.ArtApexJars artModules := global.ArtApexJars
frameworkModules := global.BootJars // This includes `artModules`. frameworkModules := global.BootJars // This includes `global.ArtApexJars`.
mainlineBcpModules := global.ApexBootJars mainlineBcpModules := global.ApexBootJars
frameworkSubdir := "system/framework" frameworkSubdir := "system/framework"
// ART config for the primary boot image in the ART apex. profileImports := []string{"com.android.art"}
// It includes the Core Libraries.
// ART boot image for testing only. Do not rely on it to make any build-time decision.
artCfg := bootImageConfig{ artCfg := bootImageConfig{
name: artBootImageName, name: artBootImageName,
stem: bootImageStem, enabledIfExists: "art-bootclasspath-fragment",
installDir: "apex/art_boot_images/javalib", stem: bootImageStem,
profileInstallPathInApex: "etc/boot-image.prof", installDir: "apex/art_boot_images/javalib",
modules: artModules, modules: artModules,
preloadedClassesFile: "art/build/boot/preloaded-classes", preloadedClassesFile: "art/build/boot/preloaded-classes",
compilerFilter: "speed-profile", compilerFilter: "speed-profile",
singleImage: false, singleImage: false,
profileImports: profileImports,
} }
// Framework config for the boot image extension. // Framework config for the boot image extension.
// It includes framework libraries and depends on the ART config. // It includes framework libraries and depends on the ART config.
frameworkCfg := bootImageConfig{ frameworkCfg := bootImageConfig{
name: frameworkBootImageName, name: frameworkBootImageName,
enabledIfExists: "platform-bootclasspath",
stem: bootImageStem, stem: bootImageStem,
installDir: frameworkSubdir, installDir: frameworkSubdir,
modules: frameworkModules, modules: frameworkModules,
preloadedClassesFile: "frameworks/base/config/preloaded-classes", preloadedClassesFile: "frameworks/base/config/preloaded-classes",
compilerFilter: "speed-profile", compilerFilter: "speed-profile",
singleImage: false, singleImage: false,
profileImports: []*bootImageConfig{&artCfg}, profileImports: profileImports,
} }
mainlineCfg := bootImageConfig{ mainlineCfg := bootImageConfig{
extends: &frameworkCfg, extends: &frameworkCfg,
name: mainlineBootImageName, name: mainlineBootImageName,
stem: bootImageStem, enabledIfExists: "platform-bootclasspath",
installDir: frameworkSubdir, stem: bootImageStem,
modules: mainlineBcpModules, installDir: frameworkSubdir,
compilerFilter: "verify", modules: mainlineBcpModules,
singleImage: true, compilerFilter: "verify",
singleImage: true,
} }
return map[string]*bootImageConfig{ return map[string]*bootImageConfig{
@ -180,10 +191,6 @@ func calculateDepsRecursive(c *bootImageConfig, targets []android.Target, visite
} }
} }
func artBootImageConfig(ctx android.PathContext) *bootImageConfig {
return genBootImageConfigs(ctx)[artBootImageName]
}
func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig { func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
return genBootImageConfigs(ctx)[frameworkBootImageName] return genBootImageConfigs(ctx)[frameworkBootImageName]
} }
@ -192,6 +199,18 @@ func mainlineBootImageConfig(ctx android.PathContext) *bootImageConfig {
return genBootImageConfigs(ctx)[mainlineBootImageName] return genBootImageConfigs(ctx)[mainlineBootImageName]
} }
// isProfileProviderApex returns true if this apex provides a boot image profile.
func isProfileProviderApex(ctx android.PathContext, apexName string) bool {
for _, config := range genBootImageConfigs(ctx) {
for _, profileImport := range config.profileImports {
if profileImport == apexName {
return true
}
}
}
return false
}
// Apex boot config allows to access build/install paths of apex boot jars without going // Apex boot config allows to access build/install paths of apex boot jars without going
// through the usual trouble of registering dependencies on those modules and extracting build paths // through the usual trouble of registering dependencies on those modules and extracting build paths
// from those dependencies. // from those dependencies.

View file

@ -16,6 +16,7 @@ package java
import ( import (
"runtime" "runtime"
"sort"
"testing" "testing"
"android/soong/android" "android/soong/android"
@ -35,3 +36,22 @@ func TestBootImageConfig(t *testing.T) {
CheckFrameworkBootImageConfig(t, result) CheckFrameworkBootImageConfig(t, result)
CheckMainlineBootImageConfig(t, result) CheckMainlineBootImageConfig(t, result)
} }
func TestImageNames(t *testing.T) {
result := android.GroupFixturePreparers(
PrepareForBootImageConfigTest,
).RunTest(t)
names := getImageNames()
sort.Strings(names)
ctx := &android.TestPathContext{TestResult: result}
configs := genBootImageConfigs(ctx)
namesFromConfigs := make([]string, 0, len(configs))
for name, _ := range configs {
namesFromConfigs = append(namesFromConfigs, name)
}
sort.Strings(namesFromConfigs)
android.AssertArrayString(t, "getImageNames vs genBootImageConfigs", names, namesFromConfigs)
}

View file

@ -813,8 +813,8 @@ func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mut
}, },
}, },
profileInstalls: []normalizedInstall{ profileInstalls: []normalizedInstall{
{from: "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", to: "/system/etc/boot-image.prof"},
{from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"}, {from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"},
{from: "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/boot/boot.prof", to: "/system/etc/boot-image.prof"},
}, },
profileLicenseMetadataFile: expectedLicenseMetadataFile, profileLicenseMetadataFile: expectedLicenseMetadataFile,
} }
@ -1230,14 +1230,14 @@ DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm=%[1]s
DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s
DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s
DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86_64=%[1]s DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86_64=%[1]s
DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/apex/art_boot_images/javalib/boot.art DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/apex/art_boot_images/javalib/boot.art
DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art
DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEmainline=/system/framework/boot.art:/system/framework/boot-framework-foo.art DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEmainline=/system/framework/boot.art:/system/framework/boot-framework-foo.art
@ -1245,8 +1245,8 @@ DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTart=out/soong/dexpreopt_arm64/dex_artjars/andro
DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art
DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art
DEXPREOPT_IMAGE_NAMES=art boot mainline DEXPREOPT_IMAGE_NAMES=art boot mainline
DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/boot/boot.prof:/system/etc/boot-image.prof DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof:/system/etc/boot-image.prof out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof
DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat

View file

@ -123,15 +123,15 @@ func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpM
} }
func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies on all the modules configured in the "art" boot image. // Add dependencies on all the ART jars.
artImageConfig := genBootImageConfigs(ctx)[artBootImageName] global := dexpreopt.GetGlobalConfig(ctx)
addDependenciesOntoBootImageModules(ctx, artImageConfig.modules, platformBootclasspathArtBootJarDepTag) addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag)
// Add dependencies on all the non-updatable module configured in the "boot" boot image. That does // Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable
// not include modules configured in the "art" boot image. // APEXes.
addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag) addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag)
// Add dependencies on all the apex jars. // Add dependencies on all the updatable jars, except the ART jars.
apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
@ -186,7 +186,6 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo
bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule)
b.generateBootImageBuildActions(ctx)
b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules) b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
} }
@ -218,7 +217,8 @@ func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext)
} }
func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) android.ConfiguredJarList { func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) android.ConfiguredJarList {
return defaultBootImageConfig(ctx).modules.RemoveList(artBootImageConfig(ctx).modules) global := dexpreopt.GetGlobalConfig(ctx)
return global.BootJars.RemoveList(global.ArtApexJars)
} }
// checkPlatformModules ensures that the non-updatable modules supplied are not part of an // checkPlatformModules ensures that the non-updatable modules supplied are not part of an
@ -399,78 +399,9 @@ func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.Make
ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String()) ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String())
} }
// generateBootImageBuildActions generates ninja rules related to the boot image creation.
func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext) {
// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
// GenerateSingletonBuildActions method as it cannot create it for itself.
dexpreopt.GetGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
if !shouldBuildBootImages(ctx.Config(), global) {
return
}
frameworkBootImageConfig := defaultBootImageConfig(ctx)
bootFrameworkProfileRule(ctx, frameworkBootImageConfig)
b.generateBootImage(ctx, frameworkBootImageName)
b.generateBootImage(ctx, mainlineBootImageName)
dumpOatRules(ctx, frameworkBootImageConfig)
}
func (b *platformBootclasspathModule) generateBootImage(ctx android.ModuleContext, imageName string) {
imageConfig := genBootImageConfigs(ctx)[imageName]
modules := b.getModulesForImage(ctx, imageConfig)
// Copy module dex jars to their predefined locations.
bootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, modules)
copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule)
// Build a profile for the image config and then use that to build the boot image.
profile := bootImageProfileRule(ctx, imageConfig)
// If dexpreopt of boot image jars should be skipped, generate only a profile.
global := dexpreopt.GetGlobalConfig(ctx)
if global.DisablePreoptBootImages {
return
}
// Build boot image files for the android variants.
androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
// Zip the android variant boot image files up.
buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch)
// Build boot image files for the host variants. There are use directly by ART host side tests.
buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
}
// Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps. // Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps.
func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) { func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) {
config := GetApexBootConfig(ctx) config := GetApexBootConfig(ctx)
apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules) apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule) copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
} }
func (b *platformBootclasspathModule) getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []android.Module {
modules := make([]android.Module, 0, imageConfig.modules.Len())
for i := 0; i < imageConfig.modules.Len(); i++ {
found := false
for _, module := range b.configuredModules {
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
if name == imageConfig.modules.Jar(i) {
modules = append(modules, module)
found = true
break
}
}
if !found && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf(
"Boot image '%s' module '%s' not added as a dependency of platform_bootclasspath",
imageConfig.name,
imageConfig.modules.Jar(i))
return []android.Module{}
}
}
return modules
}

View file

@ -145,8 +145,8 @@ func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) {
preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "art-bootclasspath-fragment") preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "art-bootclasspath-fragment")
// Check that source on its own configures the bootImageConfig correctly. // Check that source on its own configures the bootImageConfig correctly.
java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/meta_lic") java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
CheckSnapshot(t, result, "mysdk", "", CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(` checkAndroidBpContents(`
@ -213,24 +213,24 @@ java_import {
java.ApexBootJarDexJarPaths..., java.ApexBootJarDexJarPaths...,
)..., )...,
) )
java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/art-bootclasspath-fragment/android_common_com.android.art/meta_lic") java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
}), }),
snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot), snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
// Check the behavior of the snapshot when the source is preferred. // Check the behavior of the snapshot when the source is preferred.
snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) { snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/meta_lic") java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
}), }),
snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot), snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
// Check the behavior of the snapshot when it is preferred. // Check the behavior of the snapshot when it is preferred.
snapshotTestChecker(checkSnapshotPreferredWithSource, func(t *testing.T, result *android.TestResult) { snapshotTestChecker(checkSnapshotPreferredWithSource, func(t *testing.T, result *android.TestResult) {
java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/prebuilt_art-bootclasspath-fragment/android_common_com.android.art/meta_lic") java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic") java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
}), }),
) )