Fix boot jar handling when both source and prebuilt APEXes and modules
are present. 1) The boot jar to APEX mapping is maintained by the base names for both of them. When building with prebuilt modules and APEXes, that means we need to take care to compare them without regard to any "prebuilt_" prefixes. 2) VisitAllModules can visit disabled modules and both source and prebuilt modules, so they need some conditions to skip modules that aren't applicable for boot jars. Test: `m droid` Test: `m droid SOONG_CONFIG_art_module_source_build=false` with fresh ART Module prebuilts in place Bug: 171061220 Change-Id: Iced269d29127bc8b8f9b3171adb60a97d115628b
This commit is contained in:
parent
57eec1007e
commit
1dc0d6d7f2
|
@ -111,6 +111,19 @@ func (i ApexInfo) InApex(apex string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InApexByBaseName tells whether this apex variant of the module is part of the given APEX or not,
|
||||||
|
// where the APEX is specified by its canonical base name, i.e. typically beginning with
|
||||||
|
// "com.android.". In particular this function doesn't differentiate between source and prebuilt
|
||||||
|
// APEXes, where the latter may have "prebuilt_" prefixes.
|
||||||
|
func (i ApexInfo) InApexByBaseName(apex string) bool {
|
||||||
|
for _, a := range i.InApexes {
|
||||||
|
if RemoveOptionalPrebuiltPrefix(a) == apex {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// ApexTestForInfo stores the contents of APEXes for which this module is a test - although this
|
// ApexTestForInfo stores the contents of APEXes for which this module is a test - although this
|
||||||
// module is not part of the APEX - and thus has access to APEX internals.
|
// module is not part of the APEX - and thus has access to APEX internals.
|
||||||
type ApexTestForInfo struct {
|
type ApexTestForInfo struct {
|
||||||
|
|
|
@ -4330,6 +4330,215 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
|
||||||
|
transform := func(config *dexpreopt.GlobalConfig) {
|
||||||
|
config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo"})
|
||||||
|
}
|
||||||
|
|
||||||
|
checkBootDexJarPath := func(ctx *android.TestContext, bootDexJarPath string) {
|
||||||
|
s := ctx.SingletonForTests("dex_bootjars")
|
||||||
|
foundLibfooJar := false
|
||||||
|
for _, output := range s.AllOutputs() {
|
||||||
|
if strings.HasSuffix(output, "/libfoo.jar") {
|
||||||
|
foundLibfooJar = true
|
||||||
|
buildRule := s.Output(output)
|
||||||
|
actual := android.NormalizePathForTesting(buildRule.Input)
|
||||||
|
if actual != bootDexJarPath {
|
||||||
|
t.Errorf("Incorrect boot dex jar path '%s', expected '%s'", actual, bootDexJarPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundLibfooJar {
|
||||||
|
t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("prebuilt only", func(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
prebuilt_apex {
|
||||||
|
name: "myapex",
|
||||||
|
arch: {
|
||||||
|
arm64: {
|
||||||
|
src: "myapex-arm64.apex",
|
||||||
|
},
|
||||||
|
arm: {
|
||||||
|
src: "myapex-arm.apex",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exported_java_libs: ["libfoo"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "libfoo",
|
||||||
|
jars: ["libfoo.jar"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
ctx := testDexpreoptWithApexes(t, bp, "", transform)
|
||||||
|
checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("prebuilt with source library preferred", func(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
prebuilt_apex {
|
||||||
|
name: "myapex",
|
||||||
|
arch: {
|
||||||
|
arm64: {
|
||||||
|
src: "myapex-arm64.apex",
|
||||||
|
},
|
||||||
|
arm: {
|
||||||
|
src: "myapex-arm.apex",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exported_java_libs: ["libfoo"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "libfoo",
|
||||||
|
jars: ["libfoo.jar"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "libfoo",
|
||||||
|
srcs: ["foo/bar/MyClass.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// In this test the source (java_library) libfoo is active since the
|
||||||
|
// prebuilt (java_import) defaults to prefer:false. However the
|
||||||
|
// 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
|
||||||
|
// or make the prebuilt libfoo preferred.
|
||||||
|
testDexpreoptWithApexes(t, bp, "failed to find a dex jar path for module 'libfoo'", transform)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("prebuilt library preferred with source", func(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
prebuilt_apex {
|
||||||
|
name: "myapex",
|
||||||
|
arch: {
|
||||||
|
arm64: {
|
||||||
|
src: "myapex-arm64.apex",
|
||||||
|
},
|
||||||
|
arm: {
|
||||||
|
src: "myapex-arm.apex",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exported_java_libs: ["libfoo"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "libfoo",
|
||||||
|
prefer: true,
|
||||||
|
jars: ["libfoo.jar"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "libfoo",
|
||||||
|
srcs: ["foo/bar/MyClass.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
ctx := testDexpreoptWithApexes(t, bp, "", transform)
|
||||||
|
checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("prebuilt with source apex preferred", func(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
key: "myapex.key",
|
||||||
|
java_libs: ["libfoo"],
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
prebuilt_apex {
|
||||||
|
name: "myapex",
|
||||||
|
arch: {
|
||||||
|
arm64: {
|
||||||
|
src: "myapex-arm64.apex",
|
||||||
|
},
|
||||||
|
arm: {
|
||||||
|
src: "myapex-arm.apex",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exported_java_libs: ["libfoo"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "libfoo",
|
||||||
|
jars: ["libfoo.jar"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "libfoo",
|
||||||
|
srcs: ["foo/bar/MyClass.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
ctx := testDexpreoptWithApexes(t, bp, "", transform)
|
||||||
|
checkBootDexJarPath(ctx, ".intermediates/libfoo/android_common_apex10000/aligned/libfoo.jar")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("prebuilt preferred with source apex disabled", func(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
enabled: false,
|
||||||
|
key: "myapex.key",
|
||||||
|
java_libs: ["libfoo"],
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
prebuilt_apex {
|
||||||
|
name: "myapex",
|
||||||
|
arch: {
|
||||||
|
arm64: {
|
||||||
|
src: "myapex-arm64.apex",
|
||||||
|
},
|
||||||
|
arm: {
|
||||||
|
src: "myapex-arm.apex",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exported_java_libs: ["libfoo"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_import {
|
||||||
|
name: "libfoo",
|
||||||
|
prefer: true,
|
||||||
|
jars: ["libfoo.jar"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "libfoo",
|
||||||
|
srcs: ["foo/bar/MyClass.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
ctx := testDexpreoptWithApexes(t, bp, "", transform)
|
||||||
|
checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestApexWithTests(t *testing.T) {
|
func TestApexWithTests(t *testing.T) {
|
||||||
ctx, config := testApex(t, `
|
ctx, config := testApex(t, `
|
||||||
apex_test {
|
apex_test {
|
||||||
|
@ -5934,6 +6143,7 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreopt
|
||||||
"build/make/target/product/security": nil,
|
"build/make/target/product/security": nil,
|
||||||
"apex_manifest.json": nil,
|
"apex_manifest.json": nil,
|
||||||
"AndroidManifest.xml": nil,
|
"AndroidManifest.xml": nil,
|
||||||
|
"system/sepolicy/apex/myapex-file_contexts": nil,
|
||||||
"system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
|
"system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
|
||||||
"system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil,
|
"system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil,
|
||||||
"system/sepolicy/apex/com.android.art.debug-file_contexts": nil,
|
"system/sepolicy/apex/com.android.art.debug-file_contexts": nil,
|
||||||
|
|
|
@ -49,14 +49,36 @@ func populateMapFromConfiguredJarList(ctx android.SingletonContext, moduleToApex
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isActiveModule returns true if the given module should be considered for boot
|
||||||
|
// jars, i.e. if it's enabled and the preferred one in case of source and
|
||||||
|
// prebuilt alternatives.
|
||||||
|
func isActiveModule(module android.Module) bool {
|
||||||
|
if !module.Enabled() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if module.IsReplacedByPrebuilt() {
|
||||||
|
// A source module that has been replaced by a prebuilt counterpart.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if prebuilt, ok := module.(android.PrebuiltInterface); ok {
|
||||||
|
if p := prebuilt.Prebuilt(); p != nil {
|
||||||
|
return p.UsePrebuilt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
||||||
config := ctx.Config()
|
config := ctx.Config()
|
||||||
if config.SkipBootJarsCheck() {
|
if config.SkipBootJarsCheck() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate a map from module name to APEX from the boot jars. If there is a problem
|
// Populate a map from module name to APEX from the boot jars. If there is a
|
||||||
// such as duplicate modules then fail and return immediately.
|
// problem such as duplicate modules then fail and return immediately. Note
|
||||||
|
// that both module and APEX names are tracked by base names here, so we need
|
||||||
|
// to be careful to remove "prebuilt_" prefixes when comparing them with
|
||||||
|
// actual modules and APEX bundles.
|
||||||
moduleToApex := make(map[string]string)
|
moduleToApex := make(map[string]string)
|
||||||
if !populateMapFromConfiguredJarList(ctx, moduleToApex, config.NonUpdatableBootJars(), "BootJars") ||
|
if !populateMapFromConfiguredJarList(ctx, moduleToApex, config.NonUpdatableBootJars(), "BootJars") ||
|
||||||
!populateMapFromConfiguredJarList(ctx, moduleToApex, config.UpdatableBootJars(), "UpdatableBootJars") {
|
!populateMapFromConfiguredJarList(ctx, moduleToApex, config.UpdatableBootJars(), "UpdatableBootJars") {
|
||||||
|
@ -69,10 +91,14 @@ func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
||||||
// Scan all the modules looking for the module/apex variants corresponding to the
|
// Scan all the modules looking for the module/apex variants corresponding to the
|
||||||
// boot jars.
|
// boot jars.
|
||||||
ctx.VisitAllModules(func(module android.Module) {
|
ctx.VisitAllModules(func(module android.Module) {
|
||||||
name := ctx.ModuleName(module)
|
if !isActiveModule(module) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
|
||||||
if apex, ok := moduleToApex[name]; ok {
|
if apex, ok := moduleToApex[name]; ok {
|
||||||
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
|
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
|
||||||
if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApex(apex) {
|
if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexByBaseName(apex) {
|
||||||
// The module name/apex variant should be unique in the system but double check
|
// The module name/apex variant should be unique in the system but double check
|
||||||
// just in case something has gone wrong.
|
// just in case something has gone wrong.
|
||||||
if existing, ok := nameToApexVariant[name]; ok {
|
if existing, ok := nameToApexVariant[name]; ok {
|
||||||
|
|
|
@ -479,7 +479,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
|
||||||
// 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 -1, nil
|
||||||
}
|
}
|
||||||
} else if !android.InList(requiredApex, apexInfo.InApexes) {
|
} 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 -1, nil
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
|
||||||
|
|
||||||
switch image.name {
|
switch image.name {
|
||||||
case artBootImageName:
|
case artBootImageName:
|
||||||
if len(apexInfo.InApexes) > 0 && allHavePrefix(apexInfo.InApexes, "com.android.art") {
|
if apexInfo.InApexByBaseName("com.android.art") || apexInfo.InApexByBaseName("com.android.art.debug") || apexInfo.InApexByBaseName("com.android.art,testing") {
|
||||||
// ok: found the jar in the ART apex
|
// ok: found the jar in the ART apex
|
||||||
} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
|
} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
|
||||||
// exception (skip and continue): Jacoco platform variant for a coverage build
|
// exception (skip and continue): Jacoco platform variant for a coverage build
|
||||||
|
@ -516,21 +516,17 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
|
||||||
return index, jar.DexJarBuildPath()
|
return index, jar.DexJarBuildPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
func allHavePrefix(list []string, prefix string) bool {
|
|
||||||
for _, s := range list {
|
|
||||||
if s != prefix && !strings.HasPrefix(s, prefix+".") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) *bootImageConfig {
|
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
|
||||||
// Collect dex jar paths for the boot image modules.
|
// Collect dex jar paths for the boot image modules.
|
||||||
// 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.
|
||||||
bootDexJars := make(android.Paths, image.modules.Len())
|
bootDexJars := make(android.Paths, image.modules.Len())
|
||||||
|
|
||||||
ctx.VisitAllModules(func(module android.Module) {
|
ctx.VisitAllModules(func(module android.Module) {
|
||||||
|
if !isActiveModule(module) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if i, j := getBootImageJar(ctx, image, module); i != -1 {
|
if i, j := getBootImageJar(ctx, image, module); i != -1 {
|
||||||
if existing := bootDexJars[i]; existing != nil {
|
if existing := bootDexJars[i]; existing != nil {
|
||||||
ctx.Errorf("Multiple dex jars found for %s:%s - %s and %s",
|
ctx.Errorf("Multiple dex jars found for %s:%s - %s and %s",
|
||||||
|
@ -860,6 +856,9 @@ func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConf
|
||||||
// Collect `permitted_packages` for updatable boot jars.
|
// Collect `permitted_packages` for updatable boot jars.
|
||||||
var updatablePackages []string
|
var updatablePackages []string
|
||||||
ctx.VisitAllModules(func(module android.Module) {
|
ctx.VisitAllModules(func(module android.Module) {
|
||||||
|
if !isActiveModule(module) {
|
||||||
|
return
|
||||||
|
}
|
||||||
if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
|
if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
|
||||||
name := ctx.ModuleName(module)
|
name := ctx.ModuleName(module)
|
||||||
if i := android.IndexList(name, updatableModules); i != -1 {
|
if i := android.IndexList(name, updatableModules); i != -1 {
|
||||||
|
|
Loading…
Reference in New Issue