Merge "Fix boot jar handling when both source and prebuilt APEXes and modules are present."
This commit is contained in:
commit
c4e17317d1
|
@ -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 {
|
||||||
|
|
|
@ -4398,6 +4398,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 {
|
||||||
|
@ -6002,10 +6211,11 @@ 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,
|
||||||
"framework/aidl/a.aidl": nil,
|
"framework/aidl/a.aidl": nil,
|
||||||
}
|
}
|
||||||
cc.GatherRequiredFilesForTest(fs)
|
cc.GatherRequiredFilesForTest(fs)
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -486,7 +486,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
|
||||||
}
|
}
|
||||||
|
@ -496,7 +496,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
|
||||||
|
@ -523,21 +523,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",
|
||||||
|
@ -867,6 +863,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