Split findAndCopyBootJars into separate find and copy functions

The main difference between the dexpreopt_bootjars singleton and the
platform_bootclasspath singleton module is the way they find the
modules to use. The former searches all modules, the latter adds
dependencies on the modules that they need. This change separates the
finding of the modules from the copying of the boot jars for those
modules to make it easier to move the remaining functionality to
platform_bootclasspath.

This temporarily creates a singleton specific copy of the hidden API
function isModuleInConfiguredList() to select the modules in place of
the logic in the getBootJar() method. There is a slight loss of context
information from the error messages but as these methods will be
removed once the boot image creation has moved this is not an issue.

While switching the isModuleInConfiguredListForSingleton() to use the
SingletonContext the error message was fixed to include the name of
the module with the issue.

Bug: 177892522
Test: m nothing
Change-Id: Iaea906da95d9da5301fb964fc593890f2216d336
This commit is contained in:
Paul Duffin
2021-04-27 15:23:28 +01:00
parent f23bc472b0
commit d6894ca4b9
2 changed files with 47 additions and 64 deletions

View File

@@ -452,90 +452,79 @@ func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig
return true return true
} }
// Inspect this module to see if it contains a bootclasspath dex jar. // A copy of isModuleInConfiguredList created to work with singleton context.
// Note that the same jar may occur in multiple modules.
// This logic is tested in the apex package to avoid import cycle apex <-> java.
// //
// This is similar to logic in isModuleInConfiguredList() so any changes needed here are likely to // TODO(b/177892522): Remove this.
// be needed there too. func isModuleInConfiguredListForSingleton(ctx android.SingletonContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool {
//
// TODO(b/177892522): Avoid having to perform this type of check or if necessary dedup it.
func getBootJar(ctx android.SingletonContext, bootjars android.ConfiguredJarList, module android.Module, fromWhere string) (int, android.Path) {
name := ctx.ModuleName(module) name := ctx.ModuleName(module)
// Strip a prebuilt_ prefix so that this can access the dex jar from a prebuilt module. // Strip a prebuilt_ prefix so that this can match a prebuilt module that has not been renamed.
name = android.RemoveOptionalPrebuiltPrefix(name) name = android.RemoveOptionalPrebuiltPrefix(name)
// Ignore any module that is not listed in the boot image configuration. // Ignore any module that is not listed in the boot image configuration.
index := bootjars.IndexOfJar(name) index := configuredBootJars.IndexOfJar(name)
if index == -1 { if index == -1 {
return -1, nil return false
} }
// It is an error if a module configured in the boot image does not support accessing the dex jar. // It is an error if the module is not an ApexModule.
// This is safe because every module that has the same name has to have the same module type.
jar, hasJar := module.(interface{ DexJarBuildPath() android.Path })
if !hasJar {
ctx.Errorf("module %q %sdoes not support accessing dex jar", module, fromWhere)
return -1, nil
}
// It is also an error if the module is not an ApexModule.
if _, ok := module.(android.ApexModule); !ok { if _, ok := module.(android.ApexModule); !ok {
ctx.Errorf("module %q %sdoes not support being added to an apex", module, fromWhere) ctx.Errorf("%s is configured in boot jars but does not support being added to an apex", ctx.ModuleName(module))
return -1, nil return false
} }
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
// Now match the apex part of the boot image configuration. // Now match the apex part of the boot image configuration.
requiredApex := bootjars.Apex(index) requiredApex := configuredBootJars.Apex(index)
if requiredApex == "platform" || requiredApex == "system_ext" { if requiredApex == "platform" || requiredApex == "system_ext" {
if len(apexInfo.InApexes) != 0 { if len(apexInfo.InApexes) != 0 {
// A platform variant is required but this is for an apex so ignore it. // A platform variant is required but this is for an apex so ignore it.
return -1, nil return false
} }
} else if !apexInfo.InApexByBaseName(requiredApex) { } else if !apexInfo.InApexByBaseName(requiredApex) {
// An apex variant for a specific apex is required but this is the wrong apex. // An apex variant for a specific apex is required but this is the wrong apex.
return -1, nil return false
} }
return index, jar.DexJarBuildPath() return true
} }
// Inspect this module to see if it contains a bootclasspath dex jar from a given boot image. // findBootJarModules finds the boot jar module variants specified in the bootjars parameter.
func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) { //
fromImage := fmt.Sprintf("configured in boot image %q ", image.name) // It returns a list of modules such that the module at index i corresponds to the configured jar
index, jarPath := getBootJar(ctx, image.modules, module, fromImage) // at index i.
if index == -1 { func findBootJarModules(ctx android.SingletonContext, bootjars android.ConfiguredJarList) []android.Module {
return -1, nil modules := make([]android.Module, bootjars.Len())
}
return index, jarPath
}
// Generate commands that will copy boot jars to predefined paths in the global config.
func findAndCopyBootJars(ctx android.SingletonContext, bootjars android.ConfiguredJarList,
jarPathsPredefined android.WritablePaths,
getBootJar func(module android.Module) (int, android.Path)) {
// This logic is tested in the apex package to avoid import cycle apex <-> java. // This logic is tested in the apex package to avoid import cycle apex <-> java.
jarPaths := make(android.Paths, bootjars.Len())
ctx.VisitAllModules(func(module android.Module) { ctx.VisitAllModules(func(module android.Module) {
if !isActiveModule(module) { if !isActiveModule(module) || !isModuleInConfiguredListForSingleton(ctx, module, bootjars) {
return return
} }
if i, j := getBootJar(module); i != -1 {
if existing := jarPaths[i]; existing != nil { name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
ctx.Errorf("Multiple dex jars found for %s:%s - %q and %q", index := bootjars.IndexOfJar(name)
bootjars.Apex(i), bootjars.Jar(i), existing, j) if existing := modules[index]; existing != nil {
return ctx.Errorf("Multiple boot jar modules found for %s:%s - %q and %q",
} bootjars.Apex(index), bootjars.Jar(index), existing, module)
jarPaths[i] = j return
} }
modules[index] = module
}) })
return modules
}
// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to
// predefined paths in the global config.
func copyBootJarsToPredefinedLocations(ctx android.SingletonContext, bootModules []android.Module, bootjars android.ConfiguredJarList, jarPathsPredefined android.WritablePaths) {
jarPaths := make(android.Paths, bootjars.Len())
for i, module := range bootModules {
if module != nil {
bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
jarPaths[i] = bootDexJar
}
}
// The paths to bootclasspath DEX files need to be known at module GenerateAndroidBuildAction // The paths to bootclasspath DEX files need to be known at module GenerateAndroidBuildAction
// time, before the boot images are built (these paths are used in dexpreopt rule generation for // time, before the boot images are built (these paths are used in dexpreopt rule generation for
@@ -575,10 +564,8 @@ func findAndCopyBootJars(ctx android.SingletonContext, bootjars android.Configur
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig, profile android.WritablePath) *bootImageConfig { func buildBootImage(ctx android.SingletonContext, image *bootImageConfig, profile android.WritablePath) *bootImageConfig {
getBootJarFunc := func(module android.Module) (int, android.Path) { bootModules := findBootJarModules(ctx, image.modules)
return getBootImageJar(ctx, image, module) copyBootJarsToPredefinedLocations(ctx, bootModules, image.modules, image.dexPaths)
}
findAndCopyBootJars(ctx, image.modules, image.dexPaths, getBootJarFunc)
var zipFiles android.Paths var zipFiles android.Paths
for _, variant := range image.variants { for _, variant := range image.variants {
@@ -605,11 +592,8 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig, profil
// Generate commands that will copy updatable boot jars to predefined paths in the global config. // Generate commands that will copy updatable boot jars to predefined paths in the global config.
func copyUpdatableBootJars(ctx android.SingletonContext) { func copyUpdatableBootJars(ctx android.SingletonContext) {
config := GetUpdatableBootConfig(ctx) config := GetUpdatableBootConfig(ctx)
getBootJarFunc := func(module android.Module) (int, android.Path) { bootModules := findBootJarModules(ctx, config.modules)
index, jar := getBootJar(ctx, config.modules, module, "configured in updatable boot jars ") copyBootJarsToPredefinedLocations(ctx, bootModules, config.modules, config.dexPaths)
return index, jar
}
findAndCopyBootJars(ctx, config.modules, config.dexPaths, getBootJarFunc)
} }
// Generate boot image build rules for a specific target. // Generate boot image build rules for a specific target.

View File

@@ -151,8 +151,7 @@ func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext)
// Checks to see whether the supplied module variant is in the list of boot jars. // Checks to see whether the supplied module variant is in the list of boot jars.
// //
// This is similar to logic in getBootImageJar() so any changes needed here are likely to be needed // Apart from the context this is identical to isModuleInConfiguredListForSingleton.
// there too.
// //
// TODO(b/179354495): Avoid having to perform this type of check or if necessary dedup it. // TODO(b/179354495): Avoid having to perform this type of check or if necessary dedup it.
func isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool { func isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool {
@@ -169,7 +168,7 @@ func isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Modu
// It is an error if the module is not an ApexModule. // It is an error if the module is not an ApexModule.
if _, ok := module.(android.ApexModule); !ok { if _, ok := module.(android.ApexModule); !ok {
ctx.ModuleErrorf("is configured in boot jars but does not support being added to an apex") ctx.ModuleErrorf("%s is configured in boot jars but does not support being added to an apex", ctx.OtherModuleName(module))
return false return false
} }