Merge "Check consistency of the BootJars/UpdatableBootJars config"
diff --git a/android/arch.go b/android/arch.go
index 9f93752..d7b12bc 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -412,6 +412,54 @@
 	}
 }
 
+func registerBp2buildArchPathDepsMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("bp2build-arch-pathdeps", bp2buildArchPathDepsMutator).Parallel()
+}
+
+// add dependencies for architecture specific properties tagged with `android:"path"`
+func bp2buildArchPathDepsMutator(ctx BottomUpMutatorContext) {
+	var module Module
+	module = ctx.Module()
+
+	m := module.base()
+	if !m.ArchSpecific() {
+		return
+	}
+
+	// addPathDepsForProps does not descend into sub structs, so we need to descend into the
+	// arch-specific properties ourselves
+	properties := []interface{}{}
+	for _, archProperties := range m.archProperties {
+		for _, archProps := range archProperties {
+			archPropValues := reflect.ValueOf(archProps).Elem()
+			// there are three "arch" variations, descend into each
+			for _, variant := range []string{"Arch", "Multilib", "Target"} {
+				// The properties are an interface, get the value (a pointer) that it points to
+				archProps := archPropValues.FieldByName(variant).Elem()
+				if archProps.IsNil() {
+					continue
+				}
+				// And then a pointer to a struct
+				archProps = archProps.Elem()
+				for i := 0; i < archProps.NumField(); i += 1 {
+					f := archProps.Field(i)
+					// If the value of the field is a struct (as opposed to a pointer to a struct) then step
+					// into the BlueprintEmbed field.
+					if f.Kind() == reflect.Struct {
+						f = f.FieldByName("BlueprintEmbed")
+					}
+					if f.IsZero() {
+						continue
+					}
+					props := f.Interface().(interface{})
+					properties = append(properties, props)
+				}
+			}
+		}
+	}
+	addPathDepsForProps(ctx, properties)
+}
+
 // osMutator splits an arch-specific module into a variant for each OS that is enabled for the
 // module.  It uses the HostOrDevice value passed to InitAndroidArchModule and the
 // device_supported and host_supported properties to determine which OsTypes are enabled for this
@@ -617,7 +665,7 @@
 	}
 
 	// only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
-	if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk() || module.InstallInDebugRamdisk()) {
+	if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk()) {
 		osTargets = []Target{osTargets[0]}
 	}
 
@@ -899,13 +947,17 @@
 		if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
 			panic(fmt.Errorf("unexpected tag format %q", field.Tag))
 		}
+		// don't delete path tag as it is needed for bp2build
 		// these tags don't need to be present in the runtime generated struct type.
-		values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
-		if len(values) > 0 {
+		values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend"})
+		if len(values) > 0 && values[0] != "path" {
 			panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
+		} else if len(values) == 1 {
+			field.Tag = reflect.StructTag(`android:"` + strings.Join(values, ",") + `"`)
+		} else {
+			field.Tag = ``
 		}
 
-		field.Tag = ""
 		return true, field
 	}
 	return false, field
diff --git a/android/arch_test.go b/android/arch_test.go
index 633ddaa..3aa4779 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -66,9 +66,9 @@
 			}{},
 			out: &struct {
 				A *string
-				B *string
-				C *string
-				D *string
+				B *string `android:"path"`
+				C *string `android:"path"`
+				D *string `android:"path"`
 			}{},
 			filtered: true,
 		},
diff --git a/android/bazel.go b/android/bazel.go
index 6800c91..ba5ae31 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -185,7 +185,7 @@
 		"libc_bionic_ndk",               // ruperts@, cc_library_static, depends on //bionic/libc/system_properties
 		"libc_bionic_systrace",          // ruperts@, cc_library_static, 'private/bionic_systrace.h' file not found
 		"libc_pthread",                  // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found
-		"libc_syscalls",                 // ruperts@, cc_library_static, mutator panic cannot get direct dep syscalls-arm64.S of libc_syscalls
+		"libc_syscalls",                 // eakammer@, cc_library_static,  'private/bionic_asm.h' file not found
 		"libc_ndk",                      // ruperts@, cc_library_static, depends on //bionic/libm:libm
 		"libc_nopthread",                // ruperts@, cc_library_static, depends on //external/arm-optimized-routines
 		"libc_common",                   // ruperts@, cc_library_static, depends on //bionic/libc:libc_nopthread
@@ -212,8 +212,8 @@
 		"libc_malloc_debug", // jingwen@, cc_library, fatal error: 'assert.h' file not found
 		"libc_malloc_hooks", // jingwen@, cc_library, fatal error: 'errno.h' file not found
 		"libdl",             // jingwen@, cc_library, ld.lld: error: no input files
-		"libm",              // jingwen@, cc_library, fatal error: 'freebsd-compat.h' file not found
-		"libseccomp_policy", // jingwen@, cc_library, fatal error: 'seccomp_policy.h' file not found
+		"libm",              // lberki@, cc_library, compiler error: "Unexpected token in argument list"
+		"libseccomp_policy", // lberki@, cc_library, 'linux/filter.h' not found, caused by missing -isystem bionic/libc/kernel/uapi, dunno where it comes from in Soong
 		"libstdc++",         // jingwen@, cc_library, depends on //external/gwp_asan
 	}
 
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 9727cc7..63e2c50 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -351,3 +351,13 @@
 		OutputPath: outputPath.withRel(validatedExecRootPath),
 	}
 }
+
+// PathsForBazelOut returns a list of paths representing the paths under an output directory
+// dedicated to Bazel-owned outputs.
+func PathsForBazelOut(ctx PathContext, paths []string) Paths {
+	outs := make(Paths, 0, len(paths))
+	for _, p := range paths {
+		outs = append(outs, PathForBazelOut(ctx, p))
+	}
+	return outs
+}
diff --git a/android/image.go b/android/image.go
index bdb9be0..1a1a423 100644
--- a/android/image.go
+++ b/android/image.go
@@ -30,11 +30,6 @@
 	// vendor ramdisk partition).
 	VendorRamdiskVariantNeeded(ctx BaseModuleContext) bool
 
-	// DebugRamdiskVariantNeeded should return true if the module needs a debug ramdisk variant (installed on the
-	// debug ramdisk partition: $(PRODUCT_OUT)/debug_ramdisk/first_stage_ramdisk if BOARD_USES_RECOVERY_AS_ROOT is
-	// true, $(PRODUCT_OUT)/debug_ramdisk otherise).
-	DebugRamdiskVariantNeeded(ctx BaseModuleContext) bool
-
 	// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
 	// recovery partition).
 	RecoveryVariantNeeded(ctx BaseModuleContext) bool
@@ -65,9 +60,6 @@
 
 	// VendorRamdiskVariation means a module to be installed to vendor ramdisk image.
 	VendorRamdiskVariation string = "vendor_ramdisk"
-
-	// DebugRamdiskVariation means a module to be installed to debug ramdisk image.
-	DebugRamdiskVariation string = "debug_ramdisk"
 )
 
 // imageMutator creates variants for modules that implement the ImageInterface that
@@ -91,9 +83,6 @@
 		if m.VendorRamdiskVariantNeeded(ctx) {
 			variations = append(variations, VendorRamdiskVariation)
 		}
-		if m.DebugRamdiskVariantNeeded(ctx) {
-			variations = append(variations, DebugRamdiskVariation)
-		}
 		if m.RecoveryVariantNeeded(ctx) {
 			variations = append(variations, RecoveryVariation)
 		}
diff --git a/android/module.go b/android/module.go
index 942e071..9f923e2 100644
--- a/android/module.go
+++ b/android/module.go
@@ -393,7 +393,6 @@
 	InstallInSanitizerDir() bool
 	InstallInRamdisk() bool
 	InstallInVendorRamdisk() bool
-	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
@@ -451,7 +450,6 @@
 	InstallInSanitizerDir() bool
 	InstallInRamdisk() bool
 	InstallInVendorRamdisk() bool
-	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
@@ -755,9 +753,6 @@
 	// Whether this module is installed to vendor ramdisk
 	Vendor_ramdisk *bool
 
-	// Whether this module is installed to debug ramdisk
-	Debug_ramdisk *bool
-
 	// Whether this module is built for non-native architectures (also known as native bridge binary)
 	Native_bridge_supported *bool `android:"arch_variant"`
 
@@ -1545,10 +1540,6 @@
 	return Bool(m.commonProperties.Vendor_ramdisk)
 }
 
-func (m *ModuleBase) InstallInDebugRamdisk() bool {
-	return Bool(m.commonProperties.Debug_ramdisk)
-}
-
 func (m *ModuleBase) InstallInRecovery() bool {
 	return Bool(m.commonProperties.Recovery)
 }
@@ -1602,10 +1593,6 @@
 	return m.base().commonProperties.ImageVariation == VendorRamdiskVariation
 }
 
-func (m *ModuleBase) InDebugRamdisk() bool {
-	return m.base().commonProperties.ImageVariation == DebugRamdiskVariation
-}
-
 func (m *ModuleBase) InRecovery() bool {
 	return m.base().commonProperties.ImageVariation == RecoveryVariation
 }
