Merge "Allow installing boot images outside of APEX."

This commit is contained in:
Jiakai Zhang
2022-01-14 17:31:04 +00:00
committed by Gerrit Code Review
8 changed files with 204 additions and 29 deletions

View File

@@ -1765,13 +1765,17 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
case bcpfTag:
{
if _, ok := child.(*java.BootclasspathFragmentModule); !ok {
bcpfModule, ok := child.(*java.BootclasspathFragmentModule)
if !ok {
ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a bootclasspath_fragment module", depName)
return false
}
filesToAdd := apexBootclasspathFragmentFiles(ctx, child)
filesInfo = append(filesInfo, filesToAdd...)
for _, makeModuleName := range bcpfModule.BootImageDeviceInstallMakeModules() {
a.requiredDeps = append(a.requiredDeps, makeModuleName)
}
return true
}
case sscpfTag:
@@ -2175,13 +2179,15 @@ func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.
var filesToAdd []apexFile
// Add the boot image files, e.g. .art, .oat and .vdex files.
for arch, files := range bootclasspathFragmentInfo.AndroidBootImageFilesByArchType() {
dirInApex := filepath.Join("javalib", arch.String())
for _, f := range files {
androidMkModuleName := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
// TODO(b/177892522) - consider passing in the bootclasspath fragment module here instead of nil
af := newApexFile(ctx, f, androidMkModuleName, dirInApex, etc, nil)
filesToAdd = append(filesToAdd, af)
if bootclasspathFragmentInfo.ShouldInstallBootImageInApex() {
for arch, files := range bootclasspathFragmentInfo.AndroidBootImageFilesByArchType() {
dirInApex := filepath.Join("javalib", arch.String())
for _, f := range files {
androidMkModuleName := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
// TODO(b/177892522) - consider passing in the bootclasspath fragment module here instead of nil
af := newApexFile(ctx, f, androidMkModuleName, dirInApex, etc, nil)
filesToAdd = append(filesToAdd, af)
}
}
}

View File

@@ -8739,6 +8739,22 @@ func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) {
})
}
// Verifies that the APEX depends on all the Make modules in the list.
func ensureContainsRequiredDeps(t *testing.T, ctx *android.TestContext, moduleName, variant string, deps []string) {
a := ctx.ModuleForTests(moduleName, variant).Module().(*apexBundle)
for _, dep := range deps {
android.AssertStringListContains(t, "", a.requiredDeps, dep)
}
}
// Verifies that the APEX does not depend on any of the Make modules in the list.
func ensureDoesNotContainRequiredDeps(t *testing.T, ctx *android.TestContext, moduleName, variant string, deps []string) {
a := ctx.ModuleForTests(moduleName, variant).Module().(*apexBundle)
for _, dep := range deps {
android.AssertStringListDoesNotContain(t, "", a.requiredDeps, dep)
}
}
func TestMain(m *testing.M) {
os.Exit(m.Run())
}

View File

