Merge "Add Soong tests for cc_prebuilt_binary for bad srcs"
diff --git a/android/config.go b/android/config.go
index e86fc27..4992882 100644
--- a/android/config.go
+++ b/android/config.go
@@ -127,6 +127,11 @@
 	return []bootstrap.PrimaryBuilderInvocation{}
 }
 
+// RunningInsideUnitTest returns true if this code is being run as part of a Soong unit test.
+func (c Config) RunningInsideUnitTest() bool {
+	return c.config.TestProductVariables != nil
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
diff --git a/android/makevars.go b/android/makevars.go
index a74185a..5165a55 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -35,7 +35,7 @@
 	ctx.Strict("MIN_SUPPORTED_SDK_VERSION", ctx.Config().MinSupportedSdkVersion().String())
 }
 
-///////////////////////////////////////////////////////////////////////////////
+// /////////////////////////////////////////////////////////////////////////////
 
 // BaseMakeVarsContext contains the common functions for other packages to use
 // to declare make variables
@@ -173,13 +173,14 @@
 	MakeVars(ctx MakeVarsModuleContext)
 }
 
-///////////////////////////////////////////////////////////////////////////////
+// /////////////////////////////////////////////////////////////////////////////
 
 func makeVarsSingletonFunc() Singleton {
 	return &makeVarsSingleton{}
 }
 
 type makeVarsSingleton struct {
+	varsForTesting     []makeVarsVariable
 	installsForTesting []byte
 }
 
@@ -320,7 +321,11 @@
 		ctx.Errorf(err.Error())
 	}
 
-	s.installsForTesting = installsBytes
+	// Only save state for tests when testing.
+	if ctx.Config().RunningInsideUnitTest() {
+		s.varsForTesting = vars
+		s.installsForTesting = installsBytes
+	}
 }
 
 func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
diff --git a/android/test_config.go b/android/test_config.go
index 0f88d51..de546c4 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -91,6 +91,9 @@
 		},
 	}
 
+	// Make the CommonOS OsType available for all products.
+	config.Targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
+
 	if runtime.GOOS == "darwin" {
 		config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
 	}
diff --git a/android/testing.go b/android/testing.go
index 4018659..f9f9670 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -673,6 +673,46 @@
 	return parseMkRules(t, ctx.config, nodes)
 }
 
+// MakeVarVariable provides access to make vars that will be written by the makeVarsSingleton
+type MakeVarVariable interface {
+	// Name is the name of the variable.
+	Name() string
+
+	// Value is the value of the variable.
+	Value() string
+}
+
+func (v makeVarsVariable) Name() string {
+	return v.name
+}
+
+func (v makeVarsVariable) Value() string {
+	return v.value
+}
+
+// PrepareForTestAccessingMakeVars sets up the test so that MakeVarsForTesting will work.
+var PrepareForTestAccessingMakeVars = GroupFixturePreparers(
+	PrepareForTestWithAndroidMk,
+	PrepareForTestWithMakevars,
+)
+
+// MakeVarsForTesting returns a filtered list of MakeVarVariable objects that represent the
+// variables that will be written out.
+//
+// It is necessary to use PrepareForTestAccessingMakeVars in tests that want to call this function.
+// Along with any other preparers needed to add the make vars.
+func (ctx *TestContext) MakeVarsForTesting(filter func(variable MakeVarVariable) bool) []MakeVarVariable {
+	vars := ctx.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).varsForTesting
+	result := make([]MakeVarVariable, 0, len(vars))
+	for _, v := range vars {
+		if filter(v) {
+			result = append(result, v)
+		}
+	}
+
+	return result
+}
+
 func (ctx *TestContext) Config() Config {
 	return ctx.config
 }
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 233fce4..4fd6e43 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -277,23 +277,23 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `[
-        ":native_shared_lib_1",
-        ":native_shared_lib_3",
+        ":native_shared_lib_for_both",
+        ":native_shared_lib_for_lib32",
     ] + select({
-        "//build/bazel/platforms/arch:arm": [":native_shared_lib_2"],
-        "//build/bazel/platforms/arch:x86": [":native_shared_lib_2"],
+        "//build/bazel/platforms/arch:arm": [":native_shared_lib_for_first"],
+        "//build/bazel/platforms/arch:x86": [":native_shared_lib_for_first"],
         "//conditions:default": [],
     })`,
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_4",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib64",
+            ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86_64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_4",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib64",
+            ":native_shared_lib_for_first",
         ],
         "//conditions:default": [],
     })`,
@@ -322,27 +322,27 @@
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `select({
         "//build/bazel/platforms/arch:arm": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_3",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib32",
+            ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_3",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib32",
+            ":native_shared_lib_for_first",
         ],
         "//conditions:default": [],
     })`,
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_4",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib64",
+            ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86_64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_4",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib64",
+            ":native_shared_lib_for_first",
         ],
         "//conditions:default": [],
     })`,
