Export boot image files from prebuilt_apex/apex_set am: 5466a3699c am: c4a3e6d2f3

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1736777

Change-Id: I45874db42b8d17e0893d5e1c4b9aca6356066221
This commit is contained in:
Paul Duffin
2021-06-18 07:05:13 +00:00
committed by Automerger Merge Worker
6 changed files with 232 additions and 54 deletions

View File

@@ -144,10 +144,22 @@ type commonBootclasspathFragment interface {
// module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a
// versioned sdk.
produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
// produceBootImageFiles produces the boot image (i.e. .art, .oat and .vdex) files for each of the
// required android.ArchType values in the returned map.
//
// It must return nil if the boot image files cannot be produced for whatever reason.
produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module) bootImageFilesByArch
}
var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil)
// bootImageFilesByArch is a map from android.ArchType to the paths to the boot image files.
//
// The paths include the .art, .oat and .vdex files, one for each of the modules from which the boot
// image is created.
type bootImageFilesByArch map[android.ArchType]android.Paths
func bootclasspathFragmentFactory() android.Module {
m := &BootclasspathFragmentModule{}
m.AddProperties(&m.properties)
@@ -285,7 +297,7 @@ type BootclasspathFragmentApexContentInfo struct {
modules android.ConfiguredJarList
// Map from arch type to the boot image files.
bootImageFilesByArch map[android.ArchType]android.OutputPaths
bootImageFilesByArch bootImageFilesByArch
// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
// hidden API encoded dex jar path.
@@ -299,7 +311,7 @@ func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarLis
// Get a map from ArchType to the associated boot image's contents for Android.
//
// Extension boot images only return their own files, not the files of the boot images they extend.
func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType() map[android.ArchType]android.OutputPaths {
func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType() bootImageFilesByArch {
return i.bootImageFilesByArch
}
@@ -409,7 +421,12 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
// Perform hidden API processing.
hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
var bootImageFilesByArch bootImageFilesByArch
if imageConfig != nil {
// Delegate the production of the boot image files to a module type specific method.
common := ctx.Module().(commonBootclasspathFragment)
bootImageFilesByArch = common.produceBootImageFiles(ctx, imageConfig, contents)
if shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
// Copy the dex jars of this fragment's content modules to their predefined locations.
copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule)
@@ -419,7 +436,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
// A prebuilt fragment cannot contribute to an apex.
if !android.IsModulePrebuilt(ctx.Module()) {
// Provide the apex content info.
b.provideApexContentInfo(ctx, imageConfig, contents, hiddenAPIOutput)
b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFilesByArch)
}
}
}
@@ -449,7 +466,7 @@ func shouldCopyBootFilesToPredefinedLocations(ctx android.ModuleContext, imageCo
// provideApexContentInfo creates, initializes and stores the apex content info for use by other
// modules.
func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module, hiddenAPIOutput *HiddenAPIOutput) {
func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFilesByArch bootImageFilesByArch) {
// Construct the apex content info from the config.
info := BootclasspathFragmentApexContentInfo{
// Populate the apex content info with paths to the dex jars.
@@ -458,28 +475,10 @@ func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleC
if imageConfig != nil {
info.modules = imageConfig.modules
if !SkipDexpreoptBootJars(ctx) {
// 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)
// Only generate the boot image if the configuration does not skip it.
if b.generateBootImageBuildActions(ctx, contents, imageConfig) {
// Allow the apex to access the boot image files.
files := map[android.ArchType]android.OutputPaths{}
for _, variant := range imageConfig.variants {
// We also generate boot images for host (for testing), but we don't need those in the apex.
// TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
if variant.target.Os == android.Android {
files[variant.target.Arch.ArchType] = variant.imagesDeps
}
}
info.bootImageFilesByArch = files
}
}
}
info.bootImageFilesByArch = bootImageFilesByArch
// Make the apex content info available for other modules.
ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
}
@@ -616,7 +615,6 @@ func retrieveLegacyEncodedBootDexFiles(ctx android.ModuleContext, contents []and
// createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived
// from the properties on this module and its dependencies.
func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput {
// Merge the HiddenAPIInfo from all the fragment dependencies.
dependencyHiddenApiInfo := newHiddenAPIInfo()
dependencyHiddenApiInfo.mergeFromFragmentDeps(ctx, fragments)
@@ -644,6 +642,30 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC
return hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
}
// produceBootImageFiles builds the boot image files from the source if it is required.
func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module) bootImageFilesByArch {
if SkipDexpreoptBootJars(ctx) {
return nil
}
// 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)
// Only generate the boot image if the configuration does not skip it.
if !b.generateBootImageBuildActions(ctx, contents, imageConfig) {
return nil
}
// Only make the files available to an apex if they were actually generated.
files := bootImageFilesByArch{}
for _, variant := range imageConfig.apexVariants() {
files[variant.target.Arch.ArchType] = variant.imagesDeps.Paths()
}
return files
}
// generateBootImageBuildActions generates ninja rules to create the boot image if required for this
// module.
//
@@ -881,8 +903,88 @@ func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx an
return &output
}
// produceBootImageFiles extracts the boot image files from the APEX if available.
func (module *prebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module) bootImageFilesByArch {
if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
return nil
}
var deapexerModule android.Module
ctx.VisitDirectDeps(func(module android.Module) {
tag := ctx.OtherModuleDependencyTag(module)
// Save away the `deapexer` module on which this depends, if any.
if tag == android.DeapexerTag {
deapexerModule = module
}
})
if deapexerModule == nil {
// This should never happen as a variant for a prebuilt_apex is only created if the
// deapexer module has been configured to export the dex implementation jar for this module.
ctx.ModuleErrorf("internal error: module does not depend on a `deapexer` module")
return nil
}
di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
name := module.BaseModuleName()
for _, variant := range imageConfig.apexVariants() {
arch := variant.target.Arch.ArchType
for _, toPath := range variant.imagesDeps {
// Get the path to the file that the deapexer extracted from the prebuilt apex file.
tag := createBootImageTag(arch, toPath.Base())
fromPath := di.PrebuiltExportPath(name, tag)
// Copy the file to the predefined location.
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Input: fromPath,
Output: toPath,
})
}
}
// The returned files will be made available to APEXes that include a bootclasspath_fragment.
// However, as a prebuilt_bootclasspath_fragment can never contribute to an APEX there is no point
// in returning any files.
return nil
}
var _ commonBootclasspathFragment = (*prebuiltBootclasspathFragmentModule)(nil)
// createBootImageTag creates the tag to uniquely identify the boot image file among all of the
// files that a module requires from the prebuilt .apex file.
func createBootImageTag(arch android.ArchType, baseName string) string {
tag := fmt.Sprintf(".bootimage-%s-%s", arch, baseName)
return tag
}
// RequiredFilesFromPrebuiltApex returns the list of all files the prebuilt_bootclasspath_fragment
// requires from a prebuilt .apex file.
//
// 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.
func (module *prebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) map[string]string {
imageConfig := module.getImageConfig(ctx)
if imageConfig != nil {
// Add the boot image files, e.g. .art, .oat and .vdex files.
files := map[string]string{}
name := module.BaseModuleName()
for _, variant := range imageConfig.apexVariants() {
arch := variant.target.Arch.ArchType
for _, path := range variant.imagesDeps.Paths() {
base := path.Base()
tag := createBootImageTag(arch, base)
key := fmt.Sprintf("%s{%s}", name, tag)
files[key] = filepath.Join("javalib", arch.String(), base)
}
}
return files
}
return nil
}
var _ android.RequiredFilesFromPrebuiltApex = (*prebuiltBootclasspathFragmentModule)(nil)
func prebuiltBootclasspathFragmentFactory() android.Module {
m := &prebuiltBootclasspathFragmentModule{}
m.AddProperties(&m.properties, &m.prebuiltProperties)

View File

@@ -358,6 +358,19 @@ func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.Ou
return ret
}
// apexVariants returns a list of all *bootImageVariant that could be included in an apex.
func (image *bootImageConfig) apexVariants() []*bootImageVariant {
variants := []*bootImageVariant{}
for _, variant := range image.variants {
// We also generate boot images for host (for testing), but we don't need those in the apex.
// TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device
if variant.target.Os == android.Android {
variants = append(variants, variant)
}
}
return variants
}
// Return boot image locations (as a list of symbolic paths).
//
// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
@@ -489,7 +502,7 @@ func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJars
}
}
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
// buildBootImage takes a bootImageConfig, and creates rules to build it.
func buildBootImage(ctx android.ModuleContext, image *bootImageConfig, profile android.WritablePath) {
var zipFiles android.Paths
for _, variant := range image.variants {