Merge "Fix boot jar handling when both source and prebuilt APEXes and modules are present."
This commit is contained in:
commit
c4e17317d1
4 changed files with 264 additions and 16 deletions
|
@ -111,6 +111,19 @@ func (i ApexInfo) InApex(apex string) bool {
|
|||
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
|
||||
// module is not part of the APEX - and thus has access to APEX internals.
|
||||
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) {
|
||||
ctx, config := testApex(t, `
|
||||
apex_test {
|
||||
|
@ -6002,10 +6211,11 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreopt
|
|||
"build/make/target/product/security": nil,
|
||||
"apex_manifest.json": nil,
|
||||
"AndroidManifest.xml": nil,
|
||||
"system/sepolicy/apex/myapex-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/com.android.art.debug-file_contexts": nil,
|
||||
"framework/aidl/a.aidl": nil,
|
||||
"framework/aidl/a.aidl": nil,
|
||||
}
|
||||
cc.GatherRequiredFilesForTest(fs)
|
||||
|
||||
|
|
|
@ -49,14 +49,36 @@ func populateMapFromConfiguredJarList(ctx android.SingletonContext, moduleToApex
|
|||
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) {
|
||||
config := ctx.Config()
|
||||
if config.SkipBootJarsCheck() {
|
||||
return
|
||||
}
|
||||
|
||||
// Populate a map from module name to APEX from the boot jars. If there is a problem
|
||||
// such as duplicate modules then fail and return immediately.
|
||||
// Populate a map from module name to APEX from the boot jars. If there is a
|
||||
// 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)
|
||||
if !populateMapFromConfiguredJarList(ctx, moduleToApex, config.NonUpdatableBootJars(), "BootJars") ||
|
||||
!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
|
||||
// boot jars.
|
||||
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 {
|
||||
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
|
||||
// just in case something has gone wrong.
|
||||
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.
|
||||
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.
|
||||
return -1, nil
|
||||
}
|
||||
|
@ -496,7 +496,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul
|
|||
|
||||
switch image.name {
|
||||
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
|
||||
} else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
|
||||
// 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()
|
||||
}
|
||||
|
||||
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.
|
||||
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
|
||||
// Collect dex jar paths for the boot image modules.
|
||||
// This logic is tested in the apex package to avoid import cycle apex <-> java.
|
||||
bootDexJars := make(android.Paths, image.modules.Len())
|
||||
|
||||
ctx.VisitAllModules(func(module android.Module) {
|
||||
if !isActiveModule(module) {
|
||||
return
|
||||
}
|
||||
|
||||
if i, j := getBootImageJar(ctx, image, module); i != -1 {
|
||||
if existing := bootDexJars[i]; existing != nil {
|
||||
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.
|
||||
var updatablePackages []string
|
||||
ctx.VisitAllModules(func(module android.Module) {
|
||||
if !isActiveModule(module) {
|
||||
return
|
||||
}
|
||||
if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok {
|
||||
name := ctx.ModuleName(module)
|
||||
if i := android.IndexList(name, updatableModules); i != -1 {
|
||||
|
|
Loading…
Reference in a new issue