@@ -2561,10 +2548,6 @@
 	return m.module.InstallInVendorRamdisk()
 }
 
-func (m *moduleContext) InstallInDebugRamdisk() bool {
-	return m.module.InstallInDebugRamdisk()
-}
-
 func (m *moduleContext) InstallInRecovery() bool {
 	return m.module.InstallInRecovery()
 }
diff --git a/android/mutator.go b/android/mutator.go
index e25e2e8..365bf29 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -55,6 +55,7 @@
 	bp2buildDepsMutators = append([]RegisterMutatorFunc{
 		registerDepsMutatorBp2Build,
 		registerPathDepsMutator,
+		registerBp2buildArchPathDepsMutator,
 	}, depsMutators...)
 
 	for _, f := range bp2buildDepsMutators {
diff --git a/android/path_properties.go b/android/path_properties.go
index 2c8d27c..4446773 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -34,7 +34,10 @@
 // ":module" module reference syntax in a property that is tagged with `android:"path"`.
 func pathDepsMutator(ctx BottomUpMutatorContext) {
 	props := ctx.Module().base().generalProperties
+	addPathDepsForProps(ctx, props)
+}
 
+func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) {
 	// Iterate through each property struct of the module extracting the contents of all properties
 	// tagged with `android:"path"`.
 	var pathProperties []string
diff --git a/android/paths.go b/android/paths.go
index 026cb87..93c5684 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -106,7 +106,6 @@
 	InstallInSanitizerDir() bool
 	InstallInRamdisk() bool
 	InstallInVendorRamdisk() bool
-	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
 	InstallBypassMake() bool
@@ -1690,16 +1689,6 @@
 			if !ctx.InstallInRoot() {
 				partition += "/system"
 			}
-		} else if ctx.InstallInDebugRamdisk() {
-			// The module is only available after switching root into
-			// /first_stage_ramdisk. To expose the module before switching root
-			// on a device without a dedicated recovery partition, install the
-			// recovery variant.
-			if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
-				partition = "debug_ramdisk/first_stage_ramdisk"
-			} else {
-				partition = "debug_ramdisk"
-			}
 		} else if ctx.InstallInRecovery() {
 			if ctx.InstallInRoot() {
 				partition = "recovery/root"
@@ -1870,7 +1859,6 @@
 	inSanitizerDir  bool
 	inRamdisk       bool
 	inVendorRamdisk bool
-	inDebugRamdisk  bool
 	inRecovery      bool
 	inRoot          bool
 	forceOS         *OsType
@@ -1903,10 +1891,6 @@
 	return m.inVendorRamdisk
 }
 
-func (m testModuleInstallPathContext) InstallInDebugRamdisk() bool {
-	return m.inDebugRamdisk
-}
-
 func (m testModuleInstallPathContext) InstallInRecovery() bool {
 	return m.inRecovery
 }
diff --git a/android/paths_test.go b/android/paths_test.go
index cb9138b..6ec75b4 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -395,19 +395,6 @@
 			partitionDir: "target/product/test_device/vendor_ramdisk",
 		},
 		{
-			name: "debug_ramdisk binary",
-			ctx: &testModuleInstallPathContext{
-				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
-				},
-				inDebugRamdisk: true,
-			},
-			in:           []string{"my_test"},
-			out:          "target/product/test_device/debug_ramdisk/my_test",
-			partitionDir: "target/product/test_device/debug_ramdisk",
-		},
-		{
 			name: "system native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
@@ -746,19 +733,6 @@
 			out:          "target/product/test_device/vendor_ramdisk/first_stage_ramdisk/my_test",
 			partitionDir: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk",
 		},
-		{
-			name: "debug_ramdisk binary",
-			ctx: &testModuleInstallPathContext{
-				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
-				},
-				inDebugRamdisk: true,
-			},
-			in:           []string{"my_test"},
-			out:          "target/product/test_device/debug_ramdisk/first_stage_ramdisk/my_test",
-			partitionDir: "target/product/test_device/debug_ramdisk/first_stage_ramdisk",
-		},
 	}
 
 	for _, tc := range testCases {
diff --git a/apex/Android.bp b/apex/Android.bp
index 7b52402..e234181 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -30,7 +30,7 @@
     ],
     testSrcs: [
         "apex_test.go",
-        "boot_image_test.go",
+        "bootclasspath_fragment_test.go",
         "platform_bootclasspath_test.go",
         "vndk_test.go",
     ],
