Merge "Allow installing boot images outside of APEX."
This commit is contained in:
22
apex/apex.go
22
apex/apex.go
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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{
|
||||
|
@@ -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...)
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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.
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user