@@ -370,11 +370,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `[
-        ":native_shared_lib_1",
-        ":native_shared_lib_3",
+        ":native_shared_lib_for_both",
+        ":native_shared_lib_for_lib32",
     ] + select({
-        "//build/bazel/platforms/arch:arm": [":native_shared_lib_2"],
-        "//build/bazel/platforms/arch:x86": [":native_shared_lib_2"],
+        "//build/bazel/platforms/arch:arm": [":native_shared_lib_for_first"],
+        "//build/bazel/platforms/arch:x86": [":native_shared_lib_for_first"],
         "//conditions:default": [],
     })`,
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
@@ -402,14 +402,14 @@
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_4",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib64",
+            ":native_shared_lib_for_first",
         ],
         "//build/bazel/platforms/arch:x86_64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_4",
-            ":native_shared_lib_2",
+            ":native_shared_lib_for_both",
+            ":native_shared_lib_for_lib64",
+            ":native_shared_lib_for_first",
         ],
         "//conditions:default": [],
     })`,
@@ -419,6 +419,56 @@
 		}})
 }
 
+func createMultilibBlueprint(compile_multilib string) string {
+	return `
+cc_library {
+	name: "native_shared_lib_for_both",
+	bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+	name: "native_shared_lib_for_first",
+	bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+	name: "native_shared_lib_for_lib32",
+	bazel_module: { bp2build_available: false },
+}
+
+cc_library {
+	name: "native_shared_lib_for_lib64",
+	bazel_module: { bp2build_available: false },
+}
+
+apex {
+	name: "com.android.apogee",
+	compile_multilib: "` + compile_multilib + `",
+	multilib: {
+		both: {
+			native_shared_libs: [
+				"native_shared_lib_for_both",
+			],
+		},
+		first: {
+			native_shared_libs: [
+				"native_shared_lib_for_first",
+			],
+		},
+		lib32: {
+			native_shared_libs: [
+				"native_shared_lib_for_lib32",
+			],
+		},
+		lib64: {
+			native_shared_libs: [
+				"native_shared_lib_for_lib64",
+			],
+		},
+	},
+}`
+}
+
 func TestApexBundleDefaultPropertyValues(t *testing.T) {
 	runApexTestCase(t, Bp2buildTestCase{
 		Description:                "apex - default property values",
@@ -474,56 +524,6 @@
 		}})
 }
 
-func createMultilibBlueprint(compile_multilib string) string {
-	return `
-cc_library {
-	name: "native_shared_lib_1",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_2",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_3",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_4",
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	compile_multilib: "` + compile_multilib + `",
-	multilib: {
-		both: {
-			native_shared_libs: [
-				"native_shared_lib_1",
-			],
-		},
-		first: {
-			native_shared_libs: [
-				"native_shared_lib_2",
-			],
-		},
-		lib32: {
-			native_shared_libs: [
-				"native_shared_lib_3",
-			],
-		},
-		lib64: {
-			native_shared_libs: [
-				"native_shared_lib_4",
-			],
-		},
-	},
-}`
-}
-
 func TestBp2BuildOverrideApex(t *testing.T) {
 	runOverrideApexTestCase(t, Bp2buildTestCase{
 		Description:                "override_apex",
diff --git a/cc/testing.go b/cc/testing.go
index 6a655db..992069b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -739,12 +739,13 @@
 }
 
 func checkOverrides(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, jsonPath string, expected []string) {
+	t.Helper()
 	out := singleton.MaybeOutput(jsonPath)
 	content := android.ContentFromFileRuleForTests(t, out)
 
 	var flags snapshotJsonFlags
 	if err := json.Unmarshal([]byte(content), &flags); err != nil {
-		t.Errorf("Error while unmarshalling json %q: %w", jsonPath, err)
+		t.Errorf("Error while unmarshalling json %q: %s", jsonPath, err.Error())
 		return
 	}
 
diff --git a/cc/tidy.go b/cc/tidy.go
index 082cf88..2ba13ca 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -76,9 +76,12 @@
 	if tidy.Properties.Tidy != nil && !*tidy.Properties.Tidy {
 		return flags
 	}
-	// Some projects like external/* and vendor/* have clang-tidy disabled by default.
-	// They can enable clang-tidy explicitly with the "tidy:true" property.
-	if config.NoClangTidyForDir(ctx.ModuleDir()) && !proptools.Bool(tidy.Properties.Tidy) {
+	// Some projects like external/* and vendor/* have clang-tidy disabled by default,
+	// unless they are enabled explicitly with the "tidy:true" property or
+	// when TIDY_EXTERNAL_VENDOR is set to true.
+	if !ctx.Config().IsEnvTrue("TIDY_EXTERNAL_VENDOR") &&
+		!proptools.Bool(tidy.Properties.Tidy) &&
+		config.NoClangTidyForDir(ctx.ModuleDir()) {
 		return flags
 	}
 	// If not explicitly disabled, set flags.Tidy to generate .tidy rules.
diff --git a/java/Android.bp b/java/Android.bp
index 8510e04..0bf7a0b 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -43,6 +43,7 @@
         "dexpreopt_bootjars.go",
         "dexpreopt_check.go",
         "dexpreopt_config.go",
+        "dexpreopt_config_testing.go",
         "droiddoc.go",
         "droidstubs.go",
         "fuzz.go",
@@ -87,6 +88,7 @@
         "dex_test.go",
         "dexpreopt_test.go",
         "dexpreopt_bootjars_test.go",
+        "dexpreopt_config_test.go",
         "droiddoc_test.go",
         "droidstubs_test.go",
         "genrule_test.go",
diff --git a/java/base.go b/java/base.go
index 656a080..bcb7226 100644
--- a/java/base.go
+++ b/java/base.go
@@ -893,7 +893,7 @@
 
 	epEnabled := j.properties.Errorprone.Enabled
 	if (ctx.Config().RunErrorProne() && epEnabled == nil) || Bool(epEnabled) {
-		if config.ErrorProneClasspath == nil && ctx.Config().TestProductVariables == nil {
+		if config.ErrorProneClasspath == nil && !ctx.Config().RunningInsideUnitTest() {
 			ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
 		}
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 9237e89..b3faae8 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -803,10 +803,15 @@
 	rule.Build(image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
 
 	// save output and installed files for makevars
+	// TODO - these are always the same and so should be initialized in genBootImageConfigs
 	image.installs = rule.Installs()
 	image.vdexInstalls = vdexInstalls
 	image.unstrippedInstalls = unstrippedInstalls
-	image.licenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
+
+	// Only set the licenseMetadataFile from the active module.
+	if isActiveModule(ctx.Module()) {
+		image.licenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
+	}
 
 	return bootImageVariantOutputs{
 		image,
diff --git a/java/dexpreopt_config_test.go b/java/dexpreopt_config_test.go
new file mode 100644
index 0000000..eaa6a8c
--- /dev/null
+++ b/java/dexpreopt_config_test.go
@@ -0,0 +1,30 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestBootImageConfig(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForBootImageConfigTest,
+	).RunTest(t)
+
+	CheckArtBootImageConfig(t, result)
+	CheckFrameworkBootImageConfig(t, result)
+}
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
new file mode 100644
index 0000000..1c236d8
--- /dev/null
+++ b/java/dexpreopt_config_testing.go
@@ -0,0 +1,768 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Testing support for dexpreopt config.
+//
+// The bootImageConfig/bootImageVariant structs returned by genBootImageConfigs are used in many
+// places in the build and are currently mutated in a number of those locations. This provides
+// comprehensive tests of the fields in those structs to ensure that they have been initialized
+// correctly and where relevant, mutated correctly.
+//
+// This is used in TestBootImageConfig to verify that the
+
+package java
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+// PrepareForBootImageConfigTest is the minimal set of preparers that are needed to be able to use
+// the Check*BootImageConfig methods define here.
+var PrepareForBootImageConfigTest = android.GroupFixturePreparers(
+	android.PrepareForTestWithArchMutator,
+	android.PrepareForTestAccessingMakeVars,
+	FixtureConfigureBootJars("com.android.art:core1", "com.android.art:core2", "platform:framework"),
+)
+
+// normalizedInstall represents a android.RuleBuilderInstall that has been normalized to remove
+// test specific parts of the From path.
+type normalizedInstall struct {
+	from string
+	to   string
+}
+
+// normalizeInstalls converts a slice of android.RuleBuilderInstall into a slice of
+// normalizedInstall to allow them to be compared using android.AssertDeepEquals.
+func normalizeInstalls(installs android.RuleBuilderInstalls) []normalizedInstall {
+	var normalized []normalizedInstall
+	for _, install := range installs {
+		normalized = append(normalized, normalizedInstall{
+			from: install.From.RelativeToTop().String(),
+			to:   install.To,
+		})
+	}
+	return normalized
+}
+
+// assertInstallsEqual normalized the android.RuleBuilderInstalls and compares against the expected
+// normalizedInstalls.
+func assertInstallsEqual(t *testing.T, message string, expected []normalizedInstall, actual android.RuleBuilderInstalls) {
+	t.Helper()
+	normalizedActual := normalizeInstalls(actual)
+	android.AssertDeepEquals(t, message, expected, normalizedActual)
+}
+
+// expectedConfig encapsulates the expected properties that will be set in a bootImageConfig
+//
+// Each field <x> in here is compared against the corresponding field <x> in bootImageConfig.
+type expectedConfig struct {
+	name                     string
+	stem                     string
+	dir                      string
+	symbolsDir               string
+	installDirOnDevice       string
+	installDirOnHost         string
+	profileInstallPathInApex string
+	modules                  android.ConfiguredJarList
+	dexPaths                 []string
+	dexPathsDeps             []string
+	zip                      string
+	variants                 []*expectedVariant
+
+	// Mutated fields
+	profileInstalls            []normalizedInstall
+	profileLicenseMetadataFile string
+}
+
+// expectedVariant encapsulates the expected properties that will be set in a bootImageVariant
+//
+// Each field <x> in here is compared against the corresponding field <x> in bootImageVariant
+// except for archType which is compared against the target.Arch.ArchType field in bootImageVariant.
+type expectedVariant struct {
+	archType          android.ArchType
+	dexLocations      []string
+	dexLocationsDeps  []string
+	imagePathOnHost   string
+	imagePathOnDevice string
+	imagesDeps        []string
+	primaryImages     string
+	primaryImagesDeps []string
+
+	// Mutated fields
+	installs            []normalizedInstall
+	vdexInstalls        []normalizedInstall
+	unstrippedInstalls  []normalizedInstall
+	licenseMetadataFile string
+}
+
+// CheckArtBootImageConfig checks the status of the fields of the bootImageConfig and
+// bootImageVariant structures that are returned from artBootImageConfig.
+//
+// This is before any fields are mutated.
+func CheckArtBootImageConfig(t *testing.T, result *android.TestResult) {
+	checkArtBootImageConfig(t, result, false, "")
+}
+
+// getArtImageConfig gets the ART bootImageConfig that was created during the test.
+func getArtImageConfig(result *android.TestResult) *bootImageConfig {
+	pathCtx := &android.TestPathContext{TestResult: result}
+	imageConfig := artBootImageConfig(pathCtx)
+	return imageConfig
+}
+
+// checkArtBootImageConfig checks the ART boot image.
+//
+// mutated is true if this is called after fields in the image have been mutated by the ART
+// bootclasspath_fragment and false otherwise.
+func checkArtBootImageConfig(t *testing.T, result *android.TestResult, mutated bool, expectedLicenseMetadataFile string) {
+	imageConfig := getArtImageConfig(result)
+
+	expected := &expectedConfig{
+		name:                     "art",
+		stem:                     "boot",
+		dir:                      "out/soong/test_device/dex_artjars",
+		symbolsDir:               "out/soong/test_device/dex_artjars_unstripped",
+		installDirOnDevice:       "system/framework",
+		installDirOnHost:         "apex/art_boot_images/javalib",
+		profileInstallPathInApex: "etc/boot-image.prof",
+		modules:                  android.CreateTestConfiguredJarList([]string{"com.android.art:core1", "com.android.art:core2"}),
+		dexPaths:                 []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar"},
+		dexPathsDeps:             []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar"},
+		zip:                      "out/soong/test_device/dex_artjars/art.zip",
+		variants: []*expectedVariant{
+			{
+				archType:          android.Arm64,
+				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
+				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
+				imagePathOnHost:   "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+				imagePathOnDevice: "/system/framework/arm64/boot.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+						to:   "/apex/art_boot_images/javalib/arm64/boot.art",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+						to:   "/apex/art_boot_images/javalib/arm64/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.art",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+						to:   "/apex/art_boot_images/javalib/arm64/boot.vdex",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat",
+						to:   "/apex/art_boot_images/javalib/arm64/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType:          android.Arm,
+				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
+				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
+				imagePathOnHost:   "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+				imagePathOnDevice: "/system/framework/arm/boot.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+						to:   "/apex/art_boot_images/javalib/arm/boot.art",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+						to:   "/apex/art_boot_images/javalib/arm/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+						to:   "/apex/art_boot_images/javalib/arm/boot-core2.art",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+						to:   "/apex/art_boot_images/javalib/arm/boot.vdex",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+						to:   "/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat",
+						to:   "/apex/art_boot_images/javalib/arm/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType:          android.X86_64,
+				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
+				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
+				imagePathOnHost:   "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+				imagePathOnDevice: "/system/framework/x86_64/boot.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot.art",
+					}, {
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+					}, {
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot.vdex",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType:          android.X86,
+				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
+				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
+				imagePathOnHost:   "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+				imagePathOnDevice: "/system/framework/x86/boot.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+						to:   "/apex/art_boot_images/javalib/x86/boot.art",
+					}, {
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+						to:   "/apex/art_boot_images/javalib/x86/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+						to:   "/apex/art_boot_images/javalib/x86/boot-core2.art",
+					}, {
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+						to:   "/apex/art_boot_images/javalib/x86/boot.vdex",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+						to:   "/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+						to:   "/apex/art_boot_images/javalib/x86/boot.oat",
+					},
+					{
+						from: "out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+						to:   "/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+		},
+	}
+
+	checkBootImageConfig(t, imageConfig, mutated, expected)
+}
+
+// getFrameworkImageConfig gets the framework bootImageConfig that was created during the test.
+func getFrameworkImageConfig(result *android.TestResult) *bootImageConfig {
+	pathCtx := &android.TestPathContext{TestResult: result}
+	imageConfig := defaultBootImageConfig(pathCtx)
+	return imageConfig
+}
+
+// CheckFrameworkBootImageConfig checks the status of the fields of the bootImageConfig and
+// bootImageVariant structures that are returned from defaultBootImageConfig.
+//
+// This is before any fields are mutated.
+func CheckFrameworkBootImageConfig(t *testing.T, result *android.TestResult) {
+	checkFrameworkBootImageConfig(t, result, false, "")
+}
+
+// checkFrameworkBootImageConfig checks the framework boot image.
+//
+// mutated is true if this is called after fields in the image have been mutated by the
+// platform_bootclasspath and false otherwise.
+func checkFrameworkBootImageConfig(t *testing.T, result *android.TestResult, mutated bool, expectedLicenseMetadataFile string) {
+	imageConfig := getFrameworkImageConfig(result)
+
+	expected := &expectedConfig{
+		name:                     "boot",
+		stem:                     "boot",
+		dir:                      "out/soong/test_device/dex_bootjars",
+		symbolsDir:               "out/soong/test_device/dex_bootjars_unstripped",
+		installDirOnDevice:       "system/framework",
+		installDirOnHost:         "system/framework",
+		profileInstallPathInApex: "",
+		modules:                  android.CreateTestConfiguredJarList([]string{"platform:framework"}),
+		dexPaths:                 []string{"out/soong/test_device/dex_bootjars_input/framework.jar"},
+		dexPathsDeps:             []string{"out/soong/test_device/dex_artjars_input/core1.jar", "out/soong/test_device/dex_artjars_input/core2.jar", "out/soong/test_device/dex_bootjars_input/framework.jar"},
+		zip:                      "out/soong/test_device/dex_bootjars/boot.zip",
+		variants: []*expectedVariant{
+			{
+				archType:     android.Arm64,
+				dexLocations: []string{"/system/framework/framework.jar"},
+				dexLocationsDeps: []string{
+					"/apex/com.android.art/javalib/core1.jar",
+					"/apex/com.android.art/javalib/core2.jar",
+					"/system/framework/framework.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+				imagePathOnDevice: "/system/framework/arm64/boot-framework.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
+				},
+				primaryImages: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+				primaryImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art",
+						to:   "/system/framework/arm64/boot-framework.art",
+					},
+					{
+						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat",
+						to:   "/system/framework/arm64/boot-framework.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex",
+						to:   "/system/framework/arm64/boot-framework.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat",
+						to:   "/system/framework/arm64/boot-framework.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType:     android.Arm,
+				dexLocations: []string{"/system/framework/framework.jar"},
+				dexLocationsDeps: []string{
+					"/apex/com.android.art/javalib/core1.jar",
+					"/apex/com.android.art/javalib/core2.jar",
+					"/system/framework/framework.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+				imagePathOnDevice: "/system/framework/arm/boot-framework.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
+				},
+				primaryImages: "out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+				primaryImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art",
+						to:   "/system/framework/arm/boot-framework.art",
+					},
+					{
+						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat",
+						to:   "/system/framework/arm/boot-framework.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex",
+						to:   "/system/framework/arm/boot-framework.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat",
+						to:   "/system/framework/arm/boot-framework.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType:     android.X86_64,
+				dexLocations: []string{"host/linux-x86/system/framework/framework.jar"},
+				dexLocationsDeps: []string{
+					"host/linux-x86/apex/com.android.art/javalib/core1.jar",
+					"host/linux-x86/apex/com.android.art/javalib/core2.jar",
+					"host/linux-x86/system/framework/framework.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+				imagePathOnDevice: "/system/framework/x86_64/boot-framework.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
+				},
+				primaryImages: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+				primaryImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art",
+						to:   "/system/framework/x86_64/boot-framework.art",
+					},
+					{
+						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat",
+						to:   "/system/framework/x86_64/boot-framework.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex",
+						to:   "/system/framework/x86_64/boot-framework.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat",
+						to:   "/system/framework/x86_64/boot-framework.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+			{
+				archType:     android.X86,
+				dexLocations: []string{"host/linux-x86/system/framework/framework.jar"},
+				dexLocationsDeps: []string{
+					"host/linux-x86/apex/com.android.art/javalib/core1.jar",
+					"host/linux-x86/apex/com.android.art/javalib/core2.jar",
+					"host/linux-x86/system/framework/framework.jar",
+				},
+				imagePathOnHost:   "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+				imagePathOnDevice: "/system/framework/x86/boot-framework.art",
+				imagesDeps: []string{
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
+					"out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
+				},
+				primaryImages: "out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+				primaryImagesDeps: []string{
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
+					"out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+				},
+				installs: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art",
+						to:   "/system/framework/x86/boot-framework.art",
+					},
+					{
+						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat",
+						to:   "/system/framework/x86/boot-framework.oat",
+					},
+				},
+				vdexInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex",
+						to:   "/system/framework/x86/boot-framework.vdex",
+					},
+				},
+				unstrippedInstalls: []normalizedInstall{
+					{
+						from: "out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat",
+						to:   "/system/framework/x86/boot-framework.oat",
+					},
+				},
+				licenseMetadataFile: expectedLicenseMetadataFile,
+			},
+		},
+		profileInstalls: []normalizedInstall{
+			{from: "out/soong/test_device/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"},
+			{from: "out/soong/test_device/dex_bootjars/boot.prof", to: "/system/etc/boot-image.prof"},
+		},
+		profileLicenseMetadataFile: expectedLicenseMetadataFile,
+	}
+
+	checkBootImageConfig(t, imageConfig, mutated, expected)
+}
+
+// clearMutatedFields clears fields in the expectedConfig that correspond to fields in the
+// bootImageConfig/bootImageVariant structs which are mutated outside the call to
+// genBootImageConfigs.
+//
+// This allows the resulting expectedConfig struct to be compared against the values of those boot
+// image structs immediately the call to genBootImageConfigs. If this is not called then the
+// expectedConfig struct will expect the boot image structs to have been mutated by the ART
+// bootclasspath_fragment and the platform_bootclasspath.
+func clearMutatedFields(expected *expectedConfig) {
+	expected.profileInstalls = nil
+	expected.profileLicenseMetadataFile = ""
+	for _, variant := range expected.variants {
+		variant.installs = nil
+		variant.vdexInstalls = nil
+		variant.unstrippedInstalls = nil
+		variant.licenseMetadataFile = ""
+	}
+}
+
+// checkBootImageConfig checks a boot image against the expected contents.
+//
+// If mutated is false then this will clear any mutated fields in the expected contents back to the
+// zero value so that they will match the unmodified values in the boot image.
+//
+// It runs the checks in an image specific subtest of the current test.
+func checkBootImageConfig(t *testing.T, imageConfig *bootImageConfig, mutated bool, expected *expectedConfig) {
+	if !mutated {
+		clearMutatedFields(expected)
+	}
+
+	t.Run(imageConfig.name, func(t *testing.T) {
+		nestedCheckBootImageConfig(t, imageConfig, expected)
+	})
+}
+
+// nestedCheckBootImageConfig does the work of comparing the image against the expected values and
+// is run in an image specific subtest.
+func nestedCheckBootImageConfig(t *testing.T, imageConfig *bootImageConfig, expected *expectedConfig) {
+	android.AssertStringEquals(t, "name", expected.name, imageConfig.name)
+	android.AssertStringEquals(t, "stem", expected.stem, imageConfig.stem)
+	android.AssertPathRelativeToTopEquals(t, "dir", expected.dir, imageConfig.dir)
+	android.AssertPathRelativeToTopEquals(t, "symbolsDir", expected.symbolsDir, imageConfig.symbolsDir)
+	android.AssertStringEquals(t, "installDirOnDevice", expected.installDirOnDevice, imageConfig.installDirOnDevice)
+	android.AssertStringEquals(t, "installDirOnHost", expected.installDirOnHost, imageConfig.installDirOnHost)
+	android.AssertStringEquals(t, "profileInstallPathInApex", expected.profileInstallPathInApex, imageConfig.profileInstallPathInApex)
+	android.AssertDeepEquals(t, "modules", expected.modules, imageConfig.modules)
+	android.AssertPathsRelativeToTopEquals(t, "dexPaths", expected.dexPaths, imageConfig.dexPaths.Paths())
+	android.AssertPathsRelativeToTopEquals(t, "dexPathsDeps", expected.dexPathsDeps, imageConfig.dexPathsDeps.Paths())
+	// dexPathsByModule is just a different representation of the other information in the config.
+	android.AssertPathRelativeToTopEquals(t, "zip", expected.zip, imageConfig.zip)
+	assertInstallsEqual(t, "profileInstalls", expected.profileInstalls, imageConfig.profileInstalls)
+	android.AssertStringEquals(t, "profileLicenseMetadataFile", expected.profileLicenseMetadataFile, imageConfig.profileLicenseMetadataFile.RelativeToTop().String())
+
+	android.AssertIntEquals(t, "variant count", 4, len(imageConfig.variants))
+	for i, variant := range imageConfig.variants {
+		expectedVariant := expected.variants[i]
+		t.Run(variant.target.Arch.ArchType.String(), func(t *testing.T) {
+			android.AssertDeepEquals(t, "archType", expectedVariant.archType, variant.target.Arch.ArchType)
+			android.AssertDeepEquals(t, "dexLocations", expectedVariant.dexLocations, variant.dexLocations)
+			android.AssertDeepEquals(t, "dexLocationsDeps", expectedVariant.dexLocationsDeps, variant.dexLocationsDeps)
+			android.AssertPathRelativeToTopEquals(t, "imagePathOnHost", expectedVariant.imagePathOnHost, variant.imagePathOnHost)
+			android.AssertStringEquals(t, "imagePathOnDevice", expectedVariant.imagePathOnDevice, variant.imagePathOnDevice)
+			android.AssertPathsRelativeToTopEquals(t, "imagesDeps", expectedVariant.imagesDeps, variant.imagesDeps.Paths())
+			android.AssertPathRelativeToTopEquals(t, "primaryImages", expectedVariant.primaryImages, variant.primaryImages)
+			android.AssertPathsRelativeToTopEquals(t, "primaryImagesDeps", expectedVariant.primaryImagesDeps, variant.primaryImagesDeps)
+			assertInstallsEqual(t, "installs", expectedVariant.installs, variant.installs)
+			assertInstallsEqual(t, "vdexInstalls", expectedVariant.vdexInstalls, variant.vdexInstalls)
+			assertInstallsEqual(t, "unstrippedInstalls", expectedVariant.unstrippedInstalls, variant.unstrippedInstalls)
+			android.AssertStringEquals(t, "licenseMetadataFile", expectedVariant.licenseMetadataFile, variant.licenseMetadataFile.RelativeToTop().String())
+		})
+	}
+}
+
+// CheckMutatedArtBootImageConfig checks the mutated fields in the bootImageConfig/Variant for ART.
+func CheckMutatedArtBootImageConfig(t *testing.T, result *android.TestResult, expectedLicenseMetadataFile string) {
+	checkArtBootImageConfig(t, result, true, expectedLicenseMetadataFile)
+
+	// Check the dexpreopt make vars. Do it in here as it depends on the expected license metadata
+	// file at the moment and it
+	checkDexpreoptMakeVars(t, result, expectedLicenseMetadataFile)
+}
+
+// CheckMutatedFrameworkBootImageConfig checks the mutated fields in the bootImageConfig/Variant for framework.
+func CheckMutatedFrameworkBootImageConfig(t *testing.T, result *android.TestResult, expectedLicenseMetadataFile string) {
+	checkFrameworkBootImageConfig(t, result, true, expectedLicenseMetadataFile)
+}
+
+// checkDexpreoptMakeVars checks the DEXPREOPT_ prefixed make vars produced by dexpreoptBootJars
+// singleton.
+func checkDexpreoptMakeVars(t *testing.T, result *android.TestResult, expectedLicenseMetadataFile string) {
+	vars := result.MakeVarsForTesting(func(variable android.MakeVarVariable) bool {
+		return strings.HasPrefix(variable.Name(), "DEXPREOPT_")
+	})
+
+	out := &strings.Builder{}
+	for _, v := range vars {
+		fmt.Fprintf(out, "%s=%s\n", v.Name(), android.StringRelativeToTop(result.Config, v.Value()))
+	}
+	format := `
+DEXPREOPT_BOOTCLASSPATH_DEX_FILES=out/soong/test_device/dex_artjars_input/core1.jar out/soong/test_device/dex_artjars_input/core2.jar out/soong/test_device/dex_bootjars_input/framework.jar
+DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS=/apex/com.android.art/javalib/core1.jar /apex/com.android.art/javalib/core2.jar /system/framework/framework.jar
+DEXPREOPT_BOOT_JARS_MODULES=platform:framework
+DEXPREOPT_GEN=out/host/linux-x86/bin/dexpreopt_gen
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/apex/art_boot_images/javalib/x86_64/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art:/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art:/system/framework/arm/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art:/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art:/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art:/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat
+DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.oat out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.oat out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex
+DEXPREOPT_IMAGE_DEPS_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.oat out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex
+DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm=%[1]s
+DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s
+DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s
+DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86_64=%[1]s
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/system/framework/boot.art
+DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art:/system/framework/boot-framework.art
+DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTart=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art
+DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/boot.art:out/soong/test_device/dex_bootjars/android/system/framework/boot-framework.art
+DEXPREOPT_IMAGE_NAMES=art boot
+DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/test_device/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/test_device/dex_bootjars/boot.prof:/system/etc/boot-image.prof
+DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/test_device/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/test_device/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars_unstripped/linux_glibc/system/framework/x86_64/boot-framework.oat:/system/framework/x86_64/boot-framework.oat
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.vdex:/system/framework/arm/boot-framework.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.vdex:/system/framework/arm64/boot-framework.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex:/system/framework/x86/boot-framework.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.vdex:/system/framework/x86_64/boot-framework.vdex
+DEXPREOPT_IMAGE_ZIP_art=out/soong/test_device/dex_artjars/art.zip
+DEXPREOPT_IMAGE_ZIP_boot=out/soong/test_device/dex_bootjars/boot.zip
+DEXPREOPT_IMAGE_art_arm=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
+DEXPREOPT_IMAGE_art_arm64=out/soong/test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art
+DEXPREOPT_IMAGE_art_host_x86=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art
+DEXPREOPT_IMAGE_art_host_x86_64=out/soong/test_device/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art
+DEXPREOPT_IMAGE_boot_arm=out/soong/test_device/dex_bootjars/android/system/framework/arm/boot-framework.art
+DEXPREOPT_IMAGE_boot_arm64=out/soong/test_device/dex_bootjars/android/system/framework/arm64/boot-framework.art
+DEXPREOPT_IMAGE_boot_host_x86=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art
+DEXPREOPT_IMAGE_boot_host_x86_64=out/soong/test_device/dex_bootjars/linux_glibc/system/framework/x86_64/boot-framework.art
+`
+	expected := strings.TrimSpace(fmt.Sprintf(format, expectedLicenseMetadataFile))
+	actual := strings.TrimSpace(out.String())
+	android.AssertStringEquals(t, "vars", expected, actual)
+}
diff --git a/java/testing.go b/java/testing.go
index 1f41191..49430ee 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -393,6 +393,7 @@
 			aidl: {
 				export_include_dirs: ["framework/aidl"],
 			},
+			compile_dex: true,
 		}
 
 		android_app {
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 4be0ace..1b64130 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -80,7 +81,7 @@
 		// Add a platform_bootclasspath that depends on the fragment.
 		fixtureAddPlatformBootclasspathForBootclasspathFragment("com.android.art", "mybootclasspathfragment"),
 
-		java.FixtureConfigureBootJars("com.android.art:mybootlib"),
+		java.PrepareForBootImageConfigTest,
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
@@ -99,7 +100,7 @@
 			bootclasspath_fragment {
 				name: "mybootclasspathfragment",
 				image_name: "art",
-				contents: ["mybootlib"],
+				contents: ["core1", "core2"],
 				apex_available: ["com.android.art"],
 				hidden_api: {
 					split_packages: ["*"],
@@ -113,19 +114,32 @@
 			}
 
 			java_library {
-				name: "mybootlib",
+				name: "core1",
 				srcs: ["Test.java"],
 				system_modules: "none",
 				sdk_version: "none",
 				compile_dex: true,
 				apex_available: ["com.android.art"],
 			}
-		`),
+
+			java_library {
+				name: "core2",
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+				compile_dex: true,
+				apex_available: ["com.android.art"],
+			}
+`),
 	).RunTest(t)
 
 	// A preparer to update the test fixture used when processing an unpackage snapshot.
 	preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "mybootclasspathfragment")
 
+	// Check that source on its own configures the bootImageConfig correctly.
+	java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/meta_lic")
+	java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
+
 	CheckSnapshot(t, result, "mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
@@ -136,7 +150,10 @@
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
     image_name: "art",
-    contents: ["mybootlib"],
+    contents: [
+        "core1",
+        "core2",
+    ],
     hidden_api: {
         annotation_flags: "hiddenapi/annotation-flags.csv",
         metadata: "hiddenapi/metadata.csv",
@@ -148,11 +165,19 @@
 }
 
 java_import {
-    name: "mybootlib",
+    name: "core1",
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
-    jars: ["java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/core1.jar"],
+}
+
+java_import {
+    name: "core2",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["com.android.art"],
+    jars: ["java_boot_libs/snapshot/jars/are/invalid/core2.jar"],
 }
 `),
 		checkAllCopyRules(`
@@ -162,31 +187,54 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core1.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core2.jar
 		`),
 		snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
 
 		// Check the behavior of the snapshot without the source.
 		snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) {
-			// Make sure that the boot jars package check rule includes the dex jar retrieved from the prebuilt apex.
-			checkBootJarsPackageCheckRule(t, result, "out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/mybootlib.jar")
+			// Make sure that the boot jars package check rule includes the dex jars retrieved from the prebuilt apex.
+			checkBootJarsPackageCheckRule(t, result,
+				"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
+				"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
+				"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar")
+			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/mybootclasspathfragment/android_common_com.android.art/meta_lic")
+			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
 		}),
 
 		snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