diff --git a/apex/apex.go b/apex/apex.go
index 088a462..762912e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1695,7 +1695,7 @@
 				}
 			case bcpfTag:
 				{
-					if _, ok := child.(*java.BootImageModule); !ok {
+					if _, ok := child.(*java.BootclasspathFragmentModule); !ok {
 						ctx.PropertyErrorf("bootclasspath_fragments", "%q is not a boot_image module", depName)
 						return false
 					}
diff --git a/apex/boot_image_test.go b/apex/bootclasspath_fragment_test.go
similarity index 91%
rename from apex/boot_image_test.go
rename to apex/bootclasspath_fragment_test.go
index dab72f7..87f0132 100644
--- a/apex/boot_image_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -22,8 +22,8 @@
 	"android/soong/java"
 )
 
-// Contains tests for boot_image logic from java/boot_image.go as the ART boot image requires
-// modules from the ART apex.
+// Contains tests for bootclasspath_fragment logic from java/bootclasspath_fragment.go as the ART
+// bootclasspath_fragment requires modules from the ART apex.
 
 var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers(
 	java.PrepareForTestWithDexpreopt,
@@ -40,7 +40,7 @@
 func TestBootclasspathFragments(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
-		// Configure some libraries in the art and framework boot images.
+		// Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
 		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
 		prepareForTestWithArtApex,
 
@@ -141,9 +141,9 @@
 func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
 	t.Helper()
 
-	bootImage := result.ModuleForTests(moduleName, "android_common").Module().(*java.BootImageModule)
+	bootclasspathFragment := result.ModuleForTests(moduleName, "android_common").Module().(*java.BootclasspathFragmentModule)
 
-	bootImageInfo := result.ModuleProvider(bootImage, java.BootImageInfoProvider).(java.BootImageInfo)
+	bootImageInfo := result.ModuleProvider(bootclasspathFragment, java.BootImageInfoProvider).(java.BootImageInfo)
 	modules := bootImageInfo.Modules()
 	android.AssertStringEquals(t, "invalid modules for "+moduleName, expectedConfiguredModules, modules.String())
 
@@ -166,7 +166,7 @@
 		prepareForTestWithBootclasspathFragment,
 		prepareForTestWithArtApex,
 
-		// Configure some libraries in the art boot image.
+		// Configure some libraries in the art bootclasspath_fragment.
 		java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
 	).RunTestWithBp(t, `
 		apex {
@@ -176,8 +176,8 @@
 				"mybootclasspathfragment",
 			],
 			// bar (like foo) should be transitively included in this apex because it is part of the
-			// mybootclasspathfragment boot_image. However, it is kept here to ensure that the apex dedups the files
-			// correctly.
+			// mybootclasspathfragment bootclasspath_fragment. However, it is kept here to ensure that the
+			// apex dedups the files correctly.
 			java_libs: [
 				"bar",
 			],
@@ -208,7 +208,7 @@
 			],
 		}
 
-		boot_image {
+		bootclasspath_fragment {
 			name: "mybootclasspathfragment",
 			image_name: "art",
 			apex_available: [
@@ -233,7 +233,7 @@
 		}
 
 		// Make sure that a preferred prebuilt doesn't affect the apex.
-		prebuilt_boot_image {
+		prebuilt_bootclasspath_fragment {
 			name: "mybootclasspathfragment",
 			image_name: "art",
 			prefer: true,
@@ -277,7 +277,7 @@
 			"com.android.art-arm.apex":   nil,
 		}),
 
-		// Configure some libraries in the art boot image.
+		// Configure some libraries in the art bootclasspath_fragment.
 		java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
 	).RunTestWithBp(t, `
 		prebuilt_apex {
@@ -309,7 +309,7 @@
 			],
 		}
 
-		prebuilt_boot_image {
+		prebuilt_bootclasspath_fragment {
 			name: "mybootclasspathfragment",
 			image_name: "art",
 			apex_available: [
@@ -369,7 +369,7 @@
 			],
 		}
 
-		boot_image {
+		bootclasspath_fragment {
 			name: "mybootclasspathfragment",
 			contents: [
 				"foo",
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 1db13f9..9bc5720 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -44,9 +44,13 @@
 // module.`
 type DeapexerProperties struct {
 	// List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
-	// APEX bundle will provide dex implementation jars for use by dexpreopt and boot jars package
-	// check.
+	// APEX bundle will create an APEX variant and provide dex implementation jars for use by
+	// dexpreopt and boot jars package check.
 	Exported_java_libs []string
+
+	// List of bootclasspath fragments inside this prebuiltd APEX bundle and for which this APEX
+	// bundle will create an APEX variant.
+	Exported_bootclasspath_fragments []string
 }
 
 type SelectedApexProperties struct {
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index a9d24a7..7830f95 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -97,10 +97,17 @@
 func (p *prebuiltCommon) deapexerDeps(ctx android.BottomUpMutatorContext) {
 	// Add dependencies onto the java modules that represent the java libraries that are provided by
 	// and exported from this prebuilt apex.
-	for _, lib := range p.deapexerProperties.Exported_java_libs {
-		dep := prebuiltApexExportedModuleName(ctx, lib)
+	for _, exported := range p.deapexerProperties.Exported_java_libs {
+		dep := prebuiltApexExportedModuleName(ctx, exported)
 		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
 	}
+
+	// Add dependencies onto the bootclasspath fragment modules that are exported from this prebuilt
+	// apex.
+	for _, exported := range p.deapexerProperties.Exported_bootclasspath_fragments {
+		dep := prebuiltApexExportedModuleName(ctx, exported)
+		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedBootclasspathFragmentTag, dep)
+	}
 }
 
 // apexInfoMutator marks any modules for which this apex exports a file as requiring an apex
@@ -137,18 +144,19 @@
 	var dependencies []android.ApexModule
 	mctx.VisitDirectDeps(func(m android.Module) {
 		tag := mctx.OtherModuleDependencyTag(m)
-		if tag == exportedJavaLibTag {
+		if exportedTag, ok := tag.(exportedDependencyTag); ok {
+			propertyName := exportedTag.name
 			depName := mctx.OtherModuleName(m)
 
 			// It is an error if the other module is not a prebuilt.
 			if _, ok := m.(android.PrebuiltInterface); !ok {
-				mctx.PropertyErrorf("exported_java_libs", "%q is not a prebuilt module", depName)
+				mctx.PropertyErrorf(propertyName, "%q is not a prebuilt module", depName)
 				return
 			}
 
 			// It is an error if the other module is not an ApexModule.
 			if _, ok := m.(android.ApexModule); !ok {
-				mctx.PropertyErrorf("exported_java_libs", "%q is not usable within an apex", depName)
+				mctx.PropertyErrorf(propertyName, "%q is not usable within an apex", depName)
 				return
 			}
 
@@ -451,7 +459,8 @@
 func (t exportedDependencyTag) ExcludeFromVisibilityEnforcement() {}
 
 var (
-	exportedJavaLibTag = exportedDependencyTag{name: "exported_java_lib"}
+	exportedJavaLibTag               = exportedDependencyTag{name: "exported_java_libs"}
+	exportedBootclasspathFragmentTag = exportedDependencyTag{name: "exported_bootclasspath_fragments"}
 )
 
 func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 8049108..c30abeb 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -14,6 +14,8 @@
 	OutputFiles          []string
 	CcObjectFiles        []string
 	CcStaticLibraryFiles []string
+	Includes             []string
+	SystemIncludes       []string
 }
 
 type getOutputFilesRequestType struct{}
@@ -63,6 +65,9 @@
 	return `
 outputFiles = [f.path for f in target.files.to_list()]
 
+includes = providers(target)["CcInfo"].compilation_context.includes.to_list()
+system_includes = providers(target)["CcInfo"].compilation_context.system_includes.to_list()
+
 ccObjectFiles = []
 staticLibraries = []
 linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
@@ -78,6 +83,8 @@
   outputFiles,
   staticLibraries,
   ccObjectFiles,
+  includes,
+  system_includes,
 ]
 
 return "|".join([", ".join(r) for r in returns])`
@@ -91,7 +98,7 @@
 	var ccObjects []string
 
 	splitString := strings.Split(rawString, "|")
-	if expectedLen := 3; len(splitString) != expectedLen {
+	if expectedLen := 5; len(splitString) != expectedLen {
 		return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
 	}
 	outputFilesString := splitString[0]
@@ -100,10 +107,14 @@
 	outputFiles = splitOrEmpty(outputFilesString, ", ")
 	ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
 	ccObjects = splitOrEmpty(ccObjectsString, ", ")
+	includes := splitOrEmpty(splitString[3], ", ")
+	systemIncludes := splitOrEmpty(splitString[4], ", ")
 	return CcInfo{
 		OutputFiles:          outputFiles,
 		CcObjectFiles:        ccObjects,
 		CcStaticLibraryFiles: ccStaticLibraries,
+		Includes:             includes,
+		SystemIncludes:       systemIncludes,
 	}, nil
 }
 
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 48edb90..6369999 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -3,6 +3,7 @@
 import (
 	"fmt"
 	"reflect"
+	"strings"
 	"testing"
 )
 
@@ -45,42 +46,48 @@
 	}{
 		{
 			description: "no result",
-			input:       "||",
+			input:       "||||",
 			expectedOutput: CcInfo{
 				OutputFiles:          []string{},
 				CcObjectFiles:        []string{},
 				CcStaticLibraryFiles: []string{},
+				Includes:             []string{},
+				SystemIncludes:       []string{},
 			},
 		},
 		{
 			description: "only output",
-			input:       "test||",
+			input:       "test||||",
 			expectedOutput: CcInfo{
 				OutputFiles:          []string{"test"},
 				CcObjectFiles:        []string{},
 				CcStaticLibraryFiles: []string{},
+				Includes:             []string{},
+				SystemIncludes:       []string{},
 			},
 		},
 		{
 			description: "all items set",
-			input:       "out1, out2|static_lib1, static_lib2|object1, object2",
+			input:       "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir",
 			expectedOutput: CcInfo{
 				OutputFiles:          []string{"out1", "out2"},
 				CcObjectFiles:        []string{"object1", "object2"},
 				CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
+				Includes:             []string{".", "dir/subdir"},
+				SystemIncludes:       []string{"system/dir", "system/other/dir"},
 			},
 		},
 		{
 			description:          "too few result splits",
 			input:                "|",
 			expectedOutput:       CcInfo{},
-			expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", ""}),
+			expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 5, []string{"", ""}),
 		},
 		{
 			description:          "too many result splits",
-			input:                "|||",
+			input:                strings.Repeat("|", 8),
 			expectedOutput:       CcInfo{},
-			expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 3, []string{"", "", "", ""}),
+			expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 5, make([]string, 9)),
 		},
 	}
 	for _, tc := range testCases {
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 1ede442..21d7062 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -204,8 +204,9 @@
 
 func TestGenerateBazelTargetModules(t *testing.T) {
 	testCases := []struct {
-		bp                  string
-		expectedBazelTarget string
+		name                 string
+		bp                   string
+		expectedBazelTargets []string
 	}{
 		{
 			bp: `custom {
@@ -214,7 +215,7 @@
     string_prop: "a",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `custom(
+			expectedBazelTargets: []string{`custom(
     name = "foo",
     string_list_prop = [
         "a",
@@ -222,6 +223,7 @@
     ],
     string_prop = "a",
 )`,
+			},
 		},
 		{
 			bp: `custom {
@@ -230,7 +232,7 @@
     string_prop: "a\t\n\r",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `custom(
+			expectedBazelTargets: []string{`custom(
     name = "control_characters",
     string_list_prop = [
         "\t",
@@ -238,6 +240,77 @@
     ],
     string_prop = "a\t\n\r",
 )`,
+			},
+		},
+		{
+			bp: `custom {
+  name: "has_dep",
+  arch_paths: [":dep"],
+  bazel_module: { bp2build_available: true },
+}
+
+custom {
+  name: "dep",
+  arch_paths: ["abc"],
+  bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`custom(
+    name = "dep",
+    arch_paths = ["abc"],
+)`,
+				`custom(
+    name = "has_dep",
+    arch_paths = [":dep"],
+)`,
+			},
+		},
+		{
+			bp: `custom {
+    name: "arch_paths",
+    arch: {
+      x86: {
+        arch_paths: ["abc"],
+      },
+    },
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`custom(
+    name = "arch_paths",
+    arch_paths = select({
+        "//build/bazel/platforms/arch:x86": ["abc"],
+        "//conditions:default": [],
+    }),
+)`,
+			},
+		},
+		{
+			bp: `custom {
+  name: "has_dep",
+  arch: {
+    x86: {
+      arch_paths: [":dep"],
+    },
+  },
+  bazel_module: { bp2build_available: true },
+}
+
+custom {
+    name: "dep",
+    arch_paths: ["abc"],
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`custom(
+    name = "dep",
+    arch_paths = ["abc"],
+)`,
+				`custom(
+    name = "has_dep",
+    arch_paths = select({
+        "//build/bazel/platforms/arch:x86": [":dep"],
+        "//conditions:default": [],
+    }),
+)`,
+			},
 		},
 	}
 
@@ -262,16 +335,18 @@
 		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
 		bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
 
-		if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
 			t.Errorf("Expected %d bazel target, got %d", expectedCount, actualCount)
 		} else {
-			actualBazelTarget := bazelTargets[0]
-			if actualBazelTarget.content != testCase.expectedBazelTarget {
-				t.Errorf(
-					"Expected generated Bazel target to be '%s', got '%s'",
-					testCase.expectedBazelTarget,
-					actualBazelTarget.content,
-				)
+			for i, expectedBazelTarget := range testCase.expectedBazelTargets {
+				actualBazelTarget := bazelTargets[i]
+				if actualBazelTarget.content != expectedBazelTarget {
+					t.Errorf(
+						"Expected generated Bazel target to be '%s', got '%s'",
+						expectedBazelTarget,
+						actualBazelTarget.content,
+					)
+				}
 			}
 		}
 	}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 30c1a5b..32b12e4 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -86,6 +86,7 @@
         "soong_module_name": attr.string(mandatory = True),
         "soong_module_variant": attr.string(),
         "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "arch_paths": attr.string_list(),
         # bazel_module start
 #         "label": attr.string(),
 #         "bp2build_available": attr.bool(),
@@ -114,6 +115,7 @@
         "soong_module_name": attr.string(mandatory = True),
         "soong_module_variant": attr.string(),
         "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "arch_paths": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
@@ -138,6 +140,7 @@
         "soong_module_name": attr.string(mandatory = True),
         "soong_module_variant": attr.string(),
         "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        "arch_paths": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
diff --git a/bp2build/testing.go b/bp2build/testing.go
index c4661ea..452f6ed 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -28,6 +28,8 @@
 
 	Nested_props     nestedProps
 	Nested_props_ptr *nestedProps
+
+	Arch_paths []string `android:"path,arch_variant"`
 }
 
 type customModule struct {
@@ -56,7 +58,7 @@
 
 func customModuleFactory() android.Module {
 	m := customModuleFactoryBase()
-	android.InitAndroidModule(m)
+	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
 	return m
 }
 
@@ -114,6 +116,7 @@
 type customBazelModuleAttributes struct {
 	String_prop      string
 	String_list_prop []string
+	Arch_paths       bazel.LabelListAttribute
 }
 
 type customBazelModule struct {
@@ -137,9 +140,18 @@
 			return
 		}
 
+		paths := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.props.Arch_paths))
+
+		for arch, props := range m.GetArchProperties(&customProps{}) {
+			if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
+				paths.SetValueForArch(arch.Name, android.BazelLabelForModuleSrc(ctx, archProps.Arch_paths))
+			}
+		}
+
 		attrs := &customBazelModuleAttributes{
 			String_prop:      m.props.String_prop,
 			String_list_prop: m.props.String_list_prop,
+			Arch_paths:       paths,
 		}
 
 		props := bazel.BazelTargetModuleProperties{
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 536efa4..8f3a652 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -191,17 +191,31 @@
 }
 
 func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) {
-	exportedFlags := library.flagExporter.flags
-	for _, dir := range library.flagExporter.dirs {
+	var exportedFlags []string
+	var includeDirs android.Paths
+	var systemIncludeDirs android.Paths
+	var exportedDeps android.Paths
+
+	if library.flagExporterInfo != nil {
+		exportedFlags = library.flagExporterInfo.Flags
+		includeDirs = library.flagExporterInfo.IncludeDirs
+		systemIncludeDirs = library.flagExporterInfo.SystemIncludeDirs
+		exportedDeps = library.flagExporterInfo.Deps
+	} else {
+		exportedFlags = library.flagExporter.flags
+		includeDirs = library.flagExporter.dirs
+		systemIncludeDirs = library.flagExporter.systemDirs
+		exportedDeps = library.flagExporter.deps
+	}
+	for _, dir := range includeDirs {
 		exportedFlags = append(exportedFlags, "-I"+dir.String())
 	}
-	for _, dir := range library.flagExporter.systemDirs {
+	for _, dir := range systemIncludeDirs {
 		exportedFlags = append(exportedFlags, "-isystem "+dir.String())
 	}
 	if len(exportedFlags) > 0 {
 		entries.AddStrings("LOCAL_EXPORT_CFLAGS", exportedFlags...)
 	}
-	exportedDeps := library.flagExporter.deps
 	if len(exportedDeps) > 0 {
 		entries.AddStrings("LOCAL_EXPORT_C_INCLUDE_DEPS", exportedDeps.Strings()...)
 	}
diff --git a/cc/genrule.go b/cc/genrule.go
index 82d7205..ca4fda7 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -75,10 +75,6 @@
 	return Bool(g.Vendor_ramdisk_available)
 }
 
-func (g *GenruleExtraProperties) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
 func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	// If the build is using a snapshot, the recovery variant under AOSP directories
 	// is not needed.
diff --git a/cc/image.go b/cc/image.go
index bf662c6..c1e5dfe 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -601,10 +601,6 @@
 	return c.Properties.VendorRamdiskVariantNeeded
 }
 
-func (c *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
 func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return c.Properties.RecoveryVariantNeeded
 }
diff --git a/cc/library.go b/cc/library.go
index 8acd7c7..af92b24 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -426,7 +426,8 @@
 	tocFile android.OptionalPath
 
 	flagExporter
-	stripper Stripper
+	flagExporterInfo *FlagExporterInfo
+	stripper         Stripper
 
 	// For whole_static_libs
 	objects Objects
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 078242f..f2cb52b 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -43,6 +43,52 @@
 	ctx.RegisterModuleType("cc_prebuilt_library_headers", prebuiltLibraryHeaderFactory)
 }
 
+type libraryHeaderBazelHander struct {
+	bazelHandler
+
+	module  *Module
+	library *libraryDecorator
+}
+
+func (h *libraryHeaderBazelHander) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
+	bazelCtx := ctx.Config().BazelContext
+	ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
+	if err != nil {
+		ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
+		return false
+	}
+	if !ok {
+		return false
+	}
+
+	outputPaths := ccInfo.OutputFiles
+	if len(outputPaths) != 1 {
+		ctx.ModuleErrorf("expected exactly one output file for %q, but got %q", label, outputPaths)
+		return false
+	}
+
+	outputPath := android.PathForBazelOut(ctx, outputPaths[0])
+	h.module.outputFile = android.OptionalPathForPath(outputPath)
+
+	// HeaderLibraryInfo is an empty struct to indicate to dependencies that this is a header library
+	ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+
+	flagExporterInfo := flagExporterInfoFromCcInfo(ctx, ccInfo)
+	// Store flag info to be passed along to androimk
+	// TODO(b/184387147): Androidmk should be done in Bazel, not Soong.
+	h.library.flagExporterInfo = &flagExporterInfo
+	// flag exporters consolidates properties like includes, flags, dependencies that should be
+	// exported from this module to other modules
+	ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfo)
+
+	// Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
+	// validation will fail. For now, set this to an empty list.
+	// TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
+	h.library.collectedSnapshotHeaders = android.Paths{}
+
+	return true
+}
+
 // cc_library_headers contains a set of c/c++ headers which are imported by
 // other soong cc modules using the header_libs property. For best practices,
 // use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
@@ -51,6 +97,7 @@
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.HeaderOnly()
 	module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType}
+	module.bazelHandler = &libraryHeaderBazelHander{module: module, library: library}
 	return module.Init()
 }
 
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index d5f2adf..9010a1a 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -162,9 +162,16 @@
 	return &nativeLibInfoProperties{memberType: mt}
 }
 
+func isBazelOutDirectory(p android.Path) bool {
+	_, bazel := p.(android.BazelOutPath)
+	return bazel
+}
+
 func isGeneratedHeaderDirectory(p android.Path) bool {
 	_, gen := p.(android.WritablePath)
-	return gen
+	// TODO(b/183213331): Here we assume that bazel-based headers are not generated; we need
+	// to support generated headers in mixed builds.
+	return gen && !isBazelOutDirectory(p)
 }
 
 type includeDirsProperty struct {
diff --git a/cc/linkable.go b/cc/linkable.go
index 0fb9c09..2fa12f6 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -2,6 +2,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/bazel/cquery"
 
 	"github.com/google/blueprint"
 )
@@ -274,3 +275,15 @@
 }
 
 var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
+
+// flagExporterInfoFromCcInfo populates FlagExporterInfo provider with information from Bazel.
+func flagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) FlagExporterInfo {
+
+	includes := android.PathsForBazelOut(ctx, ccInfo.Includes)
+	systemIncludes := android.PathsForBazelOut(ctx, ccInfo.SystemIncludes)
+
+	return FlagExporterInfo{
+		IncludeDirs:       includes,
+		SystemIncludeDirs: systemIncludes,
+	}
+}
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 885a0ce..c12ad79 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -308,10 +308,6 @@
 	return false
 }
 
-func (s *snapshot) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
 func (s *snapshot) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return false
 }
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 3204e70..6e502b7 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -84,13 +84,6 @@
 	// the recovery variant instead.
 	Vendor_ramdisk_available *bool
 
-	// Make this module available when building for debug ramdisk.
-	// On device without a dedicated recovery partition, the module is only
-	// available after switching root into
-	// /first_stage_ramdisk. To expose the module before switching root, install
-	// the recovery variant instead.
-	Debug_ramdisk_available *bool
-
 	// Make this module available when building for recovery.
 	Recovery_available *bool
 
@@ -166,18 +159,6 @@
 	return p.inVendorRamdisk()
 }
 
-func (p *PrebuiltEtc) inDebugRamdisk() bool {
-	return p.ModuleBase.InDebugRamdisk() || p.ModuleBase.InstallInDebugRamdisk()
-}
-
-func (p *PrebuiltEtc) onlyInDebugRamdisk() bool {
-	return p.ModuleBase.InstallInDebugRamdisk()
-}
-
-func (p *PrebuiltEtc) InstallInDebugRamdisk() bool {
-	return p.inDebugRamdisk()
-}
-
 func (p *PrebuiltEtc) inRecovery() bool {
 	return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
 }
@@ -196,7 +177,7 @@
 
 func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
 	return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk() &&
-		!p.ModuleBase.InstallInVendorRamdisk() && !p.ModuleBase.InstallInDebugRamdisk()
+		!p.ModuleBase.InstallInVendorRamdisk()
 }
 
 func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -207,10 +188,6 @@
 	return proptools.Bool(p.properties.Vendor_ramdisk_available) || p.ModuleBase.InstallInVendorRamdisk()
 }
 
-func (p *PrebuiltEtc) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return proptools.Bool(p.properties.Debug_ramdisk_available) || p.ModuleBase.InstallInDebugRamdisk()
-}
-
 func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
 }
@@ -336,9 +313,6 @@
 	if p.inVendorRamdisk() && !p.onlyInVendorRamdisk() {
 		nameSuffix = ".vendor_ramdisk"
 	}
-	if p.inDebugRamdisk() && !p.onlyInDebugRamdisk() {
-		nameSuffix = ".debug_ramdisk"
-	}
 	if p.inRecovery() && !p.onlyInRecovery() {
 		nameSuffix = ".recovery"
 	}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 77dae75..b426b20 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -626,7 +626,6 @@
 func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool            { return false }
 func (x noopImageInterface) RamdiskVariantNeeded(android.BaseModuleContext) bool         { return false }
 func (x noopImageInterface) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool   { return false }
-func (x noopImageInterface) DebugRamdiskVariantNeeded(android.BaseModuleContext) bool    { return false }
 func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool        { return false }
 func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil }
 func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
diff --git a/java/Android.bp b/java/Android.bp
index 8e3e10d..a17140c 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -29,8 +29,9 @@
         "app_import.go",
         "app_set.go",
         "base.go",
-        "boot_image.go",
         "boot_jars.go",
+        "bootclasspath.go",
+        "bootclasspath_fragment.go",
         "builder.go",
         "classpath_fragment.go",
         "device_host_converter.go",
@@ -72,7 +73,7 @@
         "app_import_test.go",
         "app_set_test.go",
         "app_test.go",
-        "boot_image_test.go",
+        "bootclasspath_fragment_test.go",
         "device_host_converter_test.go",
         "dexpreopt_test.go",
         "dexpreopt_bootjars_test.go",
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
new file mode 100644
index 0000000..6ca0f75
--- /dev/null
+++ b/java/bootclasspath.go
@@ -0,0 +1,172 @@
+// Copyright 2021 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 (
+	"fmt"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+// Contains code that is common to both platform_bootclasspath and bootclasspath_fragment.
+
+func init() {
+	registerBootclasspathBuildComponents(android.InitRegistrationContext)
+}
+
+func registerBootclasspathBuildComponents(ctx android.RegistrationContext) {
+	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator)
+	})
+}
+
+// BootclasspathDepsMutator is the interface that a module must implement if it wants to add
+// dependencies onto APEX specific variants of bootclasspath fragments or bootclasspath contents.
+type BootclasspathDepsMutator interface {
+	// BootclasspathDepsMutator implementations should add dependencies using
+	// addDependencyOntoApexModulePair and addDependencyOntoApexVariants.
+	BootclasspathDepsMutator(ctx android.BottomUpMutatorContext)
+}
+
+// bootclasspathDepsMutator is called during the final deps phase after all APEX variants have
+// been created so can add dependencies onto specific APEX variants of modules.
+func bootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
+	m := ctx.Module()
+	if p, ok := m.(BootclasspathDepsMutator); ok {
+		p.BootclasspathDepsMutator(ctx)
+	}
+}
+
+// addDependencyOntoApexVariants adds dependencies onto the appropriate apex specific variants of
+// the module as specified in the ApexVariantReference list.
+func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyName string, refs []ApexVariantReference, tag blueprint.DependencyTag) {
+	for i, ref := range refs {
+		apex := proptools.StringDefault(ref.Apex, "platform")
+
+		if ref.Module == nil {
+			ctx.PropertyErrorf(propertyName, "missing module name at position %d", i)
+			continue
+		}
+		name := proptools.String(ref.Module)
+
+		addDependencyOntoApexModulePair(ctx, apex, name, tag)
+	}
+}
+
+// addDependencyOntoApexModulePair adds a dependency onto the specified APEX specific variant or the
+// specified module.
+//
+// If apex="platform" then this adds a dependency onto the platform variant of the module. This adds
+// dependencies onto the prebuilt and source modules with the specified name, depending on which
+// ones are available. Visiting must use isActiveModule to select the preferred module when both
+// source and prebuilt modules are available.
+func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
+	var variations []blueprint.Variation
+	if apex != "platform" {
+		// Pick the correct apex variant.
+		variations = []blueprint.Variation{
+			{Mutator: "apex", Variation: apex},
+		}
+	}
+
+	addedDep := false
+	if ctx.OtherModuleDependencyVariantExists(variations, name) {
+		ctx.AddFarVariationDependencies(variations, tag, name)
+		addedDep = true
+	}
+
+	// Add a dependency on the prebuilt module if it exists.
+	prebuiltName := android.PrebuiltNameFromSource(name)
+	if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
+		ctx.AddVariationDependencies(variations, tag, prebuiltName)
+		addedDep = true
+	}
+
+	// If no appropriate variant existing for this, so no dependency could be added, then it is an
+	// error, unless missing dependencies are allowed. The simplest way to handle that is to add a
+	// dependency that will not be satisfied and the default behavior will handle it.
+	if !addedDep {
+		// Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does
+		// not exist. The resulting error message will contain useful information about the available
+		// variants.
+		reportMissingVariationDependency(ctx, variations, name)
+
+		// Add dependency on the missing prefixed prebuilt variant too if a module with that name exists
+		// so that information about its available variants will be reported too.
+		if ctx.OtherModuleExists(prebuiltName) {
+			reportMissingVariationDependency(ctx, variations, prebuiltName)
+		}
+	}
+}
+
+// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order
+// to generate an appropriate error message with information about the available variations.
+func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) {
+	modules := ctx.AddFarVariationDependencies(variations, nil, name)
+	if len(modules) != 1 {
+		panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules)))
+		return
+	}
+	if modules[0] != nil {
+		panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0]))
+		return
+	}
+}
+
+// ApexVariantReference specifies a particular apex variant of a module.
+type ApexVariantReference struct {
+	// The name of the module apex variant, i.e. the apex containing the module variant.
+	//
+	// If this is not specified then it defaults to "platform" which will cause a dependency to be
+	// added to the module's platform variant.
+	Apex *string
+
+	// The name of the module.
+	Module *string
+}
+
+// BootclasspathFragmentsDepsProperties contains properties related to dependencies onto fragments.
+type BootclasspathFragmentsDepsProperties struct {
+	// The names of the bootclasspath_fragment modules that form part of this module.
+	Fragments []ApexVariantReference
+}
+
+// addDependenciesOntoFragments adds dependencies to the fragments specified in this properties
+// structure.
+func (p *BootclasspathFragmentsDepsProperties) addDependenciesOntoFragments(ctx android.BottomUpMutatorContext) {
+	addDependencyOntoApexVariants(ctx, "fragments", p.Fragments, bootclasspathFragmentDepTag)
+}
+
+// bootclasspathDependencyTag defines dependencies from/to bootclasspath_fragment,
+// prebuilt_bootclasspath_fragment and platform_bootclasspath onto either source or prebuilt
+// modules.
+type bootclasspathDependencyTag struct {
+	blueprint.BaseDependencyTag
+
+	name string
+}
+
+func (t bootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() {
+}
+
+// Dependencies that use the bootclasspathDependencyTag instances are only added after all the
+// visibility checking has been done so this has no functional effect. However, it does make it
+// clear that visibility is not being enforced on these tags.
+var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathDependencyTag{}
+
+// The tag used for dependencies onto bootclasspath_fragments.
+var bootclasspathFragmentDepTag = bootclasspathDependencyTag{name: "fragment"}
diff --git a/java/boot_image.go b/java/bootclasspath_fragment.go
similarity index 69%
rename from java/boot_image.go
rename to java/bootclasspath_fragment.go
index d0862a9..619d47f 100644
--- a/java/boot_image.go
+++ b/java/bootclasspath_fragment.go
@@ -27,17 +27,9 @@
 )
 
 func init() {
-	RegisterBootImageBuildComponents(android.InitRegistrationContext)
+	registerBootclasspathFragmentBuildComponents(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{
+	android.RegisterSdkMemberType(&bootclasspathFragmentMemberType{
 		SdkMemberTypeBase: android.SdkMemberTypeBase{
 			PropertyName: "bootclasspath_fragments",
 			SupportsSdk:  true,
@@ -45,23 +37,19 @@
 	})
 }
 
-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)
+func registerBootclasspathFragmentBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("bootclasspath_fragment", bootclasspathFragmentFactory)
+	ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory)
 }
 
 type bootclasspathFragmentContentDependencyTag struct {
 	blueprint.BaseDependencyTag
 }
 
-// Avoid having to make boot image content visible to the boot image.
+// Avoid having to make bootclasspath_fragment content visible to the bootclasspath_fragment.
 //
-// This is a temporary workaround to make it easier to migrate to boot image modules with proper
-// dependencies.
+// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
+// with proper dependencies.
 // TODO(b/177892522): Remove this and add needed visibility.
 func (b bootclasspathFragmentContentDependencyTag) ExcludeFromVisibilityEnforcement() {
 }
@@ -71,7 +59,7 @@
 	return false
 }
 
-// The tag used for the dependency between the boot image module and its contents.
+// The tag used for the dependency between the bootclasspath_fragment module and its contents.
 var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyTag{}
 
 var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag
@@ -81,13 +69,13 @@
 	return tag == bootclasspathFragmentContentDepTag
 }
 
-type bootImageProperties struct {
+type bootclasspathFragmentProperties struct {
 	// The name of the image this represents.
 	//
 	// If specified then it must be one of "art" or "boot".
 	Image_name *string
 
-	// The contents of this boot image, could be either java_library, java_sdk_library, or boot_image.
+	// The contents of this bootclasspath_fragment, 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
@@ -95,28 +83,30 @@
 	Hidden_api HiddenAPIFlagFileProperties
 }
 
-type BootImageModule struct {
+type BootclasspathFragmentModule struct {
 	android.ModuleBase
 	android.ApexModuleBase
 	android.SdkBase
-	properties bootImageProperties
+	properties bootclasspathFragmentProperties
 }
 
-func bootImageFactory() android.Module {
-	m := &BootImageModule{}
+func bootclasspathFragmentFactory() android.Module {
+	m := &BootclasspathFragmentModule{}
 	m.AddProperties(&m.properties)
 	android.InitApexModule(m)
 	android.InitSdkAwareModule(m)
 	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
 
-	// Perform some consistency checking to ensure that the configuration is correct.
+	// Initialize the contents property from the image_name.
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
-		bootImageConsistencyCheck(ctx, m)
+		bootclasspathFragmentInitContentsFromImage(ctx, m)
 	})
 	return m
 }
 
-func bootImageConsistencyCheck(ctx android.EarlyModuleContext, m *BootImageModule) {
+// bootclasspathFragmentInitContentsFromImage will initialize the contents property from the image_name if
+// necessary.
+func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) {
 	contents := m.properties.Contents
 	if m.properties.Image_name == nil && len(contents) == 0 {
 		ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
@@ -124,8 +114,22 @@
 	if m.properties.Image_name != nil && len(contents) != 0 {
 		ctx.ModuleErrorf(`both of the "image_name" and "contents" properties have been supplied, please supply exactly one`)
 	}
+
 	imageName := proptools.String(m.properties.Image_name)
 	if imageName == "art" {
+		// TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
+		if m.MemberName() != "" {
+			// The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
+			// 1. There is no way to use this at the moment so ignoring it is safe.
+			// 2. Attempting to initialize the contents property from the configuration will end up having
+			//    the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
+			//    as the unversioned prebuilt could end up with an APEX variant created for the source
+			//    APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
+			//    turn will prevent it from accessing the dex implementation jar from that which will
+			//    break hidden API processing, amongst others.
+			return
+		}
+
 		// Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is
 		// too early in the Soong processing for that to work.
 		global := dexpreopt.GetGlobalConfig(ctx)
@@ -192,7 +196,7 @@
 	return files
 }
 
-func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	tag := ctx.OtherModuleDependencyTag(dep)
 	if IsBootclasspathFragmentContentDepTag(tag) {
 		// Boot image contents are automatically added to apex.
@@ -205,7 +209,7 @@
 	panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag)))
 }
 
-func (b *BootImageModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
+func (b *BootclasspathFragmentModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
 	return nil
 }
 
@@ -213,9 +217,9 @@
 // corresponding source module are renamed. This means that adding a dependency using a name without
 // a prebuilt_ prefix will always resolve to a source module and when using a name with that prefix
 // it will always resolve to a prebuilt module.
-func (b *BootImageModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
+func (b *BootclasspathFragmentModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
 	module := ctx.Module()
-	_, isSourceModule := module.(*BootImageModule)
+	_, isSourceModule := module.(*BootclasspathFragmentModule)
 
 	for _, name := range b.properties.Contents {
 		// A bootclasspath_fragment must depend only on other source modules, while the
@@ -230,7 +234,7 @@
 
 }
 
-func (b *BootImageModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 
 	if SkipDexpreoptBootJars(ctx) {
 		return
@@ -241,7 +245,7 @@
 	dexpreopt.RegisterToolDeps(ctx)
 }
 
-func (b *BootImageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// Perform hidden API processing.
 	b.generateHiddenAPIBuildActions(ctx)
 
@@ -266,7 +270,7 @@
 	ctx.SetProvider(BootImageInfoProvider, info)
 }
 
-func (b *BootImageModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
+func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
 	// Get a map of the image configs that are supported.
 	imageConfigs := genBootImageConfigs(ctx)
 
@@ -286,7 +290,7 @@
 }
 
 // generateHiddenAPIBuildActions generates all the hidden API related build rules.
-func (b *BootImageModule) generateHiddenAPIBuildActions(ctx android.ModuleContext) {
+func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext) {
 	// Resolve the properties to paths.
 	flagFileInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx)
 
@@ -294,20 +298,20 @@
 	ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
 }
 
-type bootImageMemberType struct {
+type bootclasspathFragmentMemberType struct {
 	android.SdkMemberTypeBase
 }
 
-func (b *bootImageMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+func (b *bootclasspathFragmentMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
 	mctx.AddVariationDependencies(nil, dependencyTag, names...)
 }
 
-func (b *bootImageMemberType) IsInstance(module android.Module) bool {
-	_, ok := module.(*BootImageModule)
+func (b *bootclasspathFragmentMemberType) IsInstance(module android.Module) bool {
+	_, ok := module.(*BootclasspathFragmentModule)
 	return ok
 }
 
-func (b *bootImageMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+func (b *bootclasspathFragmentMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
 	if b.PropertyName == "boot_images" {
 		return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_boot_image")
 	} else {
@@ -315,11 +319,11 @@
 	}
 }
 
-func (b *bootImageMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
-	return &bootImageSdkMemberProperties{}
+func (b *bootclasspathFragmentMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &bootclasspathFragmentSdkMemberProperties{}
 }
 
-type bootImageSdkMemberProperties struct {
+type bootclasspathFragmentSdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
 	// The image name
@@ -332,8 +336,8 @@
 	Flag_files_by_category map[*hiddenAPIFlagFileCategory]android.Paths
 }
 
-func (b *bootImageSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
-	module := variant.(*BootImageModule)
+func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	module := variant.(*BootclasspathFragmentModule)
 
 	b.Image_name = module.properties.Image_name
 	if b.Image_name == nil {
@@ -349,7 +353,7 @@
 	b.Flag_files_by_category = flagFileInfo.categoryToPaths
 }
 
-func (b *bootImageSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
 	if b.Image_name != nil {
 		propertySet.AddProperty("image_name", *b.Image_name)
 	}
@@ -376,28 +380,28 @@
 	}
 }
 
-var _ android.SdkMemberType = (*bootImageMemberType)(nil)
+var _ android.SdkMemberType = (*bootclasspathFragmentMemberType)(nil)
 
-// A prebuilt version of the boot image module.
+// A prebuilt version of the bootclasspath_fragment module.
 //
-// At the moment this is basically just a boot image module that can be used as a prebuilt.
-// Eventually as more functionality is migrated into the boot image module from the singleton then
-// this will diverge.
-type prebuiltBootImageModule struct {
-	BootImageModule
+// At the moment this is basically just a bootclasspath_fragment module that can be used as a
+// prebuilt. Eventually as more functionality is migrated into the bootclasspath_fragment module
+// type from the various singletons then this will diverge.
+type prebuiltBootclasspathFragmentModule struct {
+	BootclasspathFragmentModule
 	prebuilt android.Prebuilt
 }
 
-func (module *prebuiltBootImageModule) Prebuilt() *android.Prebuilt {
+func (module *prebuiltBootclasspathFragmentModule) Prebuilt() *android.Prebuilt {
 	return &module.prebuilt
 }
 
-func (module *prebuiltBootImageModule) Name() string {
+func (module *prebuiltBootclasspathFragmentModule) Name() string {
 	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
-func prebuiltBootImageFactory() android.Module {
-	m := &prebuiltBootImageModule{}
+func prebuiltBootclasspathFragmentFactory() android.Module {
+	m := &prebuiltBootclasspathFragmentModule{}
 	m.AddProperties(&m.properties)
 	// This doesn't actually have any prebuilt files of its own so pass a placeholder for the srcs
 	// array.
@@ -406,9 +410,9 @@
 	android.InitSdkAwareModule(m)
 	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
 
-	// Perform some consistency checking to ensure that the configuration is correct.
+	// Initialize the contents property from the image_name.
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
-		bootImageConsistencyCheck(ctx, &m.BootImageModule)
+		bootclasspathFragmentInitContentsFromImage(ctx, &m.BootclasspathFragmentModule)
 	})
 	return m
 }
diff --git a/java/boot_image_test.go b/java/bootclasspath_fragment_test.go
similarity index 65%
rename from java/boot_image_test.go
rename to java/bootclasspath_fragment_test.go
index e1866de..524a226 100644
--- a/java/boot_image_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -21,60 +21,60 @@
 	"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.
+// Contains some simple tests for bootclasspath_fragment logic, additional tests can be found in
+// apex/bootclasspath_fragment_test.go as the ART boot image requires modules from the ART apex.
 
-var prepareForTestWithBootImage = android.GroupFixturePreparers(
+var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers(
 	PrepareForTestWithJavaDefaultModules,
 	dexpreopt.PrepareForTestByEnablingDexpreopt,
 )
 
-func TestUnknownBootImage(t *testing.T) {
-	prepareForTestWithBootImage.
+func TestUnknownBootclasspathFragment(t *testing.T) {
+	prepareForTestWithBootclasspathFragment.
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
 			`\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
 		RunTestWithBp(t, `
-			boot_image {
-				name: "unknown-boot-image",
+			bootclasspath_fragment {
+				name: "unknown-bootclasspath-fragment",
 				image_name: "unknown",
 			}
 		`)
 }
 
 func TestUnknownBootclasspathFragmentImageName(t *testing.T) {
-	prepareForTestWithBootImage.
+	prepareForTestWithBootclasspathFragment.
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
 			`\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
 		RunTestWithBp(t, `
 			bootclasspath_fragment {
-				name: "unknown-boot-image",
+				name: "unknown-bootclasspath-fragment",
 				image_name: "unknown",
 			}
 		`)
 }
 
-func TestUnknownPrebuiltBootImage(t *testing.T) {
-	prepareForTestWithBootImage.
+func TestUnknownPrebuiltBootclasspathFragment(t *testing.T) {
+	prepareForTestWithBootclasspathFragment.
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
 			`\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)).
 		RunTestWithBp(t, `
-			prebuilt_boot_image {
-				name: "unknown-boot-image",
+			prebuilt_bootclasspath_fragment {
+				name: "unknown-bootclasspath-fragment",
 				image_name: "unknown",
 			}
 		`)
 }
 
-func TestBootImageInconsistentArtConfiguration_Platform(t *testing.T) {
+func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T) {
 	android.GroupFixturePreparers(
-		prepareForTestWithBootImage,
+		prepareForTestWithBootclasspathFragment,
 		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",
+			bootclasspath_fragment {
+				name: "bootclasspath-fragment",
 				image_name: "art",
 				apex_available: [
 					"apex",
@@ -83,16 +83,16 @@
 		`)
 }
 
-func TestBootImageInconsistentArtConfiguration_ApexMixture(t *testing.T) {
+func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testing.T) {
 	android.GroupFixturePreparers(
-		prepareForTestWithBootImage,
+		prepareForTestWithBootclasspathFragment,
 		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",
+			bootclasspath_fragment {
+				name: "bootclasspath-fragment",
 				image_name: "art",
 				apex_available: [
 					"apex1",
@@ -102,24 +102,24 @@
 		`)
 }
 
-func TestBootImageWithoutImageNameOrContents(t *testing.T) {
-	prepareForTestWithBootImage.
+func TestBootclasspathFragmentWithoutImageNameOrContents(t *testing.T) {
+	prepareForTestWithBootclasspathFragment.
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
 			`\Qneither of the "image_name" and "contents" properties\E`)).
 		RunTestWithBp(t, `
-			boot_image {
-				name: "boot-image",
+			bootclasspath_fragment {
+				name: "bootclasspath-fragment",
 			}
 		`)
 }
 
-func TestBootImageWithImageNameAndContents(t *testing.T) {
-	prepareForTestWithBootImage.
+func TestBootclasspathFragmentWithImageNameAndContents(t *testing.T) {
+	prepareForTestWithBootclasspathFragment.
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
 			`\Qboth of the "image_name" and "contents" properties\E`)).
 		RunTestWithBp(t, `
-			boot_image {
-				name: "boot-image",
+			bootclasspath_fragment {
+				name: "bootclasspath-fragment",
 				image_name: "boot",
 				contents: ["other"],
 			}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 656f5ef..0ab6502 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -236,9 +236,5 @@
 }
 
 func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
-	ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":"))
-	ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":"))
-	ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":"))
-
 	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
 }
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index e575085..bc3b474 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -84,6 +84,11 @@
 	// created by the unsupported app usage annotation processor during compilation of the class
 	// implementation jar.
 	indexCSVPath android.Path
+
+	// The paths to the classes jars that contain classes and class members annotated with
+	// the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API
+	// processing.
+	classesJarPaths android.Paths
 }
 
 func (h *hiddenAPI) flagsCSV() android.Path {
@@ -102,11 +107,16 @@
 	return h.indexCSVPath
 }
 
+func (h *hiddenAPI) classesJars() android.Paths {
+	return h.classesJarPaths
+}
+
 type hiddenAPIIntf interface {
 	bootDexJar() android.Path
 	flagsCSV() android.Path
 	indexCSV() android.Path
 	metadataCSV() android.Path
+	classesJars() android.Paths
 }
 
 var _ hiddenAPIIntf = (*hiddenAPI)(nil)
@@ -244,6 +254,7 @@
 		javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
 		classesJars = append(classesJars, javaInfo.ImplementationJars...)
 	})
+	h.classesJarPaths = classesJars
 
 	stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
 
diff --git a/java/lint.go b/java/lint.go
index 862c9b4..5e39274 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -261,6 +261,7 @@
 	cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
 
 	if BoolDefault(l.properties.Lint.Strict_updatability_linting, false) {
+		// Verify the module does not baseline issues that endanger safe updatability.
 		if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
 			cmd.FlagWithInput("--baseline ", baselinePath.Path())
 			cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 568f5e4..b1a0ac4 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -19,8 +19,6 @@
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -29,33 +27,10 @@
 
 func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)
-
-	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("platform_bootclasspath_deps", platformBootclasspathDepsMutator)
-	})
-}
-
-type platformBootclasspathDependencyTag struct {
-	blueprint.BaseDependencyTag
-
-	name string
-}
-
-// Avoid having to make platform bootclasspath content visible to the platform bootclasspath.
-//
-// This is a temporary workaround to make it easier to migrate to platform bootclasspath with proper
-// dependencies.
-// TODO(b/177892522): Remove this and add needed visibility.
-func (t platformBootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() {
 }
 
 // The tag used for the dependency between the platform bootclasspath and any configured boot jars.
-var platformBootclasspathModuleDepTag = platformBootclasspathDependencyTag{name: "module"}
-
-// The tag used for the dependency between the platform bootclasspath and bootclasspath_fragments.
-var platformBootclasspathFragmentDepTag = platformBootclasspathDependencyTag{name: "fragment"}
-
-var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathDependencyTag{}
+var platformBootclasspathModuleDepTag = bootclasspathDependencyTag{name: "module"}
 
 type platformBootclasspathModule struct {
 	android.ModuleBase
@@ -83,22 +58,8 @@
 	hiddenAPIMetadataCSV android.OutputPath
 }
 
-// ApexVariantReference specifies a particular apex variant of a module.
-type ApexVariantReference struct {
-	// The name of the module apex variant, i.e. the apex containing the module variant.
-	//
-	// If this is not specified then it defaults to "platform" which will cause a dependency to be
-	// added to the module's platform variant.
-	Apex *string
-
-	// The name of the module.
-	Module *string
-}
-
 type platformBootclasspathProperties struct {
-	// The names of the bootclasspath_fragment modules that form part of this
-	// platform_bootclasspath.
-	Fragments []ApexVariantReference
+	BootclasspathFragmentsDepsProperties
 
 	Hidden_api HiddenAPIFlagFileProperties
 }
@@ -161,92 +122,22 @@
 	hiddenAPIAddStubLibDependencies(ctx, sdkKindToStubLibModules)
 }
 
-func platformBootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
-	m := ctx.Module()
-	if p, ok := m.(*platformBootclasspathModule); ok {
-		// Add dependencies on all the modules configured in the "art" boot image.
-		artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
-		addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)
+func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
+	// Add dependencies on all the modules configured in the "art" boot image.
+	artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
+	addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)
 
-		// Add dependencies on all the modules configured in the "boot" boot image. That does not
-		// include modules configured in the "art" boot image.
-		bootImageConfig := p.getImageConfig(ctx)
-		addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)
+	// Add dependencies on all the modules configured in the "boot" boot image. That does not
+	// include modules configured in the "art" boot image.
+	bootImageConfig := b.getImageConfig(ctx)
+	addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)
 
-		// Add dependencies on all the updatable modules.
-		updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
-		addDependenciesOntoBootImageModules(ctx, updatableModules)
+	// Add dependencies on all the updatable modules.
+	updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
+	addDependenciesOntoBootImageModules(ctx, updatableModules)
 
-		// Add dependencies on all the fragments.
-		addDependencyOntoApexVariants(ctx, "fragments", p.properties.Fragments, platformBootclasspathFragmentDepTag)
-	}
-}
-
-func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyName string, refs []ApexVariantReference, tag blueprint.DependencyTag) {
-	for i, ref := range refs {
-		apex := proptools.StringDefault(ref.Apex, "platform")
-
-		if ref.Module == nil {
-			ctx.PropertyErrorf(propertyName, "missing module name at position %d", i)
-			continue
-		}
-		name := proptools.String(ref.Module)
-
-		addDependencyOntoApexModulePair(ctx, apex, name, tag)
-	}
-}
-
-func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
-	var variations []blueprint.Variation
-	if apex != "platform" {
-		// Pick the correct apex variant.
-		variations = []blueprint.Variation{
-			{Mutator: "apex", Variation: apex},
-		}
-	}
-
-	addedDep := false
-	if ctx.OtherModuleDependencyVariantExists(variations, name) {
-		ctx.AddFarVariationDependencies(variations, tag, name)
-		addedDep = true
-	}
-
-	// Add a dependency on the prebuilt module if it exists.
-	prebuiltName := android.PrebuiltNameFromSource(name)
-	if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
-		ctx.AddVariationDependencies(variations, tag, prebuiltName)
-		addedDep = true
-	}
-
-	// If no appropriate variant existing for this, so no dependency could be added, then it is an
-	// error, unless missing dependencies are allowed. The simplest way to handle that is to add a
-	// dependency that will not be satisfied and the default behavior will handle it.
-	if !addedDep {
-		// Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does
-		// not exist. The resulting error message will contain useful information about the available
-		// variants.
-		reportMissingVariationDependency(ctx, variations, name)
-
-		// Add dependency on the missing prefixed prebuilt variant too if a module with that name exists
-		// so that information about its available variants will be reported too.
-		if ctx.OtherModuleExists(prebuiltName) {
-			reportMissingVariationDependency(ctx, variations, prebuiltName)
-		}
-	}
-}
-
-// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order
-// to generate an appropriate error message with information about the available variations.
-func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) {
-	modules := ctx.AddFarVariationDependencies(variations, nil, name)
-	if len(modules) != 1 {
-		panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules)))
-		return
-	}
-	if modules[0] != nil {
-		panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0]))
-		return
-	}
+	// Add dependencies on all the fragments.
+	b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
 }
 
 func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList) {
@@ -265,7 +156,7 @@
 		tag := ctx.OtherModuleDependencyTag(module)
 		if tag == platformBootclasspathModuleDepTag {
 			b.configuredModules = append(b.configuredModules, module)
-		} else if tag == platformBootclasspathFragmentDepTag {
+		} else if tag == bootclasspathFragmentDepTag {
 			b.fragments = append(b.fragments, module)
 		}
 	})
diff --git a/java/testing.go b/java/testing.go
index 08a71b8..649d27b 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -232,7 +232,8 @@
 	RegisterAppBuildComponents(ctx)
 	RegisterAppImportBuildComponents(ctx)
 	RegisterAppSetBuildComponents(ctx)
-	RegisterBootImageBuildComponents(ctx)
+	registerBootclasspathBuildComponents(ctx)
+	registerBootclasspathFragmentBuildComponents(ctx)
 	RegisterDexpreoptBootJarsComponents(ctx)
 	RegisterDocsBuildComponents(ctx)
 	RegisterGenRuleBuildComponents(ctx)
diff --git a/rust/bindgen.go b/rust/bindgen.go
index ba0ab93..f9e6cd0 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -144,6 +144,7 @@
 
 	// Toolchain clang flags
 	cflags = append(cflags, "-target "+ccToolchain.ClangTriple())
+	cflags = append(cflags, strings.ReplaceAll(ccToolchain.ClangCflags(), "${config.", "${cc_config."))
 	cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${cc_config."))
 
 	// Dependency clang flags and include paths
diff --git a/rust/image.go b/rust/image.go
index 900842e..7eb49d9 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -97,10 +97,6 @@
 	return mod.InRamdisk()
 }
 
-func (mod *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
 func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool {
 	return mod.InRecovery()
 }
diff --git a/scripts/lint_project_xml.py b/scripts/lint_project_xml.py
index 74aebc1..3b0158d 100755
--- a/scripts/lint_project_xml.py
+++ b/scripts/lint_project_xml.py
@@ -144,12 +144,12 @@
   if issues_element.tagName != 'issues':
     raise RuntimeError('expected issues tag at root')
   issues = issues_element.getElementsByTagName('issue')
-  disallwed = set()
+  disallowed = set()
   for issue in issues:
     id = issue.getAttribute('id')
     if id in forced_checks:
-      disallwed.add(id)
-  return disallwed
+      disallowed.add(id)
+  return disallowed
 
 
 def main():
@@ -158,10 +158,10 @@
 
   if args.baseline_path:
     baseline = minidom.parse(args.baseline_path)
-    diallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
-    if bool(diallowed_issues):
+    disallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
+    if bool(disallowed_issues):
       raise RuntimeError('disallowed issues %s found in lint baseline file %s for module %s'
-                         % (diallowed_issues, args.baseline_path, args.name))
+                         % (disallowed_issues, args.baseline_path, args.name))
 
   if args.project_out:
     with open(args.project_out, 'w') as f:
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 0ce4351..ef4d7cd 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -24,6 +24,7 @@
 func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
 		prepareForSdkTestWithApex,
 
 		// Some additional files needed for the art apex.
@@ -32,6 +33,20 @@
 			"com.android.art.pem":                                nil,
 			"system/sepolicy/apex/com.android.art-file_contexts": nil,
 		}),
+
+		// platform_bootclasspath that depends on the fragment.
+		android.FixtureAddTextFile("frameworks/base/boot/Android.bp", `
+			platform_bootclasspath {
+				name: "platform-bootclasspath",
+				fragments: [
+					{
+						apex: "com.android.art",
+						module: "mybootclasspathfragment",
+					},
+				],
+			}
+		`),
+
 		java.FixtureConfigureBootJars("com.android.art:mybootlib"),
 		android.FixtureWithRootAndroidBp(`
 			sdk {
@@ -72,6 +87,23 @@
 		`),
 	).RunTest(t)
 
+	// A preparer to add a prebuilt apex to the test fixture.
+	prepareWithPrebuiltApex := android.GroupFixturePreparers(
+		android.FixtureAddTextFile("prebuilts/apex/Android.bp", `
+				prebuilt_apex {
+					name: "com.android.art",
+					src: "art.apex",
+					exported_java_libs: [
+						"mybootlib",
+					],
+					exported_bootclasspath_fragments: [
+						"mybootclasspathfragment",
+					],
+				}
+			`),
+		android.FixtureAddFile("prebuilts/apex/art.apex", nil),
+	)
+
 	CheckSnapshot(t, result, "mysdk", "",
 		checkUnversionedAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
@@ -121,19 +153,9 @@
 		checkAllCopyRules(`
 .intermediates/mybootlib/android_common/javac/mybootlib.jar -> java/mybootlib.jar
 `),
-		snapshotTestPreparer(checkSnapshotPreferredWithSource, android.GroupFixturePreparers(
-			android.FixtureAddTextFile("prebuilts/apex/Android.bp", `
-				prebuilt_apex {
-					name: "com.android.art",
-					src: "art.apex",
-					exported_java_libs: [
-						"mybootlib",
-					],
-				}
-			`),
-			android.FixtureAddFile("prebuilts/apex/art.apex", nil),
-		),
-		),
+		snapshotTestPreparer(checkSnapshotWithoutSource, prepareWithPrebuiltApex),
+		snapshotTestPreparer(checkSnapshotWithSourcePreferred, prepareWithPrebuiltApex),
+		snapshotTestPreparer(checkSnapshotPreferredWithSource, prepareWithPrebuiltApex),
 	)
 }
 
diff --git a/sdk/testing.go b/sdk/testing.go
index bf59aed..f4e85c0 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -254,6 +254,7 @@
 	snapshotPreparer := android.GroupFixturePreparers(sourcePreparers, fs.AddToFixture())
 
 	var runSnapshotTestWithCheckers = func(t *testing.T, testConfig snapshotTest, extraPreparer android.FixturePreparer) {
+		t.Helper()
 		customization := snapshotBuildInfo.snapshotTestCustomization(testConfig)
 		customizedPreparers := android.GroupFixturePreparers(customization.preparers...)
 
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 42d5680..6623381 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -210,10 +210,6 @@
 	return proptools.Bool(s.properties.Vendor_ramdisk_available) || s.ModuleBase.InstallInVendorRamdisk()
 }
 
-func (s *ShBinary) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
 func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery()
 }