@@ -410,6 +410,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
// bootclasspath_fragment's contents property.
java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
addSource("foo", "bar"),
java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
@@ -437,12 +438,62 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
`mybootclasspathfragment`,
})
// The boot images are installed in the APEX by Soong, so there shouldn't be any dexpreopt-related Make modules.
ensureDoesNotContainRequiredDeps(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
"mybootclasspathfragment-dexpreopt-arm64-boot.art",
"mybootclasspathfragment-dexpreopt-arm64-boot.oat",
"mybootclasspathfragment-dexpreopt-arm64-boot.vdex",
"mybootclasspathfragment-dexpreopt-arm64-boot-bar.art",
"mybootclasspathfragment-dexpreopt-arm64-boot-bar.oat",
"mybootclasspathfragment-dexpreopt-arm64-boot-bar.vdex",
"mybootclasspathfragment-dexpreopt-arm-boot.art",
"mybootclasspathfragment-dexpreopt-arm-boot.oat",
"mybootclasspathfragment-dexpreopt-arm-boot.vdex",
"mybootclasspathfragment-dexpreopt-arm-boot-bar.art",
"mybootclasspathfragment-dexpreopt-arm-boot-bar.oat",
"mybootclasspathfragment-dexpreopt-arm-boot-bar.vdex",
})
// Make sure that the source bootclasspath_fragment copies its dex files to the predefined
// locations for the art image.
module := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
})
t.Run("boot image files from source no boot image in apex", func(t *testing.T) {
result := android.GroupFixturePreparers(
commonPreparer,
// Configure some libraries in the art bootclasspath_fragment that match the source
// bootclasspath_fragment's contents property.
java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
addSource("foo", "bar"),
java.FixtureSetBootImageInstallDirOnDevice("art", "system/framework"),
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
"etc/boot-image.prof",
"etc/classpaths/bootclasspath.pb",
"javalib/bar.jar",
"javalib/foo.jar",
})
ensureContainsRequiredDeps(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
"mybootclasspathfragment-dexpreopt-arm64-boot.art",
"mybootclasspathfragment-dexpreopt-arm64-boot.oat",
"mybootclasspathfragment-dexpreopt-arm64-boot.vdex",
"mybootclasspathfragment-dexpreopt-arm64-boot-bar.art",
"mybootclasspathfragment-dexpreopt-arm64-boot-bar.oat",
"mybootclasspathfragment-dexpreopt-arm64-boot-bar.vdex",
"mybootclasspathfragment-dexpreopt-arm-boot.art",
"mybootclasspathfragment-dexpreopt-arm-boot.oat",
"mybootclasspathfragment-dexpreopt-arm-boot.vdex",
"mybootclasspathfragment-dexpreopt-arm-boot-bar.art",
"mybootclasspathfragment-dexpreopt-arm-boot-bar.oat",
"mybootclasspathfragment-dexpreopt-arm-boot-bar.vdex",
})
})
t.Run("boot image disable generate profile", func(t *testing.T) {
result := android.GroupFixturePreparers(
commonPreparer,
@@ -472,6 +523,8 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
addPrebuilt(true, "foo", "bar"),
java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{

View File

@@ -219,6 +219,11 @@ type BootclasspathFragmentModule struct {
// Collect the module directory for IDE info in java/jdeps.go.
modulePaths []string
// Installs for on-device boot image files. This list has entries only if the installs should be
// handled by Make (e.g., the boot image should be installed on the system partition, rather than
// in the APEX).
bootImageDeviceInstalls []dexpreopterInstall
}
// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
@@ -387,6 +392,9 @@ type BootclasspathFragmentApexContentInfo struct {
// Map from arch type to the boot image files.
bootImageFilesByArch bootImageFilesByArch
// True if the boot image should be installed in the APEX.
shouldInstallBootImageInApex bool
// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
// hidden API encoded dex jar path.
contentModuleDexJarPaths bootDexJarByModule
@@ -410,6 +418,11 @@ func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType()
return i.bootImageFilesByArch
}
// Return true if the boot image should be installed in the APEX.
func (i *BootclasspathFragmentApexContentInfo) ShouldInstallBootImageInApex() bool {
return i.shouldInstallBootImageInApex
}
// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
//
// The dex boot jar is one which has had hidden API encoding performed on it.
@@ -550,6 +563,24 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
// Copy the dex jars of this fragment's content modules to their predefined locations.
copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule)
}
for _, variant := range imageConfig.apexVariants() {
arch := variant.target.Arch.ArchType.String()
for _, install := range variant.deviceInstalls {
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
installBase := filepath.Base(install.To)
installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
b.bootImageDeviceInstalls = append(b.bootImageDeviceInstalls, dexpreopterInstall{
name: arch + "-" + installBase,
moduleName: b.Name(),
outputPathOnHost: install.From,
installDirOnDevice: installPath,
installFileOnDevice: installBase,
})
}
}
}
// A prebuilt fragment cannot contribute to an apex.
@@ -599,6 +630,8 @@ func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleC
info.profilePathOnHost = imageConfig.profilePathOnHost
info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
}
info.shouldInstallBootImageInApex = imageConfig.shouldInstallInApex()
}
info.bootImageFilesByArch = bootImageFilesByArch
@@ -813,6 +846,23 @@ func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.
return androidBootImageFilesByArch
}
func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries {
var entriesList []android.AndroidMkEntries
for _, install := range b.bootImageDeviceInstalls {
entriesList = append(entriesList, install.ToMakeEntries())
}
return entriesList
}
// Returns the names of all Make modules that handle the installation of the boot image.
func (b *BootclasspathFragmentModule) BootImageDeviceInstallMakeModules() []string {
var makeModules []string
for _, install := range b.bootImageDeviceInstalls {
makeModules = append(makeModules, install.FullModuleName())
}
return makeModules
}
// Collect information for opening IDE project files in java/jdeps.go.
func (b *BootclasspathFragmentModule) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Deps = append(dpInfo.Deps, b.properties.Contents...)

View File

@@ -57,6 +57,25 @@ func (install *dexpreopterInstall) SubModuleName() string {
return "-dexpreopt-" + install.name
}
// Returns Make entries for installing the file.
//
// This function uses a value receiver rather than a pointer receiver to ensure that the object is
// safe to use in `android.AndroidMkExtraEntriesFunc`.
func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
return android.AndroidMkEntries{
Class: "ETC",
SubName: install.SubModuleName(),
OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
},
},
}
}
type dexpreopter struct {
dexpreoptProperties DexpreoptProperties
@@ -383,19 +402,7 @@ func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall {
func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
var entries []android.AndroidMkEntries
for _, install := range d.builtInstalledForApex {
install := install
entries = append(entries, android.AndroidMkEntries{
Class: "ETC",
SubName: install.SubModuleName(),
OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
},
},
})
entries = append(entries, install.ToMakeEntries())
}
return entries
}