+
+		// Check the behavior of the snapshot when the source is preferred.
+		snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
+			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/meta_lic")
+			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
+		}),
+
 		snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
+
+		// Check the behavior of the snapshot when it is preferred.
+		snapshotTestChecker(checkSnapshotPreferredWithSource, func(t *testing.T, result *android.TestResult) {
+			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/prebuilt_mybootclasspathfragment/android_common_com.android.art/meta_lic")
+			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
+		}),
 	)
 
-	// Make sure that the boot jars package check rule includes the dex jar created from the source.
-	checkBootJarsPackageCheckRule(t, result, "out/soong/.intermediates/mybootlib/android_common_apex10000/aligned/mybootlib.jar")
+	// Make sure that the boot jars package check rule includes the dex jars created from the source.
+	checkBootJarsPackageCheckRule(t, result,
+		"out/soong/.intermediates/core1/android_common_apex10000/aligned/core1.jar",
+		"out/soong/.intermediates/core2/android_common_apex10000/aligned/core2.jar",
+		"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar")
 }
 
 // checkBootJarsPackageCheckRule checks that the supplied module is an input to the boot jars
 // package check rule.
-func checkBootJarsPackageCheckRule(t *testing.T, result *android.TestResult, expectedModule string) {
+func checkBootJarsPackageCheckRule(t *testing.T, result *android.TestResult, expectedModules ...string) {
+	t.Helper()
 	platformBcp := result.ModuleForTests("platform-bootclasspath", "android_common")
 	bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check")
 	command := bootJarsCheckRule.RuleParams.Command
-	expectedCommandArgs := " out/soong/host/linux-x86/bin/dexdump build/soong/scripts/check_boot_jars/package_allowed_list.txt " + expectedModule + " &&"
+	expectedCommandArgs := " build/soong/scripts/check_boot_jars/package_allowed_list.txt " + strings.Join(expectedModules, " ") + " &&"
 	android.AssertStringDoesContain(t, "boot jars package check", command, expectedCommandArgs)
 }