Make copyBootJarsToPredefinedLocations simpler and less fragile am: 3e2db5c10b
Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/14967906 Change-Id: Ifccf1d37420c5d73e213266fb8aeb776c135c857
This commit is contained in:
commit
c9f384104b
|
@ -1661,6 +1661,16 @@ func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) Writable
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildPathsByModule returns a map from module name to build paths based on the given directory
|
||||||
|
// prefix.
|
||||||
|
func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
|
||||||
|
paths := map[string]WritablePath{}
|
||||||
|
for _, jar := range l.jars {
|
||||||
|
paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
|
||||||
|
}
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalJSON converts JSON configuration from raw bytes into a
|
// UnmarshalJSON converts JSON configuration from raw bytes into a
|
||||||
// ConfiguredJarList structure.
|
// ConfiguredJarList structure.
|
||||||
func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
|
func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
|
||||||
|
|
|
@ -4546,7 +4546,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
|
||||||
// prebuilt_apex module always depends on the prebuilt, and so it doesn't
|
// prebuilt_apex module always depends on the prebuilt, and so it doesn't
|
||||||
// find the dex boot jar in it. We either need to disable the source libfoo
|
// find the dex boot jar in it. We either need to disable the source libfoo
|
||||||
// or make the prebuilt libfoo preferred.
|
// or make the prebuilt libfoo preferred.
|
||||||
testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", preparer)
|
testDexpreoptWithApexes(t, bp, "module libfoo does not provide a dex boot jar", preparer)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("prebuilt library preferred with source", func(t *testing.T) {
|
t.Run("prebuilt library preferred with source", func(t *testing.T) {
|
||||||
|
|
|
@ -648,7 +648,8 @@ func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the dex jars of this fragment's content modules to their predefined locations.
|
// Copy the dex jars of this fragment's content modules to their predefined locations.
|
||||||
copyBootJarsToPredefinedLocations(ctx, contents, imageConfig.modules, imageConfig.dexPaths)
|
bootDexJarByModule := extractEncodedDexJarsFromModules(ctx, contents)
|
||||||
|
copyBootJarsToPredefinedLocations(ctx, bootDexJarByModule, imageConfig.dexPathsByModule)
|
||||||
|
|
||||||
// Build a profile for the image config and then use that to build the boot image.
|
// Build a profile for the image config and then use that to build the boot image.
|
||||||
profile := bootImageProfileRule(ctx, imageConfig)
|
profile := bootImageProfileRule(ctx, imageConfig)
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
package java
|
package java
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -254,6 +253,9 @@ type bootImageConfig struct {
|
||||||
dexPaths android.WritablePaths // for this image
|
dexPaths android.WritablePaths // for this image
|
||||||
dexPathsDeps android.WritablePaths // for the dependency images and in this image
|
dexPathsDeps android.WritablePaths // for the dependency images and in this image
|
||||||
|
|
||||||
|
// Map from module name (without prebuilt_ prefix) to the predefined build path.
|
||||||
|
dexPathsByModule map[string]android.WritablePath
|
||||||
|
|
||||||
// File path to a zip archive with all image files (or nil, if not needed).
|
// File path to a zip archive with all image files (or nil, if not needed).
|
||||||
zip android.WritablePath
|
zip android.WritablePath
|
||||||
|
|
||||||
|
@ -461,53 +463,27 @@ func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to
|
// copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined
|
||||||
// predefined paths in the global config.
|
// paths in the global config.
|
||||||
func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, bootModules []android.Module, bootjars android.ConfiguredJarList, jarPathsPredefined android.WritablePaths) {
|
func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
|
||||||
jarPaths := make(android.Paths, bootjars.Len())
|
// Create the super set of module names.
|
||||||
for i, module := range bootModules {
|
names := []string{}
|
||||||
if module != nil {
|
names = append(names, android.SortedStringKeys(srcBootDexJarsByModule)...)
|
||||||
bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
|
names = append(names, android.SortedStringKeys(dstBootJarsByModule)...)
|
||||||
jarPaths[i] = bootDexJar
|
names = android.SortedUniqueStrings(names)
|
||||||
|
for _, name := range names {
|
||||||
name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(module))
|
src := srcBootDexJarsByModule[name]
|
||||||
if bootjars.Jar(i) != name {
|
dst := dstBootJarsByModule[name]
|
||||||
ctx.ModuleErrorf("expected module %s at position %d but found %s", bootjars.Jar(i), i, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// Java libraries and apps). Generate rules that copy bootclasspath DEX jars to the predefined
|
|
||||||
// paths.
|
|
||||||
for i := range jarPaths {
|
|
||||||
input := jarPaths[i]
|
|
||||||
output := jarPathsPredefined[i]
|
|
||||||
module := bootjars.Jar(i)
|
|
||||||
if input == nil {
|
|
||||||
if ctx.Config().AllowMissingDependencies() {
|
|
||||||
apex := bootjars.Apex(i)
|
|
||||||
|
|
||||||
// Create an error rule that pretends to create the output file but will actually fail if it
|
|
||||||
// is run.
|
|
||||||
ctx.Build(pctx, android.BuildParams{
|
|
||||||
Rule: android.ErrorRule,
|
|
||||||
Output: output,
|
|
||||||
Args: map[string]string{
|
|
||||||
"error": fmt.Sprintf("missing dependencies: dex jar for %s:%s", module, apex),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ctx.ModuleErrorf("failed to find a dex jar path for module '%s'"+
|
|
||||||
", note that some jars may be filtered out by module constraints", module)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if src == nil {
|
||||||
|
ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
|
||||||
|
} else if dst == nil {
|
||||||
|
ctx.ModuleErrorf("module %s is not part of the boot configuration", name)
|
||||||
} else {
|
} else {
|
||||||
ctx.Build(pctx, android.BuildParams{
|
ctx.Build(pctx, android.BuildParams{
|
||||||
Rule: android.Cp,
|
Rule: android.Cp,
|
||||||
Input: input,
|
Input: src,
|
||||||
Output: output,
|
Output: dst,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
|
||||||
// TODO(b/143682396): use module dependencies instead
|
// TODO(b/143682396): use module dependencies instead
|
||||||
inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
|
inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
|
||||||
c.dexPaths = c.modules.BuildPaths(ctx, inputDir)
|
c.dexPaths = c.modules.BuildPaths(ctx, inputDir)
|
||||||
|
c.dexPathsByModule = c.modules.BuildPathsByModule(ctx, inputDir)
|
||||||
c.dexPathsDeps = c.dexPaths
|
c.dexPathsDeps = c.dexPaths
|
||||||
|
|
||||||
// Create target-specific variants.
|
// Create target-specific variants.
|
||||||
|
@ -153,6 +154,9 @@ type updatableBootConfig struct {
|
||||||
// later on a singleton adds commands to copy actual jars to the predefined paths.
|
// later on a singleton adds commands to copy actual jars to the predefined paths.
|
||||||
dexPaths android.WritablePaths
|
dexPaths android.WritablePaths
|
||||||
|
|
||||||
|
// Map from module name (without prebuilt_ prefix) to the predefined build path.
|
||||||
|
dexPathsByModule map[string]android.WritablePath
|
||||||
|
|
||||||
// A list of dex locations (a.k.a. on-device paths) to the boot jars.
|
// A list of dex locations (a.k.a. on-device paths) to the boot jars.
|
||||||
dexLocations []string
|
dexLocations []string
|
||||||
}
|
}
|
||||||
|
@ -166,10 +170,11 @@ func GetUpdatableBootConfig(ctx android.PathContext) updatableBootConfig {
|
||||||
|
|
||||||
dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "updatable_bootjars")
|
dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "updatable_bootjars")
|
||||||
dexPaths := updatableBootJars.BuildPaths(ctx, dir)
|
dexPaths := updatableBootJars.BuildPaths(ctx, dir)
|
||||||
|
dexPathsByModuleName := updatableBootJars.BuildPathsByModule(ctx, dir)
|
||||||
|
|
||||||
dexLocations := updatableBootJars.DevicePaths(ctx.Config(), android.Android)
|
dexLocations := updatableBootJars.DevicePaths(ctx.Config(), android.Android)
|
||||||
|
|
||||||
return updatableBootConfig{updatableBootJars, dexPaths, dexLocations}
|
return updatableBootConfig{updatableBootJars, dexPaths, dexPathsByModuleName, dexLocations}
|
||||||
}).(updatableBootConfig)
|
}).(updatableBootConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -571,6 +571,15 @@ type HiddenAPIFlagOutput struct {
|
||||||
AllFlagsPath android.Path
|
AllFlagsPath android.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
|
||||||
|
// path.
|
||||||
|
type bootDexJarByModule map[string]android.Path
|
||||||
|
|
||||||
|
// addPath adds the path for a module to the map.
|
||||||
|
func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
|
||||||
|
b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
|
||||||
|
}
|
||||||
|
|
||||||
// pathForValidation creates a path of the same type as the supplied type but with a name of
|
// pathForValidation creates a path of the same type as the supplied type but with a name of
|
||||||
// <path>.valid.
|
// <path>.valid.
|
||||||
//
|
//
|
||||||
|
@ -792,3 +801,113 @@ func extractClassJarsFromHiddenAPIModules(ctx android.ModuleContext, contents []
|
||||||
}
|
}
|
||||||
return classesJars
|
return classesJars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
|
||||||
|
// Soong but should instead only be reported in ninja if the file is actually built.
|
||||||
|
func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
|
||||||
|
// TODO(b/179354495): Remove this workaround when it is unnecessary.
|
||||||
|
// Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
|
||||||
|
// create a fake one that will cause a build error only if it is used.
|
||||||
|
if ctx.Config().AlwaysUsePrebuiltSdks() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called for both platform_bootclasspath and bootclasspath_fragment modules.
|
||||||
|
//
|
||||||
|
// A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
|
||||||
|
// Ideally, a bootclasspath_fragment module should never have a platform variant created for it
|
||||||
|
// but unfortunately, due to b/187910671 it does.
|
||||||
|
//
|
||||||
|
// That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
|
||||||
|
// used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
|
||||||
|
// has an APEX variant not a platform variant.
|
||||||
|
//
|
||||||
|
// There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
|
||||||
|
// provide a boot dex jar:
|
||||||
|
// 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
|
||||||
|
// does not have an APEX variant and only has a platform variant and neither do its content
|
||||||
|
// modules.
|
||||||
|
// 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
|
||||||
|
// java_sdk_library_import modules to be treated as preferred and as many of them are not part
|
||||||
|
// of an apex they cannot provide a boot dex jar.
|
||||||
|
//
|
||||||
|
// The first case causes problems when the affected prebuilt modules are preferred but that is an
|
||||||
|
// invalid configuration and it is ok for it to fail as the work to enable that is not yet
|
||||||
|
// complete. The second case is used for building targets that do not use boot dex jars and so
|
||||||
|
// deferring error reporting to ninja is fine as the affected ninja targets should never be built.
|
||||||
|
// That is handled above.
|
||||||
|
//
|
||||||
|
// A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
|
||||||
|
// the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
|
||||||
|
// can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
|
||||||
|
// that if the library can be part of an APEX then it is the APEX variant that is used.
|
||||||
|
//
|
||||||
|
// This check handles the slightly different requirements of the bootclasspath_fragment and
|
||||||
|
// platform_bootclasspath modules by only deferring error reporting for the platform variant of
|
||||||
|
// a prebuilt modules that has other variants which are part of an APEX.
|
||||||
|
//
|
||||||
|
// TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
|
||||||
|
if android.IsModulePrebuilt(module) {
|
||||||
|
if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
|
||||||
|
apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
|
||||||
|
if apexInfo.IsForPlatform() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
|
||||||
|
// is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
|
||||||
|
// versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
|
||||||
|
// failures missing boot dex jars need to be deferred.
|
||||||
|
if android.IsModuleInVersionedSdk(ctx.Module()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
|
||||||
|
// file depending on the value returned from deferReportingMissingBootDexJar.
|
||||||
|
func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
|
||||||
|
if deferReportingMissingBootDexJar(ctx, module) {
|
||||||
|
// Create an error rule that pretends to create the output file but will actually fail if it
|
||||||
|
// is run.
|
||||||
|
ctx.Build(pctx, android.BuildParams{
|
||||||
|
Rule: android.ErrorRule,
|
||||||
|
Output: fake,
|
||||||
|
Args: map[string]string{
|
||||||
|
"error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctx.ModuleErrorf("module %s does not provide a dex jar", module)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
|
||||||
|
// DexJarBuildPath() method.
|
||||||
|
//
|
||||||
|
// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
|
||||||
|
// However, under certain conditions, e.g. errors, or special build configurations it will return
|
||||||
|
// a path to a fake file.
|
||||||
|
func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
|
||||||
|
bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
|
||||||
|
if bootDexJar == nil {
|
||||||
|
fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
|
||||||
|
bootDexJar = fake
|
||||||
|
|
||||||
|
handleMissingDexBootFile(ctx, module, fake)
|
||||||
|
}
|
||||||
|
return bootDexJar
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
|
||||||
|
func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
|
||||||
|
encodedDexJarsByModuleName := bootDexJarByModule{}
|
||||||
|
for _, module := range contents {
|
||||||
|
path := retrieveEncodedBootDexJarFromModule(ctx, module)
|
||||||
|
encodedDexJarsByModuleName.addPath(module, path)
|
||||||
|
}
|
||||||
|
return encodedDexJarsByModuleName
|
||||||
|
}
|
||||||
|
|
|
@ -389,11 +389,13 @@ func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.
|
||||||
generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
|
generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules)
|
||||||
|
|
||||||
// Copy non-updatable module dex jars to their predefined locations.
|
// Copy non-updatable module dex jars to their predefined locations.
|
||||||
copyBootJarsToPredefinedLocations(ctx, nonUpdatableModules, imageConfig.modules, imageConfig.dexPaths)
|
nonUpdatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, nonUpdatableModules)
|
||||||
|
copyBootJarsToPredefinedLocations(ctx, nonUpdatableBootDexJarsByModule, imageConfig.dexPathsByModule)
|
||||||
|
|
||||||
// Copy updatable module dex jars to their predefined locations.
|
// Copy updatable module dex jars to their predefined locations.
|
||||||
config := GetUpdatableBootConfig(ctx)
|
config := GetUpdatableBootConfig(ctx)
|
||||||
copyBootJarsToPredefinedLocations(ctx, updatableModules, config.modules, config.dexPaths)
|
updatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, updatableModules)
|
||||||
|
copyBootJarsToPredefinedLocations(ctx, updatableBootDexJarsByModule, config.dexPathsByModule)
|
||||||
|
|
||||||
// Build a profile for the image config and then use that to build the boot image.
|
// Build a profile for the image config and then use that to build the boot image.
|
||||||
profile := bootImageProfileRule(ctx, imageConfig)
|
profile := bootImageProfileRule(ctx, imageConfig)
|
||||||
|
|
Loading…
Reference in New Issue