View File

@@ -313,10 +313,13 @@ type bootImageVariant struct {
// This is only set for a variant of an image that extends another image.
primaryImagesDeps android.Paths
// Rules which should be used in make to install the outputs.
// Rules which should be used in make to install the outputs on host.
installs android.RuleBuilderInstalls
vdexInstalls android.RuleBuilderInstalls
unstrippedInstalls android.RuleBuilderInstalls
// Rules which should be used in make to install the outputs on device.
deviceInstalls android.RuleBuilderInstalls
}
// Get target-specific boot image variant for the given boot image config and target.
@@ -388,6 +391,11 @@ func (image *bootImageConfig) apexVariants() []*bootImageVariant {
return variants
}
// Returns true if the boot image should be installed in the APEX.
func (image *bootImageConfig) shouldInstallInApex() bool {
return strings.HasPrefix(image.installDirOnDevice, "apex/")
}
// Return boot image locations (as a list of symbolic paths).
//
// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
@@ -710,6 +718,7 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
var vdexInstalls android.RuleBuilderInstalls
var unstrippedInstalls android.RuleBuilderInstalls
var deviceInstalls android.RuleBuilderInstalls
for _, artOrOat := range image.moduleFiles(ctx, outputDir, ".art", ".oat") {
cmd.ImplicitOutput(artOrOat)
@@ -735,12 +744,21 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
}
if image.installDirOnHost != image.installDirOnDevice && !image.shouldInstallInApex() && !ctx.Config().UnbundledBuild() {
installDirOnDevice := filepath.Join("/", image.installDirOnDevice, arch.String())
for _, file := range image.moduleFiles(ctx, outputDir, ".art", ".oat", ".vdex") {
deviceInstalls = append(deviceInstalls,
android.RuleBuilderInstall{file, filepath.Join(installDirOnDevice, file.Base())})
}
}
rule.Build(image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
// save output and installed files for makevars
image.installs = rule.Installs()
image.vdexInstalls = vdexInstalls
image.unstrippedInstalls = unstrippedInstalls
image.deviceInstalls = deviceInstalls
}
const failureMessage = `ERROR: Dex2oat failed to compile a boot image.

View File

@@ -41,17 +41,14 @@ func dexpreoptTargets(ctx android.PathContext) []android.Target {
var (
bootImageConfigKey = android.NewOnceKey("bootImageConfig")
bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
artBootImageName = "art"
frameworkBootImageName = "boot"
)
// Construct the global boot image configs.
func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
return ctx.Config().Once(bootImageConfigKey, func() interface{} {
func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
return ctx.Config().Once(bootImageConfigRawKey, func() interface{} {
global := dexpreopt.GetGlobalConfig(ctx)
targets := dexpreoptTargets(ctx)
deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
artModules := global.ArtApexJars
frameworkModules := global.BootJars.RemoveList(artModules)
@@ -79,10 +76,22 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
modules: frameworkModules,
}
configs := map[string]*bootImageConfig{
return map[string]*bootImageConfig{
artBootImageName: &artCfg,
frameworkBootImageName: &frameworkCfg,
}
}).(map[string]*bootImageConfig)
}
// Construct the global boot image configs.
func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
return ctx.Config().Once(bootImageConfigKey, func() interface{} {
targets := dexpreoptTargets(ctx)
deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
configs := genBootImageConfigRaw(ctx)
artCfg := configs[artBootImageName]
frameworkCfg := configs[frameworkBootImageName]
// common to all configs
for _, c := range configs {

View File

@@ -506,3 +506,19 @@ func fakeApexMutator(mctx android.BottomUpMutatorContext) {
}
}
}
// Applies the given modifier on the boot image config with the given name.
func FixtureModifyBootImageConfig(name string, configModifier func(*bootImageConfig)) android.FixturePreparer {
return android.FixtureModifyConfig(func(androidConfig android.Config) {
pathCtx := android.PathContextForTesting(androidConfig)
config := genBootImageConfigRaw(pathCtx)
configModifier(config[name])
})
}
// Sets the value of `installDirOnDevice` of the boot image config with the given name.
func FixtureSetBootImageInstallDirOnDevice(name string, installDir string) android.FixturePreparer {
return FixtureModifyBootImageConfig(name, func(config *bootImageConfig) {
config.installDirOnDevice = installDir
})
}