Allow contents and image_name to be specified together
Previously, only one of the contents or image_name properties could be specified at once which meant that there was no way to create a prebuilt which lists its fixed contents while at the same time allowing it to check that that the contents matched what the build configuration required. e.g. a prebuilt_bootclasspath_fragment that had image_name: "art", could not list its contents and also check that those contents matched the ART_APEX_JARS which the build configuration required. This change allows contents and image_name to be specified together and adds a check to make sure that the contents are consistent with the configuration appropriate to the image_name. The check is only performed for modules that are active so that a prebuilt_bootclasspath_fragment which was created without coverage enabled (the default) would not cause a build failure in a coverage build unless it was preferred. Bug: 177892522 Test: m nothing Change-Id: Ie601f29f707b3f6030fa7d252afa2c4826cc9f8e
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
package apex
|
package apex
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -162,13 +163,11 @@ func checkBootclasspathFragment(t *testing.T, result *android.TestResult, module
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBootclasspathFragmentInArtApex(t *testing.T) {
|
func TestBootclasspathFragmentInArtApex(t *testing.T) {
|
||||||
result := android.GroupFixturePreparers(
|
commonPreparer := android.GroupFixturePreparers(
|
||||||
prepareForTestWithBootclasspathFragment,
|
prepareForTestWithBootclasspathFragment,
|
||||||
prepareForTestWithArtApex,
|
prepareForTestWithArtApex,
|
||||||
|
|
||||||
// Configure some libraries in the art bootclasspath_fragment.
|
android.FixtureWithRootAndroidBp(`
|
||||||
java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
|
|
||||||
).RunTestWithBp(t, `
|
|
||||||
apex {
|
apex {
|
||||||
name: "com.android.art",
|
name: "com.android.art",
|
||||||
key: "com.android.art.key",
|
key: "com.android.art.key",
|
||||||
@@ -208,14 +207,6 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
bootclasspath_fragment {
|
|
||||||
name: "mybootclasspathfragment",
|
|
||||||
image_name: "art",
|
|
||||||
apex_available: [
|
|
||||||
"com.android.art",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
java_import {
|
java_import {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
jars: ["foo.jar"],
|
jars: ["foo.jar"],
|
||||||
@@ -231,17 +222,59 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
|
|||||||
"com.android.art",
|
"com.android.art",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
`),
|
||||||
|
)
|
||||||
|
|
||||||
// Make sure that a preferred prebuilt doesn't affect the apex.
|
contentsInsert := func(contents []string) string {
|
||||||
prebuilt_bootclasspath_fragment {
|
insert := ""
|
||||||
|
if contents != nil {
|
||||||
|
insert = fmt.Sprintf(`contents: ["%s"],`, strings.Join(contents, `", "`))
|
||||||
|
}
|
||||||
|
return insert
|
||||||
|
}
|
||||||
|
|
||||||
|
addSource := func(contents ...string) android.FixturePreparer {
|
||||||
|
text := fmt.Sprintf(`
|
||||||
|
bootclasspath_fragment {
|
||||||
name: "mybootclasspathfragment",
|
name: "mybootclasspathfragment",
|
||||||
image_name: "art",
|
image_name: "art",
|
||||||
prefer: true,
|
%s
|
||||||
apex_available: [
|
apex_available: [
|
||||||
"com.android.art",
|
"com.android.art",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
`)
|
`, contentsInsert(contents))
|
||||||
|
|
||||||
|
return android.FixtureAddTextFile("art/build/boot/Android.bp", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
addPrebuilt := func(prefer bool, contents ...string) android.FixturePreparer {
|
||||||
|
text := fmt.Sprintf(`
|
||||||
|
prebuilt_bootclasspath_fragment {
|
||||||
|
name: "mybootclasspathfragment",
|
||||||
|
image_name: "art",
|
||||||
|
%s
|
||||||
|
prefer: %t,
|
||||||
|
apex_available: [
|
||||||
|
"com.android.art",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`, contentsInsert(contents), prefer)
|
||||||
|
return android.FixtureAddTextFile("prebuilts/module_sdk/art/Android.bp", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("boot image files", func(t *testing.T) {
|
||||||
|
result := android.GroupFixturePreparers(
|
||||||
|
commonPreparer,
|
||||||
|
|
||||||
|
// Configure some libraries in the art bootclasspath_fragment that match the source
|
||||||
|
// bootclasspath_fragment's contents property.
|
||||||
|
java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
|
||||||
|
addSource("foo", "bar"),
|
||||||
|
|
||||||
|
// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
|
||||||
|
addPrebuilt(true, "foo", "bar"),
|
||||||
|
).RunTest(t)
|
||||||
|
|
||||||
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
|
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
|
||||||
"javalib/arm/boot.art",
|
"javalib/arm/boot.art",
|
||||||
@@ -265,6 +298,66 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
|
|||||||
`com.android.art.key`,
|
`com.android.art.key`,
|
||||||
`mybootclasspathfragment`,
|
`mybootclasspathfragment`,
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("source with inconsistency between config and contents", func(t *testing.T) {
|
||||||
|
android.GroupFixturePreparers(
|
||||||
|
commonPreparer,
|
||||||
|
|
||||||
|
// Create an inconsistency between the ArtApexJars configuration and the art source
|
||||||
|
// bootclasspath_fragment module's contents property.
|
||||||
|
java.FixtureConfigureBootJars("com.android.art:foo"),
|
||||||
|
addSource("foo", "bar"),
|
||||||
|
).
|
||||||
|
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
|
||||||
|
RunTest(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("prebuilt with inconsistency between config and contents", func(t *testing.T) {
|
||||||
|
android.GroupFixturePreparers(
|
||||||
|
commonPreparer,
|
||||||
|
|
||||||
|
// Create an inconsistency between the ArtApexJars configuration and the art
|
||||||
|
// prebuilt_bootclasspath_fragment module's contents property.
|
||||||
|
java.FixtureConfigureBootJars("com.android.art:foo"),
|
||||||
|
addPrebuilt(false, "foo", "bar"),
|
||||||
|
).
|
||||||
|
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
|
||||||
|
RunTest(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("preferred prebuilt with inconsistency between config and contents", func(t *testing.T) {
|
||||||
|
android.GroupFixturePreparers(
|
||||||
|
commonPreparer,
|
||||||
|
|
||||||
|
// Create an inconsistency between the ArtApexJars configuration and the art
|
||||||
|
// prebuilt_bootclasspath_fragment module's contents property.
|
||||||
|
java.FixtureConfigureBootJars("com.android.art:foo"),
|
||||||
|
addPrebuilt(true, "foo", "bar"),
|
||||||
|
|
||||||
|
// Source contents property is consistent with the config.
|
||||||
|
addSource("foo"),
|
||||||
|
).
|
||||||
|
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
|
||||||
|
RunTest(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("source preferred and prebuilt with inconsistency between config and contents", func(t *testing.T) {
|
||||||
|
android.GroupFixturePreparers(
|
||||||
|
commonPreparer,
|
||||||
|
|
||||||
|
// Create an inconsistency between the ArtApexJars configuration and the art
|
||||||
|
// prebuilt_bootclasspath_fragment module's contents property.
|
||||||
|
java.FixtureConfigureBootJars("com.android.art:foo"),
|
||||||
|
addPrebuilt(false, "foo", "bar"),
|
||||||
|
|
||||||
|
// Source contents property is consistent with the config.
|
||||||
|
addSource("foo"),
|
||||||
|
|
||||||
|
// This should pass because while the prebuilt is inconsistent with the configuration it is
|
||||||
|
// not actually used.
|
||||||
|
).RunTest(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
||||||
|
@@ -17,6 +17,7 @@ package java
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
@@ -128,8 +129,10 @@ func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext,
|
|||||||
if m.properties.Image_name == nil && len(contents) == 0 {
|
if m.properties.Image_name == nil && len(contents) == 0 {
|
||||||
ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
|
ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
|
||||||
}
|
}
|
||||||
if m.properties.Image_name != nil && len(contents) != 0 {
|
|
||||||
ctx.ModuleErrorf(`both of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
|
if len(contents) != 0 {
|
||||||
|
// Nothing to do.
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
imageName := proptools.String(m.properties.Image_name)
|
imageName := proptools.String(m.properties.Image_name)
|
||||||
@@ -154,7 +157,6 @@ func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext,
|
|||||||
|
|
||||||
// Make sure that the apex specified in the configuration is consistent and is one for which
|
// Make sure that the apex specified in the configuration is consistent and is one for which
|
||||||
// this boot image is available.
|
// this boot image is available.
|
||||||
jars := []string{}
|
|
||||||
commonApex := ""
|
commonApex := ""
|
||||||
for i := 0; i < modules.Len(); i++ {
|
for i := 0; i < modules.Len(); i++ {
|
||||||
apex := modules.Apex(i)
|
apex := modules.Apex(i)
|
||||||
@@ -174,11 +176,50 @@ func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext,
|
|||||||
ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
|
ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
|
||||||
commonApex, apex)
|
commonApex, apex)
|
||||||
}
|
}
|
||||||
jars = append(jars, jar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the jars in the Contents property so that they can be used to add dependencies.
|
// Store the jars in the Contents property so that they can be used to add dependencies.
|
||||||
m.properties.Contents = jars
|
m.properties.Contents = modules.CopyOfJars()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this
|
||||||
|
// module (if any) matches the contents.
|
||||||
|
//
|
||||||
|
// This should be a noop as if image_name="art" then the contents will be set from the ArtApexJars
|
||||||
|
// config by bootclasspathFragmentInitContentsFromImage so it will be guaranteed to match. However,
|
||||||
|
// in future this will not be the case.
|
||||||
|
func (b *BootclasspathFragmentModule) bootclasspathImageNameContentsConsistencyCheck(ctx android.BaseModuleContext) {
|
||||||
|
imageName := proptools.String(b.properties.Image_name)
|
||||||
|
if imageName == "art" {
|
||||||
|
// TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
|
||||||
|
if b.MemberName() != "" {
|
||||||
|
// The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
|
||||||
|
// 1. There is no way to use this at the moment so ignoring it is safe.
|
||||||
|
// 2. Attempting to initialize the contents property from the configuration will end up having
|
||||||
|
// the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
|
||||||
|
// as the unversioned prebuilt could end up with an APEX variant created for the source
|
||||||
|
// APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
|
||||||
|
// turn will prevent it from accessing the dex implementation jar from that which will
|
||||||
|
// break hidden API processing, amongst others.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the configuration for the art apex jars.
|
||||||
|
modules := b.getImageConfig(ctx).modules
|
||||||
|
configuredJars := modules.CopyOfJars()
|
||||||
|
|
||||||
|
// Skip the check if the configured jars list is empty as that is a common configuration when
|
||||||
|
// building targets that do not result in a system image.
|
||||||
|
if len(configuredJars) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
contents := b.properties.Contents
|
||||||
|
if !reflect.DeepEqual(configuredJars, contents) {
|
||||||
|
ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v",
|
||||||
|
configuredJars, contents)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +315,13 @@ func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
|
// Only perform a consistency check if this module is the active module. That will prevent an
|
||||||
|
// unused prebuilt that was created without instrumentation from breaking an instrumentation
|
||||||
|
// build.
|
||||||
|
if isActiveModule(ctx.Module()) {
|
||||||
|
b.bootclasspathImageNameContentsConsistencyCheck(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// Perform hidden API processing.
|
// Perform hidden API processing.
|
||||||
b.generateHiddenAPIBuildActions(ctx)
|
b.generateHiddenAPIBuildActions(ctx)
|
||||||
|
|
||||||
|
@@ -113,19 +113,6 @@ func TestBootclasspathFragmentWithoutImageNameOrContents(t *testing.T) {
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBootclasspathFragmentWithImageNameAndContents(t *testing.T) {
|
|
||||||
prepareForTestWithBootclasspathFragment.
|
|
||||||
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
|
|
||||||
`\Qboth of the "image_name" and "contents" properties\E`)).
|
|
||||||
RunTestWithBp(t, `
|
|
||||||
bootclasspath_fragment {
|
|
||||||
name: "bootclasspath-fragment",
|
|
||||||
image_name: "boot",
|
|
||||||
contents: ["other"],
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBootclasspathFragment_Coverage(t *testing.T) {
|
func TestBootclasspathFragment_Coverage(t *testing.T) {
|
||||||
prepareForTestWithFrameworkCoverage := android.FixtureMergeEnv(map[string]string{
|
prepareForTestWithFrameworkCoverage := android.FixtureMergeEnv(map[string]string{
|
||||||
"EMMA_INSTRUMENT": "true",
|
"EMMA_INSTRUMENT": "true",
|
||||||
|
Reference in New Issue
Block a user