Merge "Don't fail the build if manifest_check cannot extract targetSdkVersion."
diff --git a/android/apex.go b/android/apex.go
index a5ff442..257bdad 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -453,6 +453,23 @@
}
}
+// AvailableToSameApexes returns true if the two modules are apex_available to
+// exactly the same set of APEXes (and platform), i.e. if their apex_available
+// properties have the same elements.
+func AvailableToSameApexes(mod1, mod2 ApexModule) bool {
+ mod1ApexAvail := SortedUniqueStrings(mod1.apexModuleBase().ApexProperties.Apex_available)
+ mod2ApexAvail := SortedUniqueStrings(mod2.apexModuleBase().ApexProperties.Apex_available)
+ if len(mod1ApexAvail) != len(mod2ApexAvail) {
+ return false
+ }
+ for i, v := range mod1ApexAvail {
+ if v != mod2ApexAvail[i] {
+ return false
+ }
+ }
+ return true
+}
+
type byApexName []ApexInfo
func (a byApexName) Len() int { return len(a) }
diff --git a/android/paths.go b/android/paths.go
index 1278961..b457372 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1642,16 +1642,10 @@
// Will panic if called from outside a test environment.
func ensureTestOnly() {
- // Normal soong test environment
- if InList("-test.short", os.Args) {
+ if PrefixInList(os.Args, "-test.") {
return
}
- // IntelliJ test environment
- if InList("-test.v", os.Args) {
- return
- }
-
- panic(fmt.Errorf("Not in test\n%s", strings.Join(os.Args, "\n")))
+ panic(fmt.Errorf("Not in test. Command line:\n %s", strings.Join(os.Args, "\n ")))
}
func (p InstallPath) RelativeToTop() Path {
diff --git a/android/util.go b/android/util.go
index 506f8f7..a0394f6 100644
--- a/android/util.go
+++ b/android/util.go
@@ -193,6 +193,17 @@
return
}
+// FilterListPred returns the elements of the given list for which the predicate
+// returns true. Order is kept.
+func FilterListPred(list []string, pred func(s string) bool) (filtered []string) {
+ for _, l := range list {
+ if pred(l) {
+ filtered = append(filtered, l)
+ }
+ }
+ return
+}
+
// RemoveListFromList removes the strings belonging to the filter list from the
// given list and returns the result
func RemoveListFromList(list []string, filter_out []string) (result []string) {
diff --git a/android/util_test.go b/android/util_test.go
index fa26c77..09bec01 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -18,6 +18,7 @@
"fmt"
"reflect"
"strconv"
+ "strings"
"testing"
)
@@ -299,6 +300,14 @@
}
}
+func TestFilterListPred(t *testing.T) {
+ pred := func(s string) bool { return strings.HasPrefix(s, "a/") }
+ AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "b/a", "a/b"}, pred), []string{"a/c", "a/b"})
+ AssertArrayString(t, "filter", FilterListPred([]string{"b/c", "a/a", "b/b"}, pred), []string{"a/a"})
+ AssertArrayString(t, "filter", FilterListPred([]string{"c/c", "b/a", "c/b"}, pred), []string{})
+ AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "a/a", "a/b"}, pred), []string{"a/c", "a/a", "a/b"})
+}
+
func TestRemoveListFromList(t *testing.T) {
input := []string{"a", "b", "c", "d", "a", "c", "d"}
filter := []string{"a", "c"}
diff --git a/apex/apex.go b/apex/apex.go
index 66c598c..80d9615 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -93,8 +93,14 @@
Multilib apexMultilibProperties
// List of boot images that are embedded inside this APEX bundle.
+ //
+ // deprecated: Use Bootclasspath_fragments
+ // TODO(b/177892522): Remove after has been replaced by Bootclasspath_fragments
Boot_images []string
+ // List of bootclasspath fragments that are embedded inside this APEX bundle.
+ Bootclasspath_fragments []string
+
// List of java libraries that are embedded inside this APEX bundle.
Java_libs []string
@@ -748,6 +754,7 @@
// Common-arch dependencies come next
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
ctx.AddFarVariationDependencies(commonVariation, bootImageTag, a.properties.Boot_images...)
+ ctx.AddFarVariationDependencies(commonVariation, bootImageTag, a.properties.Bootclasspath_fragments...)
ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.properties.Bpfs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index bcbbb28..37db5d8 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -6863,21 +6863,77 @@
}
`)
- // the test 'mytest' is a test for the apex, therefore is linked to the
+ ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
+ ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").RelativeToTop().Args["libFlags"], " ")
+ mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
+ android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
+ }
+
+ // These modules are tests for the apex, therefore are linked to the
// actual implementation of mylib instead of its stub.
- ldFlags := ctx.ModuleForTests("mytest", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
- ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so")
- ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
+ ensureLinkedLibIs("mytest", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
+ ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
+ ensureLinkedLibIs("mybench", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
+}
- // The same should be true for cc_library
- ldFlags = ctx.ModuleForTests("mytestlib", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
- ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so")
- ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
+func TestIndirectTestFor(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib", "myprivlib"],
+ updatable: false,
+ }
- // ... and for cc_benchmark
- ldFlags = ctx.ModuleForTests("mybench", "android_arm64_armv8-a").Rule("ld").Args["libFlags"]
- ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so")
- ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1"],
+ },
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "myprivlib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ shared_libs: ["mylib"],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "mytestlib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ shared_libs: ["myprivlib"],
+ stl: "none",
+ test_for: ["myapex"],
+ }
+ `)
+
+ ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
+ ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").RelativeToTop().Args["libFlags"], " ")
+ mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
+ android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
+ }
+
+ // The platform variant of mytestlib links to the platform variant of the
+ // internal myprivlib.
+ ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/myprivlib/", "android_arm64_armv8-a_shared/myprivlib.so")
+
+ // The platform variant of myprivlib links to the platform variant of mylib
+ // and bypasses its stubs.
+ ensureLinkedLibIs("myprivlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
}
// TODO(jungjw): Move this to proptools
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index 91b45fc..678a4cd 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -95,6 +95,9 @@
boot_image {
name: "art-boot-image",
image_name: "art",
+ apex_available: [
+ "com.android.art",
+ ],
}
boot_image {
@@ -160,24 +163,29 @@
android.AssertTrimmedStringEquals(t, "invalid paths for "+moduleName, expectedBootImageFiles, strings.Join(allPaths, "\n"))
}
-func TestBootImageInApex(t *testing.T) {
+func TestBootImageInArtApex(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithBootImage,
- prepareForTestWithMyapex,
- // Configure some libraries in the framework boot image.
- dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
+ prepareForTestWithArtApex,
+
+ // Configure some libraries in the art boot image.
+ dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
).RunTestWithBp(t, `
apex {
- name: "myapex",
- key: "myapex.key",
+ name: "com.android.art",
+ key: "com.android.art.key",
boot_images: [
"mybootimage",
],
+ java_libs: [
+ "foo",
+ "bar",
+ ],
updatable: false,
}
apex_key {
- name: "myapex.key",
+ name: "com.android.art.key",
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
@@ -186,52 +194,125 @@
name: "foo",
srcs: ["b.java"],
installable: true,
+ apex_available: [
+ "com.android.art",
+ ],
}
java_library {
name: "bar",
srcs: ["b.java"],
installable: true,
+ apex_available: [
+ "com.android.art",
+ ],
}
boot_image {
name: "mybootimage",
- image_name: "boot",
+ image_name: "art",
apex_available: [
- "myapex",
+ "com.android.art",
],
}
// Make sure that a preferred prebuilt doesn't affect the apex.
prebuilt_boot_image {
name: "mybootimage",
- image_name: "boot",
+ image_name: "art",
prefer: true,
apex_available: [
- "myapex",
+ "com.android.art",
],
}
`)
- ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+ ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ "javalib/arm/boot.art",
+ "javalib/arm/boot.oat",
+ "javalib/arm/boot.vdex",
"javalib/arm/boot-bar.art",
"javalib/arm/boot-bar.oat",
"javalib/arm/boot-bar.vdex",
- "javalib/arm/boot-foo.art",
- "javalib/arm/boot-foo.oat",
- "javalib/arm/boot-foo.vdex",
+ "javalib/arm64/boot.art",
+ "javalib/arm64/boot.oat",
+ "javalib/arm64/boot.vdex",
"javalib/arm64/boot-bar.art",
"javalib/arm64/boot-bar.oat",
"javalib/arm64/boot-bar.vdex",
- "javalib/arm64/boot-foo.art",
- "javalib/arm64/boot-foo.oat",
- "javalib/arm64/boot-foo.vdex",
+ "javalib/bar.jar",
+ "javalib/foo.jar",
})
- java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
- `myapex.key`,
+ java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ `bar`,
+ `com.android.art.key`,
+ `foo`,
`mybootimage`,
})
}
+func TestBootImageInPrebuiltArtApex(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootImage,
+ prepareForTestWithArtApex,
+
+ android.FixtureMergeMockFs(android.MockFS{
+ "com.android.art-arm64.apex": nil,
+ "com.android.art-arm.apex": nil,
+ }),
+
+ // Configure some libraries in the art boot image.
+ dexpreopt.FixtureSetArtBootJars("com.android.art:foo", "com.android.art:bar"),
+ ).RunTestWithBp(t, `
+ prebuilt_apex {
+ name: "com.android.art",
+ arch: {
+ arm64: {
+ src: "com.android.art-arm64.apex",
+ },
+ arm: {
+ src: "com.android.art-arm.apex",
+ },
+ },
+ exported_java_libs: ["foo", "bar"],
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["foo.jar"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ java_import {
+ name: "bar",
+ jars: ["bar.jar"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ prebuilt_boot_image {
+ name: "mybootimage",
+ image_name: "art",
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+ `)
+
+ java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common", []string{
+ `prebuilt_bar`,
+ `prebuilt_foo`,
+ })
+
+ java.CheckModuleDependencies(t, result.TestContext, "mybootimage", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_bar`,
+ `prebuilt_foo`,
+ })
+}
+
// TODO(b/177892522) - add test for host apex.
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 21bf4ac..653c489 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -22,7 +22,7 @@
"github.com/google/blueprint"
)
-const bloatyDescriptorExt = "bloaty.csv"
+const bloatyDescriptorExt = ".bloaty.csv"
const protoFilename = "binary_sizes.pb"
var (
@@ -75,7 +75,7 @@
return
}
filePath := ctx.ModuleProvider(m, fileSizeMeasurerKey).(android.ModuleOutPath)
- sizeFile := filePath.ReplaceExtension(ctx, bloatyDescriptorExt)
+ sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
ctx.Build(pctx, android.BuildParams{
Rule: bloaty,
Description: "bloaty " + filePath.Rel(),
diff --git a/cc/cc.go b/cc/cc.go
index f843b41..f074597 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -363,7 +363,7 @@
// List of APEXes that this module has private access to for testing purpose. The module
// can depend on libraries that are not exported by the APEXes and use private symbols
// from the exported libraries.
- Test_for []string
+ Test_for []string `android:"arch_variant"`
}
type VendorProperties struct {
@@ -2631,14 +2631,31 @@
// However, for host, ramdisk, vendor_ramdisk, recovery or bootstrap modules,
// always link to non-stub variant
useStubs = dep.(android.ApexModule).NotInPlatform() && !c.bootstrap()
- // Another exception: if this module is bundled with an APEX, then
- // it is linked with the non-stub variant of a module in the APEX
- // as if this is part of the APEX.
- testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
- for _, apexContents := range testFor.ApexContents {
- if apexContents.DirectlyInApex(depName) {
+ if useStubs {
+ // Another exception: if this module is a test for an APEX, then
+ // it is linked with the non-stub variant of a module in the APEX
+ // as if this is part of the APEX.
+ testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
+ for _, apexContents := range testFor.ApexContents {
+ if apexContents.DirectlyInApex(depName) {
+ useStubs = false
+ break
+ }
+ }
+ }
+ if useStubs {
+ // Yet another exception: If this module and the dependency are
+ // available to the same APEXes then skip stubs between their
+ // platform variants. This complements the test_for case above,
+ // which avoids the stubs on a direct APEX library dependency, by
+ // avoiding stubs for indirect test dependencies as well.
+ //
+ // TODO(b/183882457): This doesn't work if the two libraries have
+ // only partially overlapping apex_available. For that test_for
+ // modules would need to be split into APEX variants and resolved
+ // separately for each APEX they have access to.
+ if android.AvailableToSameApexes(c, dep.(android.ApexModule)) {
useStubs = false
- break
}
}
} else {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index cd09e6e..e1ac9f0 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1129,6 +1129,9 @@
Bool(c.sanitize.Properties.Sanitize.Undefined) ||
Bool(c.sanitize.Properties.Sanitize.All_undefined) {
runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)
+ if c.staticBinary() {
+ runtimeLibrary += ".static"
+ }
}
if runtimeLibrary != "" && (toolchain.Bionic() || c.sanitize.Properties.UbsanRuntimeDep) {
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index d341b8c..d9116b0 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -144,6 +144,7 @@
var hostAndDeviceModuleNames = HostAndDeviceModuleNames{}
var sdkVersion string
+var defaultMinSdkVersion string
var useVersion string
var staticDeps bool
var jetifier bool
@@ -286,6 +287,10 @@
return sdkVersion
}
+func (p Pom) DefaultMinSdkVersion() string {
+ return defaultMinSdkVersion
+}
+
func (p Pom) Jetifier() bool {
return jetifier
}
@@ -457,7 +462,7 @@
min_sdk_version: "{{.MinSdkVersion}}",
manifest: "manifests/{{.BpName}}/AndroidManifest.xml",
{{- else if not .IsHostOnly}}
- min_sdk_version: "24",
+ min_sdk_version: "{{.DefaultMinSdkVersion}}",
{{- end}}
{{- end}}
static_libs: [
@@ -598,6 +603,8 @@
This may be specified multiple times to declare these dependencies.
-sdk-version <version>
Sets sdk_version: "<version>" for all modules.
+ -default-min-sdk-version
+ The default min_sdk_version to use for a module if one cannot be mined from AndroidManifest.xml
-use-version <version>
If the maven directory contains multiple versions of artifacts and their pom files,
-use-version can be used to only write Android.bp files for a specific version of those artifacts.
@@ -622,6 +629,7 @@
flag.Var(&hostModuleNames, "host", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is a host module")
flag.Var(&hostAndDeviceModuleNames, "host-and-device", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is both a host and device module.")
flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
+ flag.StringVar(&defaultMinSdkVersion, "default-min-sdk-version", "24", "Default min_sdk_version to use, if one is not available from AndroidManifest.xml. Default: 24")
flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
diff --git a/java/app.go b/java/app.go
index 1b6e0e3..b849b98 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1294,7 +1294,8 @@
// check is not necessary, and although it is good to have, it is difficult to maintain on
// non-linux build platforms where dexpreopt is generally disabled (the check may fail due to
// various unrelated reasons, such as a failure to get manifest from an APK).
- if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ if global.DisablePreopt || global.OnlyPreoptBootImageAndSystemServer {
return inputFile
}
diff --git a/java/boot_image.go b/java/boot_image.go
index a14940d..8594792 100644
--- a/java/boot_image.go
+++ b/java/boot_image.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/dexpreopt"
+ "github.com/google/blueprint/proptools"
"github.com/google/blueprint"
)
@@ -27,24 +28,58 @@
func init() {
RegisterBootImageBuildComponents(android.InitRegistrationContext)
+ // TODO(b/177892522): Remove after has been replaced by bootclasspath_fragments
android.RegisterSdkMemberType(&bootImageMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "boot_images",
SupportsSdk: true,
},
})
+
+ android.RegisterSdkMemberType(&bootImageMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "bootclasspath_fragments",
+ SupportsSdk: true,
+ },
+ })
}
func RegisterBootImageBuildComponents(ctx android.RegistrationContext) {
+ // TODO(b/177892522): Remove after has been replaced by bootclasspath_fragment
ctx.RegisterModuleType("boot_image", bootImageFactory)
ctx.RegisterModuleType("prebuilt_boot_image", prebuiltBootImageFactory)
+
+ ctx.RegisterModuleType("bootclasspath_fragment", bootImageFactory)
+ ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootImageFactory)
}
+type bootImageContentDependencyTag struct {
+ blueprint.BaseDependencyTag
+}
+
+// Avoid having to make boot image content visible to the boot image.
+//
+// This is a temporary workaround to make it easier to migrate to boot image modules with proper
+// dependencies.
+// TODO(b/177892522): Remove this and add needed visibility.
+func (b bootImageContentDependencyTag) ExcludeFromVisibilityEnforcement() {
+}
+
+// The tag used for the dependency between the boot image module and its contents.
+var bootImageContentDepTag = bootImageContentDependencyTag{}
+
+var _ android.ExcludeFromVisibilityEnforcementTag = bootImageContentDepTag
+
type bootImageProperties struct {
// The name of the image this represents.
//
// Must be one of "art" or "boot".
- Image_name string
+ Image_name *string
+
+ // The contents of this boot image, could be either java_library, java_sdk_library, or boot_image.
+ //
+ // The order of this list matters as it is the order that is used in the bootclasspath.
+ Contents []string `blueprint:"mutated"`
}
type BootImageModule struct {
@@ -60,9 +95,52 @@
android.InitApexModule(m)
android.InitSdkAwareModule(m)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
+
+ // Perform some consistency checking to ensure that the configuration is correct.
+ android.AddLoadHook(m, func(ctx android.LoadHookContext) {
+ bootImageConsistencyCheck(ctx, m)
+ })
return m
}
+func bootImageConsistencyCheck(ctx android.EarlyModuleContext, m *BootImageModule) {
+ imageName := proptools.String(m.properties.Image_name)
+ if imageName == "art" {
+ // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is
+ // too early in the Soong processing for that to work.
+ global := dexpreopt.GetGlobalConfig(ctx)
+ modules := global.ArtApexJars
+
+ // Make sure that the apex specified in the configuration is consistent and is one for which
+ // this boot image is available.
+ jars := []string{}
+ commonApex := ""
+ for i := 0; i < modules.Len(); i++ {
+ apex := modules.Apex(i)
+ jar := modules.Jar(i)
+ if apex == "platform" {
+ ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar)
+ continue
+ }
+ if !m.AvailableFor(apex) {
+ ctx.ModuleErrorf("incompatible with ArtApexJars which expects this to be in apex %q but this is only in apexes %q",
+ apex, m.ApexAvailable())
+ continue
+ }
+ if commonApex == "" {
+ commonApex = apex
+ } else if commonApex != apex {
+ ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
+ commonApex, apex)
+ }
+ jars = append(jars, jar)
+ }
+
+ // Store the jars in the Contents property so that they can be used to add dependencies.
+ m.properties.Contents = jars
+ }
+}
+
var BootImageInfoProvider = blueprint.NewProvider(BootImageInfo{})
type BootImageInfo struct {
@@ -96,6 +174,10 @@
func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
tag := ctx.OtherModuleDependencyTag(dep)
+ if tag == bootImageContentDepTag {
+ // Boot image contents are not automatically added to apex, yet.
+ return false
+ }
if android.IsMetaDependencyTag(tag) {
// Cross-cutting metadata dependencies are metadata.
return false
@@ -108,6 +190,8 @@
}
func (b *BootImageModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ ctx.AddDependency(ctx.Module(), bootImageContentDepTag, b.properties.Contents...)
+
if SkipDexpreoptBootJars(ctx) {
return
}
@@ -127,14 +211,8 @@
// GenerateSingletonBuildActions method as it cannot create it for itself.
dexpreopt.GetGlobalSoongConfig(ctx)
- // Get a map of the image configs that are supported.
- imageConfigs := genBootImageConfigs(ctx)
-
- // Retrieve the config for this image.
- imageName := b.properties.Image_name
- imageConfig := imageConfigs[imageName]
+ imageConfig := b.getImageConfig(ctx)
if imageConfig == nil {
- ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
return
}
@@ -145,6 +223,25 @@
ctx.SetProvider(BootImageInfoProvider, info)
}
+func (b *BootImageModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
+ // Get a map of the image configs that are supported.
+ imageConfigs := genBootImageConfigs(ctx)
+
+ // Retrieve the config for this image.
+ imageNamePtr := b.properties.Image_name
+ if imageNamePtr == nil {
+ return nil
+ }
+
+ imageName := *imageNamePtr
+ imageConfig := imageConfigs[imageName]
+ if imageConfig == nil {
+ ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
+ return nil
+ }
+ return imageConfig
+}
+
type bootImageMemberType struct {
android.SdkMemberTypeBase
}
@@ -159,7 +256,11 @@
}
func (b *bootImageMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
- return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_boot_image")
+ if b.PropertyName == "boot_images" {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_boot_image")
+ } else {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_bootclasspath_fragment")
+ }
}
func (b *bootImageMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
@@ -169,7 +270,7 @@
type bootImageSdkMemberProperties struct {
android.SdkMemberPropertiesBase
- Image_name string
+ Image_name *string
}
func (b *bootImageSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -179,8 +280,8 @@
}
func (b *bootImageSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
- if b.Image_name != "" {
- propertySet.AddProperty("image_name", b.Image_name)
+ if b.Image_name != nil {
+ propertySet.AddProperty("image_name", *b.Image_name)
}
}
@@ -213,5 +314,10 @@
android.InitApexModule(m)
android.InitSdkAwareModule(m)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
+
+ // Perform some consistency checking to ensure that the configuration is correct.
+ android.AddLoadHook(m, func(ctx android.LoadHookContext) {
+ bootImageConsistencyCheck(ctx, &m.BootImageModule)
+ })
return m
}
diff --git a/java/boot_image_test.go b/java/boot_image_test.go
index 65e590d..a289df8 100644
--- a/java/boot_image_test.go
+++ b/java/boot_image_test.go
@@ -16,25 +16,88 @@
import (
"testing"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
)
// Contains some simple tests for boot_image logic, additional tests can be found in
// apex/boot_image_test.go as the ART boot image requires modules from the ART apex.
+var prepareForTestWithBootImage = android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ dexpreopt.PrepareForTestByEnablingDexpreopt,
+)
+
func TestUnknownBootImage(t *testing.T) {
- testJavaError(t, "image_name: Unknown image name \\\"unknown\\\", expected one of art, boot", `
- boot_image {
- name: "unknown-boot-image",
- image_name: "unknown",
- }
-`)
+ prepareForTestWithBootImage.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
+ RunTestWithBp(t, `
+ boot_image {
+ name: "unknown-boot-image",
+ image_name: "unknown",
+ }
+ `)
+}
+
+func TestUnknownBootclasspathFragmentImageName(t *testing.T) {
+ prepareForTestWithBootImage.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
+ RunTestWithBp(t, `
+ bootclasspath_fragment {
+ name: "unknown-boot-image",
+ image_name: "unknown",
+ }
+ `)
}
func TestUnknownPrebuiltBootImage(t *testing.T) {
- testJavaError(t, "image_name: Unknown image name \\\"unknown\\\", expected one of art, boot", `
- prebuilt_boot_image {
- name: "unknown-boot-image",
- image_name: "unknown",
- }
-`)
+ prepareForTestWithBootImage.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
+ RunTestWithBp(t, `
+ prebuilt_boot_image {
+ name: "unknown-boot-image",
+ image_name: "unknown",
+ }
+ `)
+}
+
+func TestBootImageInconsistentArtConfiguration_Platform(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForTestWithBootImage,
+ dexpreopt.FixtureSetArtBootJars("platform:foo", "apex:bar"),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\QArtApexJars is invalid as it requests a platform variant of "foo"\E`)).
+ RunTestWithBp(t, `
+ boot_image {
+ name: "boot-image",
+ image_name: "art",
+ apex_available: [
+ "apex",
+ ],
+ }
+ `)
+}
+
+func TestBootImageInconsistentArtConfiguration_ApexMixture(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForTestWithBootImage,
+ dexpreopt.FixtureSetArtBootJars("apex1:foo", "apex2:bar"),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `\QArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex "apex1" and "apex2"\E`)).
+ RunTestWithBp(t, `
+ boot_image {
+ name: "boot-image",
+ image_name: "art",
+ apex_available: [
+ "apex1",
+ "apex2",
+ ],
+ }
+ `)
}
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index ff548e5..da80a47 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -27,7 +27,11 @@
func init() {
pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config")
- android.RegisterModuleType("linker_config", linkerConfigFactory)
+ registerLinkerConfigBuildComponent(android.InitRegistrationContext)
+}
+
+func registerLinkerConfigBuildComponent(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("linker_config", linkerConfigFactory)
}
type linkerConfigProperties struct {
diff --git a/linkerconfig/linkerconfig_test.go b/linkerconfig/linkerconfig_test.go
index 8eed4b5..939e4bb 100644
--- a/linkerconfig/linkerconfig_test.go
+++ b/linkerconfig/linkerconfig_test.go
@@ -15,65 +15,29 @@
package linkerconfig
import (
- "android/soong/android"
- "io/ioutil"
"os"
"reflect"
"testing"
+
+ "android/soong/android"
)
-var buildDir string
-
-func setUp() {
- var err error
- buildDir, err = ioutil.TempDir("", "soong_etc_test")
- if err != nil {
- panic(err)
- }
-}
-
-func tearDown() {
- os.RemoveAll(buildDir)
-}
-
func TestMain(m *testing.M) {
- run := func() int {
- setUp()
- defer tearDown()
-
- return m.Run()
- }
-
- os.Exit(run())
+ os.Exit(m.Run())
}
-func testContext(t *testing.T, bp string) *android.TestContext {
- t.Helper()
-
- fs := map[string][]byte{
- "linker.config.json": nil,
- }
-
- config := android.TestArchConfig(buildDir, nil, bp, fs)
-
- ctx := android.NewTestArchContext(config)
- ctx.RegisterModuleType("linker_config", linkerConfigFactory)
- ctx.Register()
-
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
- android.FailIfErrored(t, errs)
- _, errs = ctx.PrepareBuildActions(config)
- android.FailIfErrored(t, errs)
-
- return ctx
-}
+var prepareForLinkerConfigTest = android.GroupFixturePreparers(
+ android.PrepareForTestWithAndroidBuildComponents,
+ android.FixtureRegisterWithContext(registerLinkerConfigBuildComponent),
+ android.FixtureAddFile("linker.config.json", nil),
+)
func TestBaseLinkerConfig(t *testing.T) {
- ctx := testContext(t, `
- linker_config {
- name: "linker-config-base",
- src: "linker.config.json",
- }
+ result := prepareForLinkerConfigTest.RunTestWithBp(t, `
+ linker_config {
+ name: "linker-config-base",
+ src: "linker.config.json",
+ }
`)
expected := map[string][]string{
@@ -82,13 +46,13 @@
"LOCAL_INSTALLED_MODULE_STEM": {"linker.config.pb"},
}
- p := ctx.ModuleForTests("linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig)
+ p := result.ModuleForTests("linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig)
if p.outputFilePath.Base() != "linker.config.pb" {
t.Errorf("expected linker.config.pb, got %q", p.outputFilePath.Base())
}
- entries := android.AndroidMkEntriesForTest(t, ctx, p)[0]
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)[0]
for k, expectedValue := range expected {
if value, ok := entries.EntryMap[k]; ok {
if !reflect.DeepEqual(value, expectedValue) {
@@ -105,18 +69,18 @@
}
func TestUninstallableLinkerConfig(t *testing.T) {
- ctx := testContext(t, `
- linker_config {
- name: "linker-config-base",
- src: "linker.config.json",
- installable: false,
- }
+ result := prepareForLinkerConfigTest.RunTestWithBp(t, `
+ linker_config {
+ name: "linker-config-base",
+ src: "linker.config.json",
+ installable: false,
+ }
`)
expected := []string{"true"}
- p := ctx.ModuleForTests("linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig)
- entries := android.AndroidMkEntriesForTest(t, ctx, p)[0]
+ p := result.ModuleForTests("linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig)
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)[0]
if value, ok := entries.EntryMap["LOCAL_UNINSTALLABLE_MODULE"]; ok {
if !reflect.DeepEqual(value, expected) {
t.Errorf("LOCAL_UNINSTALLABLE_MODULE is expected to be true but %s", value)