Merge changes from topic "go_bp2build" into main

* changes:
  Respect package boundaries in bp2build conversion of go modules
  Create a temporary denylist for go binaries used in mixed builds
  Partial bp2build conversion of blueprint_go_binary
  Partial bp2build conversion of bootstratp_go_package
diff --git a/android/configured_jars.go b/android/configured_jars.go
index 53fef05..1281bae 100644
--- a/android/configured_jars.go
+++ b/android/configured_jars.go
@@ -311,4 +311,9 @@
 	return ConfiguredJarList{}
 }
 
+// IsConfiguredJarForPlatform returns true if the given apex name is a special name for the platform.
+func IsConfiguredJarForPlatform(apex string) bool {
+	return apex == "platform" || apex == "system_ext"
+}
+
 var earlyBootJarsKey = NewOnceKey("earlyBootJars")
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b67535a..f7a4dea 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5587,6 +5587,7 @@
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
 			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
 
@@ -5664,6 +5665,7 @@
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
 			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 
 		myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module()
@@ -5758,6 +5760,28 @@
 
 	t.Run("prebuilt library preferred with source", func(t *testing.T) {
 		bp := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: false,
+			bootclasspath_fragments: ["my-bootclasspath-fragment"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			contents: ["libfoo", "libbar"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -5773,6 +5797,7 @@
 
 		prebuilt_bootclasspath_fragment {
 			name: "my-bootclasspath-fragment",
+			prefer: true,
 			contents: ["libfoo", "libbar"],
 			apex_available: ["myapex"],
 			hidden_api: {
@@ -5797,6 +5822,7 @@
 			name: "libfoo",
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
+			installable: true,
 		}
 
 		java_sdk_library_import {
@@ -5815,6 +5841,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			unsafe_ignore_missing_latest_api: true,
 			apex_available: ["myapex"],
+			compile_dex: true,
 		}
 	`
 
@@ -5827,6 +5854,7 @@
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
 			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
 
@@ -5835,8 +5863,8 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
-			java_libs: ["libfoo", "libbar"],
 			updatable: false,
+			bootclasspath_fragments: ["my-bootclasspath-fragment"],
 		}
 
 		apex_key {
@@ -5845,6 +5873,15 @@
 			private_key: "testkey.pem",
 		}
 
+		bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			contents: ["libfoo", "libbar"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -5883,6 +5920,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
+			installable: true,
 		}
 
 		java_sdk_library_import {
@@ -5900,6 +5938,7 @@
 			unsafe_ignore_missing_latest_api: true,
 			apex_available: ["myapex"],
 			permitted_packages: ["bar"],
+			compile_dex: true,
 		}
 	`
 
@@ -5910,8 +5949,9 @@
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
-			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/modular-hiddenapi/index.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
 
@@ -5921,7 +5961,7 @@
 			name: "myapex",
 			enabled: false,
 			key: "myapex.key",
-			java_libs: ["libfoo", "libbar"],
+			bootclasspath_fragments: ["my-bootclasspath-fragment"],
 		}
 
 		apex_key {
@@ -5930,6 +5970,16 @@
 			private_key: "testkey.pem",
 		}
 
+		bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			enabled: false,
+			contents: ["libfoo", "libbar"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -5959,7 +6009,6 @@
 
 		java_import {
 			name: "libfoo",
-			prefer: true,
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
@@ -5967,13 +6016,14 @@
 
 		java_library {
 			name: "libfoo",
+			enabled: false,
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
+			installable: true,
 		}
 
 		java_sdk_library_import {
 			name: "libbar",
-			prefer: true,
 			public: {
 				jars: ["libbar.jar"],
 			},
@@ -5984,9 +6034,11 @@
 
 		java_sdk_library {
 			name: "libbar",
+			enabled: false,
 			srcs: ["foo/bar/MyClass.java"],
 			unsafe_ignore_missing_latest_api: true,
 			apex_available: ["myapex"],
+			compile_dex: true,
 		}
 	`
 
@@ -5999,6 +6051,7 @@
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
 			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
 }
@@ -8163,126 +8216,6 @@
 	android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings())
 }
 
-func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) {
-	t.Helper()
-
-	bp := `
-		java_library {
-			name: "some-updatable-apex-lib",
-			srcs: ["a.java"],
-			sdk_version: "current",
-			apex_available: [
-				"some-updatable-apex",
-			],
-			permitted_packages: ["some.updatable.apex.lib"],
-			min_sdk_version: "33",
-		}
-
-		java_library {
-			name: "some-non-updatable-apex-lib",
-			srcs: ["a.java"],
-			apex_available: [
-				"some-non-updatable-apex",
-			],
-			compile_dex: true,
-			permitted_packages: ["some.non.updatable.apex.lib"],
-		}
-
-		bootclasspath_fragment {
-			name: "some-non-updatable-fragment",
-			contents: ["some-non-updatable-apex-lib"],
-			apex_available: [
-				"some-non-updatable-apex",
-			],
-			hidden_api: {
-				split_packages: ["*"],
-			},
-		}
-
-		java_library {
-			name: "some-platform-lib",
-			srcs: ["a.java"],
-			sdk_version: "current",
-			installable: true,
-		}
-
-		java_library {
-			name: "some-art-lib",
-			srcs: ["a.java"],
-			sdk_version: "current",
-			apex_available: [
-				"com.android.art.debug",
-			],
-			hostdex: true,
-			compile_dex: true,
-			min_sdk_version: "33",
-		}
-
-		apex {
-			name: "some-updatable-apex",
-			key: "some-updatable-apex.key",
-			java_libs: ["some-updatable-apex-lib"],
-			updatable: true,
-			min_sdk_version: "33",
-		}
-
-		apex {
-			name: "some-non-updatable-apex",
-			key: "some-non-updatable-apex.key",
-			bootclasspath_fragments: ["some-non-updatable-fragment"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "some-updatable-apex.key",
-		}
-
-		apex_key {
-			name: "some-non-updatable-apex.key",
-		}
-
-		apex {
-			name: "com.android.art.debug",
-			key: "com.android.art.debug.key",
-			bootclasspath_fragments: ["art-bootclasspath-fragment"],
-			updatable: true,
-			min_sdk_version: "33",
-		}
-
-		bootclasspath_fragment {
-			name: "art-bootclasspath-fragment",
-			image_name: "art",
-			contents: ["some-art-lib"],
-			apex_available: [
-				"com.android.art.debug",
-			],
-			hidden_api: {
-				split_packages: ["*"],
-			},
-		}
-
-		apex_key {
-			name: "com.android.art.debug.key",
-		}
-
-		filegroup {
-			name: "some-updatable-apex-file_contexts",
-			srcs: [
-				"system/sepolicy/apex/some-updatable-apex-file_contexts",
-			],
-		}
-
-		filegroup {
-			name: "some-non-updatable-apex-file_contexts",
-			srcs: [
-				"system/sepolicy/apex/some-non-updatable-apex-file_contexts",
-			],
-		}
-	`
-
-	testDexpreoptWithApexes(t, bp, errmsg, preparer, fragments...)
-}
-
 func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) *android.TestContext {
 	t.Helper()
 
@@ -8306,7 +8239,7 @@
 	result := android.GroupFixturePreparers(
 		cc.PrepareForTestWithCcDefaultModules,
 		java.PrepareForTestWithHiddenApiBuildComponents,
-		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithDexpreopt,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		PrepareForTestWithApexBuildComponents,
 		preparer,
@@ -8321,12 +8254,16 @@
 					platform_bootclasspath {
 						name: "platform-bootclasspath",
 						fragments: [
+							{apex: "com.android.art", module: "art-bootclasspath-fragment"},
   						%s
 						],
 					}
 				`, insert))
 			}
 		}),
+		// Dexpreopt for boot jars requires the ART boot image profile.
+		java.PrepareApexBootJarModule("com.android.art", "core-oj"),
+		dexpreopt.FixtureSetArtBootJars("com.android.art:core-oj"),
 		dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"),
 	).
 		ExtendWithErrorHandler(errorHandler).
@@ -8633,126 +8570,6 @@
 	)
 }
 
-func TestNoUpdatableJarsInBootImage(t *testing.T) {
-	// Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can
-	// result in an invalid configuration as it does not set the ArtApexJars and allows art apex
-	// modules to be included in the BootJars.
-	prepareSetBootJars := func(bootJars ...string) android.FixturePreparer {
-		return android.GroupFixturePreparers(
-			dexpreopt.FixtureSetBootJars(bootJars...),
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
-			}),
-		)
-	}
-
-	// Set the ArtApexJars and BootJars in dexpreopt.GlobalConfig and productVariables all to the
-	// same value. This can result in an invalid configuration as it allows non art apex jars to be
-	// specified in the ArtApexJars configuration.
-	prepareSetArtJars := func(bootJars ...string) android.FixturePreparer {
-		return android.GroupFixturePreparers(
-			dexpreopt.FixtureSetArtBootJars(bootJars...),
-			dexpreopt.FixtureSetBootJars(bootJars...),
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
-			}),
-		)
-	}
-
-	t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
-		preparer := android.GroupFixturePreparers(
-			java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		fragments := []java.ApexVariantReference{
-			{
-				Apex:   proptools.StringPtr("com.android.art.debug"),
-				Module: proptools.StringPtr("art-bootclasspath-fragment"),
-			},
-			{
-				Apex:   proptools.StringPtr("some-non-updatable-apex"),
-				Module: proptools.StringPtr("some-non-updatable-fragment"),
-			},
-		}
-		testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
-	})
-
-	t.Run("updatable jar from ART apex in the platform bootclasspath => error", func(t *testing.T) {
-		err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the platform bootclasspath`
-		// Update the dexpreopt BootJars directly.
-		preparer := android.GroupFixturePreparers(
-			prepareSetBootJars("com.android.art.debug:some-art-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
-		err := `ArtApexJars expects this to be in apex "some-updatable-apex" but this is only in apexes.*"com.android.art.debug"`
-		// Update the dexpreopt ArtApexJars directly.
-		preparer := prepareSetArtJars("some-updatable-apex:some-updatable-apex-lib")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
-		err := `ArtApexJars expects this to be in apex "some-non-updatable-apex" but this is only in apexes.*"com.android.art.debug"`
-		// Update the dexpreopt ArtApexJars directly.
-		preparer := prepareSetArtJars("some-non-updatable-apex:some-non-updatable-apex-lib")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("updatable jar from some other apex in the platform bootclasspath => error", func(t *testing.T) {
-		err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the platform bootclasspath`
-		preparer := android.GroupFixturePreparers(
-			java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("non-updatable jar from some other apex in the platform bootclasspath => ok", func(t *testing.T) {
-		preparer := java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
-		fragment := java.ApexVariantReference{
-			Apex:   proptools.StringPtr("some-non-updatable-apex"),
-			Module: proptools.StringPtr("some-non-updatable-fragment"),
-		}
-		testNoUpdatableJarsInBootImage(t, "", preparer, fragment)
-	})
-
-	t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
-		err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
-		preparer := java.FixtureConfigureBootJars("platform:nonexistent")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("nonexistent jar in the platform bootclasspath => error", func(t *testing.T) {
-		err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
-		preparer := java.FixtureConfigureBootJars("platform:nonexistent")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
-		err := `ArtApexJars is invalid as it requests a platform variant of "some-platform-lib"`
-		// Update the dexpreopt ArtApexJars directly.
-		preparer := prepareSetArtJars("platform:some-platform-lib")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("platform jar in the platform bootclasspath => ok", func(t *testing.T) {
-		preparer := android.GroupFixturePreparers(
-			java.FixtureConfigureBootJars("platform:some-platform-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		fragments := []java.ApexVariantReference{
-			{
-				Apex:   proptools.StringPtr("some-non-updatable-apex"),
-				Module: proptools.StringPtr("some-non-updatable-fragment"),
-			},
-		}
-		testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
-	})
-}
-
 func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
 	preparer := java.FixtureConfigureApexBootJars("myapex:libfoo")
 	t.Run("prebuilt no source", func(t *testing.T) {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 1b52886..7be8477 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -46,78 +46,6 @@
 	dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"),
 )
 
-func TestBootclasspathFragments(t *testing.T) {
-	result := android.GroupFixturePreparers(
-		prepareForTestWithBootclasspathFragment,
-		// 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,
-
-		java.PrepareForTestWithJavaSdkLibraryFiles,
-		java.FixtureWithLastReleaseApis("foo"),
-	).RunTestWithBp(t, `
-		java_sdk_library {
-			name: "foo",
-			srcs: ["b.java"],
-		}
-
-		java_library {
-			name: "bar",
-			srcs: ["b.java"],
-			installable: true,
-		}
-
-		apex {
-			name: "com.android.art",
-			key: "com.android.art.key",
-			bootclasspath_fragments: ["art-bootclasspath-fragment"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "com.android.art.key",
-			public_key: "com.android.art.avbpubkey",
-			private_key: "com.android.art.pem",
-		}
-
-		java_library {
-			name: "baz",
-			apex_available: [
-				"com.android.art",
-			],
-			srcs: ["b.java"],
-			compile_dex: true,
-		}
-
-		java_library {
-			name: "quuz",
-			apex_available: [
-				"com.android.art",
-			],
-			srcs: ["b.java"],
-			compile_dex: true,
-		}
-
-		bootclasspath_fragment {
-			name: "art-bootclasspath-fragment",
-			image_name: "art",
-			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
-			contents: ["baz", "quuz"],
-			apex_available: [
-				"com.android.art",
-			],
-			hidden_api: {
-				split_packages: ["*"],
-			},
-		}
-`,
-	)
-
-	// Make sure that the art-bootclasspath-fragment is using the correct configuration.
-	checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000",
-		"com.android.art:baz,com.android.art:quuz")
-}
-
 func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
@@ -248,16 +176,6 @@
 	checkAPIScopeStubs("other", otherInfo, java.CorePlatformHiddenAPIScope)
 }
 
-func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string) {
-	t.Helper()
-
-	bootclasspathFragment := result.ModuleForTests(moduleName, variantName).Module().(*java.BootclasspathFragmentModule)
-
-	bootclasspathFragmentInfo := result.ModuleProvider(bootclasspathFragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
-	modules := bootclasspathFragmentInfo.Modules()
-	android.AssertStringEquals(t, "invalid modules for "+moduleName, expectedConfiguredModules, modules.String())
-}
-
 func TestBootclasspathFragmentInArtApex(t *testing.T) {
 	commonPreparer := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
@@ -268,10 +186,10 @@
 			name: "com.android.art",
 			key: "com.android.art.key",
 			bootclasspath_fragments: [
-				"mybootclasspathfragment",
+				"art-bootclasspath-fragment",
 			],
 			// bar (like foo) should be transitively included in this apex because it is part of the
-			// mybootclasspathfragment bootclasspath_fragment.
+			// art-bootclasspath-fragment bootclasspath_fragment.
 			updatable: false,
 		}
 
@@ -280,42 +198,6 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-
-		java_library {
-			name: "foo",
-			srcs: ["b.java"],
-			installable: true,
-			apex_available: [
-				"com.android.art",
-			],
-		}
-
-		java_library {
-			name: "bar",
-			srcs: ["b.java"],
-			installable: true,
-			apex_available: [
-				"com.android.art",
-			],
-		}
-
-		java_import {
-			name: "foo",
-			jars: ["foo.jar"],
-			apex_available: [
-				"com.android.art",
-			],
-			compile_dex: true,
-		}
-
-		java_import {
-			name: "bar",
-			jars: ["bar.jar"],
-			apex_available: [
-				"com.android.art",
-			],
-			compile_dex: true,
-		}
 	`),
 	)
 
@@ -330,7 +212,7 @@
 	addSource := func(contents ...string) android.FixturePreparer {
 		text := fmt.Sprintf(`
 			bootclasspath_fragment {
-				name: "mybootclasspathfragment",
+				name: "art-bootclasspath-fragment",
 				image_name: "art",
 				%s
 				apex_available: [
@@ -342,6 +224,19 @@
 			}
 		`, contentsInsert(contents))
 
+		for _, content := range contents {
+			text += fmt.Sprintf(`
+				java_library {
+					name: "%[1]s",
+					srcs: ["%[1]s.java"],
+					installable: true,
+					apex_available: [
+						"com.android.art",
+					],
+				}
+			`, content)
+		}
+
 		return android.FixtureAddTextFile("art/build/boot/Android.bp", text)
 	}
 
@@ -357,11 +252,11 @@
 						src: "com.android.art-arm.apex",
 					},
 				},
-				exported_bootclasspath_fragments: ["mybootclasspathfragment"],
+				exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 			}
 
 			prebuilt_bootclasspath_fragment {
-				name: "mybootclasspathfragment",
+				name: "art-bootclasspath-fragment",
 				image_name: "art",
 				%s
 				prefer: %t,
@@ -369,14 +264,29 @@
 					"com.android.art",
 				],
 				hidden_api: {
-					annotation_flags: "mybootclasspathfragment/annotation-flags.csv",
-					metadata: "mybootclasspathfragment/metadata.csv",
-					index: "mybootclasspathfragment/index.csv",
-					stub_flags: "mybootclasspathfragment/stub-flags.csv",
-					all_flags: "mybootclasspathfragment/all-flags.csv",
+					annotation_flags: "hiddenapi/annotation-flags.csv",
+					metadata: "hiddenapi/metadata.csv",
+					index: "hiddenapi/index.csv",
+					stub_flags: "hiddenapi/stub-flags.csv",
+					all_flags: "hiddenapi/all-flags.csv",
 				},
 			}
 		`, contentsInsert(contents), prefer)
+
+		for _, content := range contents {
+			text += fmt.Sprintf(`
+				java_import {
+					name: "%[1]s",
+					prefer: %[2]t,
+					jars: ["%[1]s.jar"],
+					apex_available: [
+						"com.android.art",
+					],
+					compile_dex: true,
+				}
+			`, content, prefer)
+		}
+
 		return android.FixtureAddTextFile("prebuilts/module_sdk/art/Android.bp", text)
 	}
 
@@ -399,13 +309,13 @@
 		})
 
 		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+			`art-bootclasspath-fragment`,
 			`com.android.art.key`,
-			`mybootclasspathfragment`,
 		})
 
 		// Make sure that the source bootclasspath_fragment copies its dex files to the predefined
 		// locations for the art image.
-		module := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
+		module := result.ModuleForTests("art-bootclasspath-fragment", "android_common_apex10000")
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
 
@@ -469,14 +379,14 @@
 		})
 
 		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+			`art-bootclasspath-fragment`,
 			`com.android.art.key`,
-			`mybootclasspathfragment`,
 			`prebuilt_com.android.art`,
 		})
 
 		// Make sure that the prebuilt bootclasspath_fragment copies its dex files to the predefined
 		// locations for the art image.
-		module := result.ModuleForTests("prebuilt_mybootclasspathfragment", "android_common_com.android.art")
+		module := result.ModuleForTests("prebuilt_art-bootclasspath-fragment", "android_common_com.android.art")
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
 
@@ -566,7 +476,7 @@
 					src: "com.android.art-arm.apex",
 				},
 			},
-			exported_bootclasspath_fragments: ["mybootclasspathfragment"],
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 		}
 
 		java_import {
@@ -586,7 +496,7 @@
 		}
 
 		prebuilt_bootclasspath_fragment {
-			name: "mybootclasspathfragment",
+			name: "art-bootclasspath-fragment",
 			image_name: "art",
 			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
 			contents: ["foo", "bar"],
@@ -594,11 +504,11 @@
 				"com.android.art",
 			],
 			hidden_api: {
-				annotation_flags: "mybootclasspathfragment/annotation-flags.csv",
-				metadata: "mybootclasspathfragment/metadata.csv",
-				index: "mybootclasspathfragment/index.csv",
-				stub_flags: "mybootclasspathfragment/stub-flags.csv",
-				all_flags: "mybootclasspathfragment/all-flags.csv",
+				annotation_flags: "hiddenapi/annotation-flags.csv",
+				metadata: "hiddenapi/metadata.csv",
+				index: "hiddenapi/index.csv",
+				stub_flags: "hiddenapi/stub-flags.csv",
+				all_flags: "hiddenapi/all-flags.csv",
 			},
 		}
 
@@ -608,7 +518,7 @@
 			apex_name: "com.android.art",
 			%s
 			src: "com.mycompany.android.art.apex",
-			exported_bootclasspath_fragments: ["mybootclasspathfragment"],
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 		}
 	`
 
@@ -617,17 +527,17 @@
 
 		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			`com.android.art.apex.selector`,
-			`prebuilt_mybootclasspathfragment`,
+			`prebuilt_art-bootclasspath-fragment`,
 		})
 
-		java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{
+		java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{
 			`com.android.art.deapexer`,
 			`dex2oatd`,
 			`prebuilt_bar`,
 			`prebuilt_foo`,
 		})
 
-		module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art")
+		module := result.ModuleForTests("art-bootclasspath-fragment", "android_common_com.android.art")
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
 
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index bba8bb6..ff8f912 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -155,15 +155,15 @@
 }
 
 func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) {
-	ruleFile := "boot.art"
+	ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
 
 	expectedInputs := []string{
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar",
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar",
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
-		"out/soong/dexpreopt_arm64/dex_artjars/boot.prof",
-		"out/soong/dexpreopt_arm64/dex_bootjars/boot.prof",
+		"out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art/boot.prof",
+		"out/soong/.intermediates/platform-bootclasspath/android_common/boot/boot.prof",
 	}
 
 	expectedOutputs := []string{
@@ -192,7 +192,7 @@
 // The only difference is that the ART profile should be deapexed from the prebuilt APEX. Other
 // inputs and outputs should be the same as above.
 func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) {
-	ruleFile := "boot.art"
+	ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
 
 	expectedInputs := []string{
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar",
@@ -200,7 +200,7 @@
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
 		"out/soong/.intermediates/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
-		"out/soong/dexpreopt_arm64/dex_bootjars/boot.prof",
+		"out/soong/.intermediates/platform-bootclasspath/android_common/boot/boot.prof",
 	}
 
 	expectedOutputs := []string{
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index 7f7aa6a..d1b4d40 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -349,7 +349,7 @@
 		}})
 }
 
-func TestAndroidAppMinSdkProvided(t *testing.T) {
+func TestAndroidAppManifestSdkVersionsProvided(t *testing.T) {
 	runAndroidAppTestCase(t, Bp2buildTestCase{
 		Description:                "Android app with value for min_sdk_version",
 		ModuleTypeUnderTest:        "android_app",
@@ -359,7 +359,9 @@
 android_app {
         name: "foo",
         sdk_version: "current",
-				min_sdk_version: "24",
+        min_sdk_version: "24",
+        max_sdk_version: "30",
+        target_sdk_version: "29",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -367,14 +369,16 @@
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `[]`,
 				"manifest_values": `{
+        "maxSdkVersion": "30",
         "minSdkVersion": "24",
+        "targetSdkVersion": "29",
     }`,
 				"sdk_version": `"current"`,
 			}),
 		}})
 }
 
-func TestAndroidAppMinSdkDefaultToSdkVersion(t *testing.T) {
+func TestAndroidAppMinAndTargetSdkDefaultToSdkVersion(t *testing.T) {
 	runAndroidAppTestCase(t, Bp2buildTestCase{
 		Description:                "Android app with value for sdk_version",
 		ModuleTypeUnderTest:        "android_app",
@@ -392,6 +396,7 @@
 				"resource_files": `[]`,
 				"manifest_values": `{
         "minSdkVersion": "30",
+        "targetSdkVersion": "30",
     }`,
 				"sdk_version": `"30"`,
 			}),
diff --git a/build_kzip.bash b/build_kzip.bash
index b161861..4c42048 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -44,7 +44,7 @@
   # xref_rust
 )
 
-build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k "${kzip_targets[@]}"
+build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k --skip-soong-tests --ninja_weight_source=not_used "${kzip_targets[@]}"
 
 # Build extraction file for Go the files in build/{blueprint,soong} directories.
 declare -r abspath_out=$(realpath "${out}")
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7534db2..fe54463 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4979,6 +4979,7 @@
 
 	conly := []string{"-fPIC", "${config.CommonGlobalConlyflags}"}
 	cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
+	ltoFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
 
 	cflags := []string{"-Werror", "-std=candcpp"}
 	cstd := []string{"-std=gnu17", "-std=conly"}
@@ -5005,17 +5006,17 @@
 		{
 			name:     "c",
 			src:      "foo.c",
-			expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+			expected: combineSlices(baseExpectedFlags, conly, expectedIncludes, cflags, ltoFlags, cstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
 		},
 		{
 			name:     "cc",
 			src:      "foo.cc",
-			expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
+			expected: combineSlices(baseExpectedFlags, cppOnly, expectedIncludes, cflags, ltoFlags, cppstd, lastIncludes, []string{"${config.NoOverrideGlobalCflags}", "${config.NoOverrideExternalGlobalCflags}"}),
 		},
 		{
 			name:     "assemble",
 			src:      "foo.s",
-			expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, lastIncludes),
+			expected: combineSlices(baseExpectedFlags, []string{"${config.CommonGlobalAsflags}"}, expectedIncludes, ltoFlags, lastIncludes),
 		},
 	}
 
diff --git a/cc/config/global.go b/cc/config/global.go
index 013b659..266d278 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -48,7 +48,6 @@
 		"-Wno-multichar",
 
 		"-O2",
-		"-g",
 		"-fdebug-default-version=5",
 
 		"-fno-strict-aliasing",
@@ -111,6 +110,9 @@
 
 		// Turn off FMA which got enabled by default in clang-r445002 (http://b/218805949)
 		"-ffp-contract=off",
+
+		// Using simple template names reduces the size of debug builds.
+		"-gsimple-template-names",
 	}
 
 	commonGlobalConlyflags = []string{}
@@ -374,6 +376,21 @@
 			flags = append(flags, "-Wno-error=unknown-warning-option")
 		}
 
+		switch ctx.Config().Getenv("CLANG_DEFAULT_DEBUG_LEVEL") {
+		case "debug_level_0":
+			flags = append(flags, "-g0")
+		case "debug_level_1":
+			flags = append(flags, "-g1")
+		case "debug_level_2":
+			flags = append(flags, "-g2")
+		case "debug_level_3":
+			flags = append(flags, "-g3")
+		case "debug_level_g":
+			flags = append(flags, "-g")
+		default:
+			flags = append(flags, "-g")
+		}
+
 		return strings.Join(flags, " ")
 	})
 
diff --git a/cc/lto.go b/cc/lto.go
index 510dd79..ff2bf5a 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -47,6 +47,7 @@
 	} `android:"arch_variant"`
 
 	LtoEnabled bool `blueprint:"mutated"`
+	LtoDefault bool `blueprint:"mutated"`
 
 	// Dep properties indicate that this module needs to be built with LTO
 	// since it is an object dependency of an LTO module.
@@ -66,7 +67,34 @@
 }
 
 func (lto *lto) begin(ctx BaseModuleContext) {
-	lto.Properties.LtoEnabled = lto.LTO(ctx)
+	// First, determine the module indepedent default LTO mode.
+	ltoDefault := GlobalThinLTO(ctx)
+	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
+		ltoDefault = false
+	} else if ctx.Host() {
+		// Performance and binary size are less important for host binaries.
+		ltoDefault = false
+	}
+
+	// Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs
+	// to be created.
+	ltoEnabled := ltoDefault
+	if lto.Never() {
+		ltoEnabled = false
+	} else if lto.ThinLTO() {
+		// Module explicitly requests for LTO.
+		ltoEnabled = true
+	} else if ctx.testBinary() || ctx.testLibrary() {
+		// Do not enable LTO for tests for better debugging.
+		ltoEnabled = false
+	} else if ctx.isVndk() {
+		// FIXME: ThinLTO for VNDK produces different output.
+		// b/169217596
+		ltoEnabled = false
+	}
+
+	lto.Properties.LtoDefault = ltoDefault
+	lto.Properties.LtoEnabled = ltoEnabled
 }
 
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
@@ -118,34 +146,6 @@
 	return flags
 }
 
-// Determine which LTO mode to use for the given module.
-func (lto *lto) LTO(ctx BaseModuleContext) bool {
-	if lto.Never() {
-		return false
-	}
-	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
-		return false
-	}
-	// Module explicitly requests for LTO.
-	if lto.ThinLTO() {
-		return true
-	}
-	// LP32 has many subtle issues and less test coverage.
-	if ctx.Arch().ArchType.Multilib == "lib32" {
-		return false
-	}
-	// Performance and binary size are less important for host binaries and tests.
-	if ctx.Host() || ctx.testBinary() || ctx.testLibrary() {
-		return false
-	}
-	// FIXME: ThinLTO for VNDK produces different output.
-	// b/169217596
-	if ctx.isVndk() {
-		return false
-	}
-	return GlobalThinLTO(ctx)
-}
-
 func (lto *lto) ThinLTO() bool {
 	return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
 }
@@ -155,15 +155,13 @@
 }
 
 func GlobalThinLTO(ctx android.BaseModuleContext) bool {
-	return ctx.Config().IsEnvTrue("GLOBAL_THINLTO")
+	return !ctx.Config().IsEnvFalse("GLOBAL_THINLTO")
 }
 
 // Propagate lto requirements down from binaries
 func ltoDepsMutator(mctx android.TopDownMutatorContext) {
-	defaultLTOMode := GlobalThinLTO(mctx)
-
 	if m, ok := mctx.Module().(*Module); ok {
-		if m.lto == nil || m.lto.Properties.LtoEnabled == defaultLTOMode {
+		if m.lto == nil || m.lto.Properties.LtoEnabled == m.lto.Properties.LtoDefault {
 			return
 		}
 
@@ -238,6 +236,7 @@
 				}
 				variation.Properties.PreventInstall = true
 				variation.Properties.HideFromMake = true
+				variation.lto.Properties.LtoDefault = m.lto.Properties.LtoDefault
 				variation.lto.Properties.LtoDep = false
 				variation.lto.Properties.NoLtoDep = false
 			}
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index 02b1145..c6fa030 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -97,8 +97,6 @@
 		"BlueberryFacadeGeneratedStub_cc",
 		"BlueberryFacadeGeneratedStub_h",
 		"BluetoothGeneratedDumpsysDataSchema_h",
-		"OpenwrtControlServerProto_cc",
-		"OpenwrtControlServerProto_h",
 		"c2hal_test_genc++",
 		"c2hal_test_genc++_headers",
 		"hidl2aidl_test_gen_aidl",
@@ -115,6 +113,9 @@
 		"nos_app_weaver_service_genc++_headers",
 		"nos_app_weaver_service_genc++_mock",
 		"nos_generator_test_service_genc++",
+		"aidl_camera_build_version",
+		"cronet_aml_base_android_runtime_unchecked_jni_headers",
+		"cronet_aml_base_android_runtime_jni_headers",
 	}
 
 	SandboxingDenyPathList = []string{
diff --git a/genrule/genrule.go b/genrule/genrule.go
index b29e2c9..99c9166 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -435,6 +435,7 @@
 		cmd = g.CmdModifier(ctx, cmd)
 	}
 
+	var extraInputs android.Paths
 	// Generate tasks, either from genrule or gensrcs.
 	for i, task := range g.taskGenerator(ctx, cmd, srcFiles) {
 		if len(task.out) == 0 {
@@ -442,7 +443,6 @@
 			return
 		}
 
-		var extraInputs android.Paths
 		// Only handle extra inputs once as these currently are the same across all tasks
 		if i == 0 {
 			for name, values := range task.extraInputs {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 7c17db1..6301bbf 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"os"
 	"regexp"
+	"strconv"
 	"testing"
 
 	"android/soong/android"
@@ -557,10 +558,12 @@
 
 		allowMissingDependencies bool
 
-		err   string
-		cmds  []string
-		deps  []string
-		files []string
+		err    string
+		cmds   []string
+		deps   []string
+		files  []string
+		shards int
+		inputs []string
 	}{
 		{
 			name: "gensrcs",
@@ -627,9 +630,29 @@
 				"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
 				"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
 			},
+			shards: 2,
+			inputs: []string{
+				"baz.txt",
+			},
 		},
 	}
 
+	checkInputs := func(t *testing.T, rule android.TestingBuildParams, inputs []string) {
+		t.Helper()
+		if len(inputs) == 0 {
+			return
+		}
+		inputBaseNames := map[string]bool{}
+		for _, f := range rule.Implicits {
+			inputBaseNames[f.Base()] = true
+		}
+		for _, f := range inputs {
+			if _, ok := inputBaseNames[f]; !ok {
+				t.Errorf("Expected to find input file %q for %q, but did not", f, rule.Description)
+			}
+		}
+	}
+
 	for _, test := range testcases {
 		t.Run(test.name, func(t *testing.T) {
 			bp := "gensrcs {\n"
@@ -647,10 +670,21 @@
 				ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
 				RunTestWithBp(t, testGenruleBp()+bp)
 
+			mod := result.ModuleForTests("gen", "")
 			if expectedErrors != nil {
 				return
 			}
 
+			if test.shards > 0 {
+				for i := 0; i < test.shards; i++ {
+					r := mod.Rule("generator" + strconv.Itoa(i))
+					checkInputs(t, r, test.inputs)
+				}
+			} else {
+				r := mod.Rule("generator")
+				checkInputs(t, r, test.inputs)
+			}
+
 			gen := result.Module("gen", "").(*Module)
 			android.AssertDeepEquals(t, "cmd", test.cmds, gen.rawCommands)
 
diff --git a/java/aar.go b/java/aar.go
index 29e86e6..ed3c652 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -31,10 +31,9 @@
 type AndroidLibraryDependency interface {
 	LibraryDependency
 	ExportPackage() android.Path
-	ExportedRRODirs() []rroDir
-	ExportedStaticPackages() android.Paths
-	ExportedManifests() android.Paths
-	ExportedAssets() android.OptionalPath
+	ResourcesNodeDepSet() *android.DepSet[resourcesNode]
+	RRODirsDepSet() *android.DepSet[rroDir]
+	ManifestsDepSet() *android.DepSet[android.Path]
 	SetRROEnforcedForDependent(enforce bool)
 	IsRROEnforced(ctx android.BaseModuleContext) bool
 }
@@ -94,30 +93,32 @@
 }
 
 type aapt struct {
-	aaptSrcJar              android.Path
-	exportPackage           android.Path
-	manifestPath            android.Path
-	transitiveManifestPaths android.Paths
-	proguardOptionsFile     android.Path
-	rroDirs                 []rroDir
-	rTxt                    android.Path
-	extraAaptPackagesFile   android.Path
-	mergedManifestFile      android.Path
-	noticeFile              android.OptionalPath
-	assetPackage            android.OptionalPath
-	isLibrary               bool
-	defaultManifestVersion  string
-	useEmbeddedNativeLibs   bool
-	useEmbeddedDex          bool
-	usesNonSdkApis          bool
-	hasNoCode               bool
-	LoggingParent           string
-	resourceFiles           android.Paths
+	aaptSrcJar             android.Path
+	exportPackage          android.Path
+	manifestPath           android.Path
+	proguardOptionsFile    android.Path
+	rTxt                   android.Path
+	extraAaptPackagesFile  android.Path
+	mergedManifestFile     android.Path
+	noticeFile             android.OptionalPath
+	assetPackage           android.OptionalPath
+	isLibrary              bool
+	defaultManifestVersion string
+	useEmbeddedNativeLibs  bool
+	useEmbeddedDex         bool
+	usesNonSdkApis         bool
+	hasNoCode              bool
+	LoggingParent          string
+	resourceFiles          android.Paths
 
 	splitNames []string
 	splits     []split
 
 	aaptProperties aaptProperties
+
+	resourcesNodesDepSet *android.DepSet[resourcesNode]
+	rroDirsDepSet        *android.DepSet[rroDir]
+	manifestsDepSet      *android.DepSet[android.Path]
 }
 
 type split struct {
@@ -141,17 +142,16 @@
 func (a *aapt) ExportPackage() android.Path {
 	return a.exportPackage
 }
-
-func (a *aapt) ExportedRRODirs() []rroDir {
-	return a.rroDirs
+func (a *aapt) ResourcesNodeDepSet() *android.DepSet[resourcesNode] {
+	return a.resourcesNodesDepSet
 }
 
-func (a *aapt) ExportedManifests() android.Paths {
-	return a.transitiveManifestPaths
+func (a *aapt) RRODirsDepSet() *android.DepSet[rroDir] {
+	return a.rroDirsDepSet
 }
 
-func (a *aapt) ExportedAssets() android.OptionalPath {
-	return a.assetPackage
+func (a *aapt) ManifestsDepSet() *android.DepSet[android.Path] {
+	return a.manifestsDepSet
 }
 
 func (a *aapt) SetRROEnforcedForDependent(enforce bool) {
@@ -291,7 +291,7 @@
 	classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string,
 	enforceDefaultTargetSdkVersion bool, extraLinkFlags ...string) {
 
-	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags :=
+	staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedDeps, libFlags :=
 		aaptLibs(ctx, sdkContext, classLoaderContexts)
 
 	// Exclude any libraries from the supplied list.
@@ -314,13 +314,20 @@
 		EnforceDefaultTargetSdkVersion: enforceDefaultTargetSdkVersion,
 	})
 
+	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
+
 	// Add additional manifest files to transitive manifests.
 	additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
-	a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...)
-	a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...)
+	transitiveManifestPaths := append(android.Paths{manifestPath}, additionalManifests...)
+	// TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import
+	// modules.  Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies
+	// of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of
+	// android_library_import modules.  If this is fixed, staticManifestsDepSet can be dropped completely in favor of
+	// staticResourcesNodesDepSet.manifests()
+	transitiveManifestPaths = append(transitiveManifestPaths, staticManifestsDepSet.ToList()...)
 
-	if len(a.transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
-		a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary)
+	if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
+		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], transitiveManifestPaths[1:], a.isLibrary)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
 			// will be propagated to the final application and merged there.  The merged manifest for libraries is
@@ -333,9 +340,9 @@
 
 	compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
 
-	rroDirs = append(rroDirs, staticRRODirs...)
 	linkFlags = append(linkFlags, libFlags...)
-	linkDeps = append(linkDeps, libDeps...)
+	linkDeps = append(linkDeps, sharedDeps...)
+	linkDeps = append(linkDeps, staticDeps.resPackages()...)
 	linkFlags = append(linkFlags, extraLinkFlags...)
 	if a.isLibrary {
 		linkFlags = append(linkFlags, "--static-lib")
@@ -363,6 +370,10 @@
 
 	var compiledRes, compiledOverlay android.Paths
 
+	// AAPT2 overlays are in lowest to highest priority order, reverse the topological order
+	// of transitiveStaticLibs.
+	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
+
 	compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
 
 	if len(transitiveStaticLibs) > 0 {
@@ -404,12 +415,18 @@
 		})
 	}
 
+	// No need to specify assets from dependencies to aapt2Link for libraries, all transitive assets will be
+	// provided to the final app aapt2Link step.
+	var transitiveAssets android.Paths
+	if !a.isLibrary {
+		transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets())
+	}
 	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages,
-		linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages)
+		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages)
 
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
-	if android.PrefixInList(linkFlags, "-A ") || len(assetPackages) > 0 {
+	if android.PrefixInList(linkFlags, "-A ") {
 		assets := android.PathForModuleOut(ctx, "assets.zip")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        extractAssetsRule,
@@ -424,17 +441,62 @@
 	a.exportPackage = packageRes
 	a.manifestPath = manifestPath
 	a.proguardOptionsFile = proguardOptionsFile
-	a.rroDirs = rroDirs
 	a.extraAaptPackagesFile = extraPackages
 	a.rTxt = rTxt
 	a.splits = splits
+	a.resourcesNodesDepSet = android.NewDepSetBuilder[resourcesNode](android.TOPOLOGICAL).
+		Direct(resourcesNode{
+			resPackage: a.exportPackage,
+			manifest:   a.manifestPath,
+			assets:     a.assetPackage,
+		}).
+		Transitive(staticResourcesNodesDepSet).Build()
+	a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
+		Direct(rroDirs...).
+		Transitive(staticRRODirsDepSet).Build()
+	a.manifestsDepSet = android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).
+		Direct(a.manifestPath).
+		Transitive(staticManifestsDepSet).Build()
+}
+
+type resourcesNode struct {
+	resPackage android.Path
+	manifest   android.Path
+	assets     android.OptionalPath
+}
+
+type transitiveAarDeps []resourcesNode
+
+func (t transitiveAarDeps) resPackages() android.Paths {
+	var paths android.Paths
+	for _, dep := range t {
+		paths = append(paths, dep.resPackage)
+	}
+	return android.FirstUniquePaths(paths)
+}
+
+func (t transitiveAarDeps) manifests() android.Paths {
+	var paths android.Paths
+	for _, dep := range t {
+		paths = append(paths, dep.manifest)
+	}
+	return android.FirstUniquePaths(paths)
+}
+
+func (t transitiveAarDeps) assets() android.Paths {
+	var paths android.Paths
+	for _, dep := range t {
+		if dep.assets.Valid() {
+			paths = append(paths, dep.assets.Path())
+		}
+	}
+	return paths
 }
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
 func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) (
-	transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) {
-
-	var sharedLibs android.Paths
+	staticResourcesNodes *android.DepSet[resourcesNode], staticRRODirs *android.DepSet[rroDir],
+	staticManifests *android.DepSet[android.Path], sharedLibs android.Paths, flags []string) {
 
 	if classLoaderContexts == nil {
 		// Not all callers need to compute class loader context, those who don't just pass nil.
@@ -447,6 +509,10 @@
 		sharedLibs = append(sharedLibs, sdkDep.jars...)
 	}
 
+	var resourcesNodeDepSets []*android.DepSet[resourcesNode]
+	rroDirsDepSetBuilder := android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL)
+	manifestsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL)
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		depTag := ctx.OtherModuleDependencyTag(module)
 
@@ -469,32 +535,28 @@
 			}
 		case staticLibTag:
 			if exportPackage != nil {
-				transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
-				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
-				transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
-				if aarDep.ExportedAssets().Valid() {
-					assets = append(assets, aarDep.ExportedAssets().Path())
-				}
-
-			outer:
-				for _, d := range aarDep.ExportedRRODirs() {
-					for _, e := range staticRRODirs {
-						if d.path == e.path {
-							continue outer
-						}
-					}
-					staticRRODirs = append(staticRRODirs, d)
-				}
+				resourcesNodeDepSets = append(resourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
+				rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet())
+				manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet())
 			}
 		}
 
 		addCLCFromDep(ctx, module, classLoaderContexts)
 	})
 
-	deps = append(deps, sharedLibs...)
-	deps = append(deps, transitiveStaticLibs...)
+	// AAPT2 overlays are in lowest to highest priority order, the topological order will be reversed later.
+	// Reverse the dependency order now going into the depset so that it comes out in order after the second
+	// reverse later.
+	// NOTE: this is legacy and probably incorrect behavior, for most other cases (e.g. conflicting classes in
+	// dependencies) the highest priority dependency is listed first, but for resources the highest priority
+	// dependency has to be listed last.
+	staticResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
+		android.ReverseSliceInPlace(resourcesNodeDepSets))
 
-	if len(transitiveStaticLibs) > 0 {
+	staticRRODirs = rroDirsDepSetBuilder.Build()
+	staticManifests = manifestsDepSetBuilder.Build()
+
+	if len(staticResourcesNodes.ToList()) > 0 {
 		flags = append(flags, "--auto-add-overlay")
 	}
 
@@ -502,10 +564,7 @@
 		flags = append(flags, "-I "+sharedLib.String())
 	}
 
-	transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
-	transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
-
-	return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags
+	return staticResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags
 }
 
 type AndroidLibrary struct {
@@ -516,8 +575,6 @@
 	androidLibraryProperties androidLibraryProperties
 
 	aarFile android.WritablePath
-
-	exportedStaticPackages android.Paths
 }
 
 var _ android.OutputFileProducer = (*AndroidLibrary)(nil)
@@ -532,10 +589,6 @@
 	}
 }
 
-func (a *AndroidLibrary) ExportedStaticPackages() android.Paths {
-	return a.exportedStaticPackages
-}
-
 var _ AndroidLibraryDependency = (*AndroidLibrary)(nil)
 
 func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -579,19 +632,15 @@
 
 	a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles,
 		android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...)
+
 	ctx.VisitDirectDeps(func(m android.Module) {
 		if ctx.OtherModuleDependencyTag(m) == staticLibTag {
 			if lib, ok := m.(LibraryDependency); ok {
 				a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
 			}
-			if alib, ok := m.(AndroidLibraryDependency); ok {
-				a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportPackage())
-				a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportedStaticPackages()...)
-			}
 		}
 	})
 	a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
-	a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages)
 
 	prebuiltJniPackages := android.Paths{}
 	ctx.VisitDirectDeps(func(module android.Module) {
@@ -681,7 +730,8 @@
 	manifest              android.WritablePath
 	assetsPackage         android.WritablePath
 
-	exportedStaticPackages android.Paths
+	resourcesNodesDepSet *android.DepSet[resourcesNode]
+	manifestsDepSet      *android.DepSet[android.Path]
 
 	hideApexVariantFromMake bool
 
@@ -738,25 +788,20 @@
 func (a *AARImport) ExportPackage() android.Path {
 	return a.exportPackage
 }
-
 func (a *AARImport) ExportedProguardFlagFiles() android.Paths {
 	return android.Paths{a.proguardFlags}
 }
 
-func (a *AARImport) ExportedRRODirs() []rroDir {
-	return nil
+func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[resourcesNode] {
+	return a.resourcesNodesDepSet
 }
 
-func (a *AARImport) ExportedStaticPackages() android.Paths {
-	return a.exportedStaticPackages
+func (a *AARImport) RRODirsDepSet() *android.DepSet[rroDir] {
+	return android.NewDepSet[rroDir](android.TOPOLOGICAL, nil, nil)
 }
 
-func (a *AARImport) ExportedManifests() android.Paths {
-	return android.Paths{a.manifest}
-}
-
-func (a *AARImport) ExportedAssets() android.OptionalPath {
-	return android.OptionalPathForPath(a.assetsPackage)
+func (a *AARImport) ManifestsDepSet() *android.DepSet[android.Path] {
+	return a.manifestsDepSet
 }
 
 // RRO enforcement is not available on aar_import since its RRO dirs are not
@@ -891,32 +936,44 @@
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags :=
+	staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags :=
 		aaptLibs(ctx, android.SdkContext(a), nil)
 
-	_ = staticLibManifests
-	_ = staticRRODirs
+	_ = staticRRODirsDepSet
+	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
 
-	linkDeps = append(linkDeps, libDeps...)
+	// AAPT2 overlays are in lowest to highest priority order, reverse the topological order
+	// of transitiveStaticLibs.
+	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
+
+	linkDeps = append(linkDeps, sharedLibs...)
+	linkDeps = append(linkDeps, transitiveStaticLibs...)
 	linkFlags = append(linkFlags, libFlags...)
 
 	overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
 
+	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
 	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
 		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
 
-	// Merge this import's assets with its dependencies' assets (if there are any).
-	if len(transitiveAssets) > 0 {
-		mergedAssets := android.PathForModuleOut(ctx, "merged-assets.zip")
-		inputZips := append(android.Paths{a.assetsPackage}, transitiveAssets...)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        mergeAssetsRule,
-			Inputs:      inputZips,
-			Output:      mergedAssets,
-			Description: "merge assets from dependencies and self",
-		})
-		a.assetsPackage = mergedAssets
-	}
+	resourcesNodesDepSetBuilder := android.NewDepSetBuilder[resourcesNode](android.TOPOLOGICAL)
+	resourcesNodesDepSetBuilder.Direct(resourcesNode{
+		resPackage: a.exportPackage,
+		manifest:   a.manifest,
+		assets:     android.OptionalPathForPath(a.assetsPackage),
+	})
+	resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet)
+	a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
+
+	manifestDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(a.manifest)
+	// TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import
+	// modules.  Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies
+	// of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of
+	// android_library_import modules.  If this is fixed, AndroidLibraryDependency.ManifestsDepSet can be dropped
+	// completely in favor of AndroidLibraryDependency.ResourceNodesDepSet.manifest
+	//manifestDepSetBuilder.Transitive(transitiveStaticDeps.manifests)
+	_ = staticManifestsDepSet
+	a.manifestsDepSet = manifestDepSetBuilder.Build()
 
 	a.collectTransitiveHeaderJars(ctx)
 	ctx.SetProvider(JavaInfoProvider, JavaInfo{
diff --git a/java/androidmk.go b/java/androidmk.go
index 9c21633..13cc96a 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -368,8 +368,13 @@
 
 				filterRRO := func(filter overlayType) android.Paths {
 					var paths android.Paths
-					for _, d := range app.rroDirs {
+					seen := make(map[android.Path]bool)
+					for _, d := range app.rroDirsDepSet.ToList() {
 						if d.overlayType == filter {
+							if seen[d.path] {
+								continue
+							}
+							seen[d.path] = true
 							paths = append(paths, d.path)
 						}
 					}
diff --git a/java/app.go b/java/app.go
index d9272e4..10010e4 100755
--- a/java/app.go
+++ b/java/app.go
@@ -204,8 +204,8 @@
 	return nil
 }
 
-func (a *AndroidApp) ExportedStaticPackages() android.Paths {
-	return nil
+func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[resourcesNode] {
+	return a.aapt.resourcesNodesDepSet
 }
 
 func (a *AndroidApp) OutputFile() android.Path {
@@ -1571,7 +1571,9 @@
 }
 
 type manifestValueAttribute struct {
-	MinSdkVersion *string
+	MinSdkVersion    *string
+	MaxSdkVersion    *string
+	TargetSdkVersion *string
 }
 
 type bazelAndroidAppAttributes struct {
@@ -1601,12 +1603,25 @@
 	// MinSdkVersion(ctx) calls SdkVersion(ctx) if no value for min_sdk_version is set
 	minSdkVersion := a.MinSdkVersion(ctx)
 	if !minSdkVersion.IsPreview() && !minSdkVersion.IsInvalid() {
-		minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx)
-		if err == nil {
+		if minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx); err == nil {
 			manifestValues.MinSdkVersion = &minSdkStr
 		}
 	}
 
+	maxSdkVersion := a.MaxSdkVersion(ctx)
+	if !maxSdkVersion.IsPreview() && !maxSdkVersion.IsInvalid() {
+		if maxSdkStr, err := maxSdkVersion.EffectiveVersionString(ctx); err == nil {
+			manifestValues.MaxSdkVersion = &maxSdkStr
+		}
+	}
+
+	targetSdkVersion := a.TargetSdkVersion(ctx)
+	if !targetSdkVersion.IsPreview() && !targetSdkVersion.IsInvalid() {
+		if targetSdkStr, err := targetSdkVersion.EffectiveVersionString(ctx); err == nil {
+			manifestValues.TargetSdkVersion = &targetSdkStr
+		}
+	}
+
 	appAttrs := &bazelAndroidAppAttributes{
 		// TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
 		Custom_package:   a.overridableAppProperties.Package_name,
diff --git a/java/app_import.go b/java/app_import.go
index 8427217..e25bcd1 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -335,11 +335,19 @@
 	// Sign or align the package if package has not been preprocessed
 
 	if proptools.Bool(a.properties.Preprocessed) {
-		output := srcApk
+		var output android.WritablePath
 		if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
-			writableOutput := android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
-			a.validatePreprocessedApk(ctx, srcApk, writableOutput)
-			output = writableOutput
+			output = android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
+			a.validatePreprocessedApk(ctx, srcApk, output)
+		} else {
+			// If using the input APK unmodified, still make a copy of it so that the output filename has the
+			// right basename.
+			output = android.PathForModuleOut(ctx, apkFilename)
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   android.Cp,
+				Input:  srcApk,
+				Output: output,
+			})
 		}
 		a.outputFile = output
 		a.certificate = PresignedCertificate
diff --git a/java/app_test.go b/java/app_test.go
index 0f98416..c438b6c 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -599,7 +599,7 @@
 			android_library {
 				name: "lib3",
 				sdk_version: "current",
-				static_libs: ["lib4"],
+				static_libs: ["lib4", "import"],
 			}
 
 			android_library {
@@ -607,6 +607,12 @@
 				sdk_version: "current",
 				asset_dirs: ["assets_b"],
 			}
+
+			android_library_import {
+				name: "import",
+				sdk_version: "current",
+				aars: ["import.aar"],
+			}
 		`
 
 	testCases := []struct {
@@ -616,11 +622,12 @@
 	}{
 		{
 			name: "foo",
-			// lib1 has its own asset. lib3 doesn't have any, but provides lib4's transitively.
+			// lib1 has its own assets. lib3 doesn't have any, but lib4 and import have assets.
 			assetPackages: []string{
 				"out/soong/.intermediates/foo/android_common/aapt2/package-res.apk",
 				"out/soong/.intermediates/lib1/android_common/assets.zip",
-				"out/soong/.intermediates/lib3/android_common/assets.zip",
+				"out/soong/.intermediates/lib4/android_common/assets.zip",
+				"out/soong/.intermediates/import/android_common/assets.zip",
 			},
 		},
 		{
@@ -632,10 +639,6 @@
 		},
 		{
 			name: "lib3",
-			assetPackages: []string{
-				"out/soong/.intermediates/lib3/android_common/aapt2/package-res.apk",
-				"out/soong/.intermediates/lib4/android_common/assets.zip",
-			},
 		},
 		{
 			name:      "lib4",
@@ -717,7 +720,267 @@
 	}
 }
 
-func TestAndroidResources(t *testing.T) {
+func TestAndroidResourceProcessor(t *testing.T) {
+	testCases := []struct {
+		name string
+
+		dontVerifyApp bool
+		appResources  []string
+		appOverlays   []string
+		appImports    []string
+		appSrcJars    []string
+		appClasspath  []string
+		appCombined   []string
+
+		dontVerifyDirect bool
+		directResources  []string
+		directOverlays   []string
+		directImports    []string
+		directSrcJars    []string
+		directClasspath  []string
+		directCombined   []string
+
+		dontVerifyTransitive bool
+		transitiveResources  []string
+		transitiveOverlays   []string
+		transitiveImports    []string
+		transitiveSrcJars    []string
+		transitiveClasspath  []string
+		transitiveCombined   []string
+
+		dontVerifyDirectImport bool
+		directImportResources  []string
+		directImportOverlays   []string
+		directImportImports    []string
+
+		dontVerifyTransitiveImport bool
+		transitiveImportResources  []string
+		transitiveImportOverlays   []string
+		transitiveImportImports    []string
+	}{
+		{
+			name: "legacy",
+
+			appResources: nil,
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
+				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+			},
+
+			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
+			appClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+			appCombined: []string{
+				"out/soong/.intermediates/app/android_common/javac/app.jar",
+				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+
+			directResources: nil,
+			directOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
+			},
+
+			directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
+			directClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+			directCombined: []string{
+				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
+				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+
+			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+			transitiveOverlays:  nil,
+			transitiveImports:   []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			transitiveSrcJars:   []string{"out/soong/.intermediates/transitive/android_common/gen/android/R.srcjar"},
+			transitiveClasspath: []string{"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar"},
+			transitiveCombined:  nil,
+
+			directImportResources: nil,
+			directImportOverlays: []string{
+				"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+			},
+			directImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+
+			transitiveImportResources: nil,
+			transitiveImportOverlays: []string{
+				"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+			},
+			transitiveImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			bp := fmt.Sprintf(`
+				android_app {
+					name: "app",
+					sdk_version: "current",
+					srcs: ["app/app.java"],
+					resource_dirs: ["app/res"],
+					manifest: "app/AndroidManifest.xml",
+					static_libs: ["direct", "direct_import"],
+				}
+
+				android_library {
+					name: "direct",
+					sdk_version: "current",
+					srcs: ["direct/direct.java"],
+					resource_dirs: ["direct/res"],
+					manifest: "direct/AndroidManifest.xml",
+					static_libs: ["transitive", "transitive_import"],
+				}
+
+				android_library {
+					name: "transitive",
+					sdk_version: "current",
+					srcs: ["transitive/transitive.java"],
+					resource_dirs: ["transitive/res"],
+					manifest: "transitive/AndroidManifest.xml",
+				}
+
+				android_library_import {
+					name: "direct_import",
+					sdk_version: "current",
+					aars: ["direct_import.aar"],
+					static_libs: ["direct_import_dep"],
+				}
+
+				android_library_import {
+					name: "direct_import_dep",
+					sdk_version: "current",
+					aars: ["direct_import_dep.aar"],
+				}
+
+				android_library_import {
+					name: "transitive_import",
+					sdk_version: "current",
+					aars: ["transitive_import.aar"],
+					static_libs: ["transitive_import_dep"],
+				}
+
+				android_library_import {
+					name: "transitive_import_dep",
+					sdk_version: "current",
+					aars: ["transitive_import_dep.aar"],
+				}
+			`)
+
+			fs := android.MockFS{
+				"app/res/values/strings.xml":        nil,
+				"direct/res/values/strings.xml":     nil,
+				"transitive/res/values/strings.xml": nil,
+			}
+
+			result := android.GroupFixturePreparers(
+				PrepareForTestWithJavaDefaultModules,
+				PrepareForTestWithOverlayBuildComponents,
+				fs.AddToFixture(),
+			).RunTestWithBp(t, bp)
+
+			type aaptInfo struct {
+				resources, overlays, imports, srcJars, classpath, combined android.Paths
+			}
+
+			getAaptInfo := func(moduleName string) (aaptInfo aaptInfo) {
+				mod := result.ModuleForTests(moduleName, "android_common")
+				resourceListRule := mod.MaybeOutput("aapt2/res.list")
+				overlayListRule := mod.MaybeOutput("aapt2/overlay.list")
+				aaptRule := mod.Rule("aapt2Link")
+				javacRule := mod.MaybeRule("javac")
+				combinedRule := mod.MaybeOutput("combined/" + moduleName + ".jar")
+
+				aaptInfo.resources = resourceListRule.Inputs
+				aaptInfo.overlays = overlayListRule.Inputs
+
+				aaptFlags := strings.Split(aaptRule.Args["flags"], " ")
+				for i, flag := range aaptFlags {
+					if flag == "-I" && i+1 < len(aaptFlags) {
+						aaptInfo.imports = append(aaptInfo.imports, android.PathForTesting(aaptFlags[i+1]))
+					}
+				}
+
+				if len(javacRule.Args["srcJars"]) > 0 {
+					aaptInfo.srcJars = android.PathsForTesting(strings.Split(javacRule.Args["srcJars"], " ")...)
+				}
+
+				if len(javacRule.Args["classpath"]) > 0 {
+					classpathArg := strings.TrimPrefix(javacRule.Args["classpath"], "-classpath ")
+					aaptInfo.classpath = android.PathsForTesting(strings.Split(classpathArg, ":")...)
+				}
+
+				aaptInfo.combined = combinedRule.Inputs
+				return
+			}
+
+			app := getAaptInfo("app")
+			direct := getAaptInfo("direct")
+			transitive := getAaptInfo("transitive")
+			directImport := getAaptInfo("direct_import")
+			transitiveImport := getAaptInfo("transitive_import")
+
+			if !testCase.dontVerifyApp {
+				android.AssertPathsRelativeToTopEquals(t, "app resources", testCase.appResources, app.resources)
+				android.AssertPathsRelativeToTopEquals(t, "app overlays", testCase.appOverlays, app.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "app imports", testCase.appImports, app.imports)
+				android.AssertPathsRelativeToTopEquals(t, "app srcjars", testCase.appSrcJars, app.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "app classpath", testCase.appClasspath, app.classpath)
+				android.AssertPathsRelativeToTopEquals(t, "app combined", testCase.appCombined, app.combined)
+			}
+
+			if !testCase.dontVerifyDirect {
+				android.AssertPathsRelativeToTopEquals(t, "direct resources", testCase.directResources, direct.resources)
+				android.AssertPathsRelativeToTopEquals(t, "direct overlays", testCase.directOverlays, direct.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "direct imports", testCase.directImports, direct.imports)
+				android.AssertPathsRelativeToTopEquals(t, "direct srcjars", testCase.directSrcJars, direct.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "direct classpath", testCase.directClasspath, direct.classpath)
+				android.AssertPathsRelativeToTopEquals(t, "direct combined", testCase.directCombined, direct.combined)
+			}
+
+			if !testCase.dontVerifyTransitive {
+				android.AssertPathsRelativeToTopEquals(t, "transitive resources", testCase.transitiveResources, transitive.resources)
+				android.AssertPathsRelativeToTopEquals(t, "transitive overlays", testCase.transitiveOverlays, transitive.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "transitive imports", testCase.transitiveImports, transitive.imports)
+				android.AssertPathsRelativeToTopEquals(t, "transitive srcjars", testCase.transitiveSrcJars, transitive.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "transitive classpath", testCase.transitiveClasspath, transitive.classpath)
+				android.AssertPathsRelativeToTopEquals(t, "transitive combined", testCase.transitiveCombined, transitive.combined)
+			}
+
+			if !testCase.dontVerifyDirectImport {
+				android.AssertPathsRelativeToTopEquals(t, "direct_import resources", testCase.directImportResources, directImport.resources)
+				android.AssertPathsRelativeToTopEquals(t, "direct_import overlays", testCase.directImportOverlays, directImport.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "direct_import imports", testCase.directImportImports, directImport.imports)
+			}
+
+			if !testCase.dontVerifyTransitiveImport {
+				android.AssertPathsRelativeToTopEquals(t, "transitive_import resources", testCase.transitiveImportResources, transitiveImport.resources)
+				android.AssertPathsRelativeToTopEquals(t, "transitive_import overlays", testCase.transitiveImportOverlays, transitiveImport.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "transitive_import imports", testCase.transitiveImportImports, transitiveImport.imports)
+			}
+		})
+	}
+}
+
+func TestAndroidResourceOverlays(t *testing.T) {
 	testCases := []struct {
 		name                       string
 		enforceRROTargets          []string
@@ -943,7 +1206,7 @@
 					overlayFiles = resourceListToFiles(module, android.PathsRelativeToTop(overlayList.Inputs))
 				}
 
-				for _, d := range module.Module().(AndroidLibraryDependency).ExportedRRODirs() {
+				for _, d := range module.Module().(AndroidLibraryDependency).RRODirsDepSet().ToList() {
 					var prefix string
 					if d.overlayType == device {
 						prefix = "device:"
diff --git a/java/base.go b/java/base.go
index f2ad5c2..cb08ef3 100644
--- a/java/base.go
+++ b/java/base.go
@@ -500,6 +500,8 @@
 	maxSdkVersion android.ApiLevel
 
 	sourceExtensions []string
+
+	annoSrcJars android.Paths
 }
 
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -1255,8 +1257,9 @@
 			// this module, or else we could have duplicated errorprone messages.
 			errorproneFlags := enableErrorproneFlags(flags)
 			errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
+			errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar")
 
-			transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneFlags, nil,
+			transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil,
 				"errorprone", "errorprone")
 
 			extraJarDeps = append(extraJarDeps, errorprone)
@@ -1657,13 +1660,15 @@
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath {
 
 	kzipName := pathtools.ReplaceExtension(jarName, "kzip")
+	annoSrcJar := android.PathForModuleOut(ctx, "javac", "anno.srcjar")
 	if idx >= 0 {
 		kzipName = strings.TrimSuffix(jarName, filepath.Ext(jarName)) + strconv.Itoa(idx) + ".kzip"
+		annoSrcJar = android.PathForModuleOut(ctx, "javac", "anno-"+strconv.Itoa(idx)+".srcjar")
 		jarName += strconv.Itoa(idx)
 	}
 
 	classes := android.PathForModuleOut(ctx, "javac", jarName).OutputPath
-	TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, flags, extraJarDeps)
+	TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps)
 
 	if ctx.Config().EmitXrefRules() {
 		extractionFile := android.PathForModuleOut(ctx, kzipName)
@@ -1671,6 +1676,10 @@
 		j.kytheFiles = append(j.kytheFiles, extractionFile)
 	}
 
+	if len(flags.processorPath) > 0 {
+		j.annoSrcJars = append(j.annoSrcJars, annoSrcJar)
+	}
+
 	return classes
 }
 
@@ -1850,6 +1859,7 @@
 	dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...)
 	dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
 	dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
+	dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...)
 }
 
 func (j *Module) CompilerDeps() []string {
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index f4cef7f..29eed79 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -77,7 +77,7 @@
 // Use gatherApexModulePairDepsWithTag to retrieve the dependencies.
 func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
 	var variations []blueprint.Variation
-	if apex != "platform" && apex != "system_ext" {
+	if !android.IsConfiguredJarForPlatform(apex) {
 		// Pick the correct apex variant.
 		variations = []blueprint.Variation{
 			{Mutator: "apex", Variation: apex},
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 50429b0..ac45ce1 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -389,10 +389,6 @@
 // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
 // apex contents.
 type BootclasspathFragmentApexContentInfo struct {
-	// The configured modules, will be empty if this is from a bootclasspath_fragment that does not
-	// set image_name: "art".
-	modules android.ConfiguredJarList
-
 	// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
 	// hidden API encoded dex jar path.
 	contentModuleDexJarPaths bootDexJarByModule
@@ -405,10 +401,6 @@
 	profileInstallPathInApex string
 }
 
-func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
-	return i.modules
-}
-
 // DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
 //
 // The dex boot jar is one which has had hidden API encoding performed on it.
@@ -597,7 +589,6 @@
 	}
 
 	if imageConfig != nil {
-		info.modules = imageConfig.modules
 		global := dexpreopt.GetGlobalConfig(ctx)
 		if !global.DisableGenerateProfile {
 			info.profilePathOnHost = bootImageFiles.profile
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 2541f14..888caad 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -40,6 +40,12 @@
 				image_name: "unknown",
 				contents: ["foo"],
 			}
+
+			java_library {
+				name: "foo",
+				srcs: ["foo.java"],
+				installable: true,
+			}
 		`)
 }
 
@@ -53,6 +59,11 @@
 				image_name: "unknown",
 				contents: ["foo"],
 			}
+
+			java_import {
+				name: "foo",
+				jars: ["foo.jar"],
+			}
 		`)
 }
 
@@ -72,6 +83,18 @@
 					"apex",
 				],
 			}
+
+			java_library {
+				name: "foo",
+				srcs: ["foo.java"],
+				installable: true,
+			}
+
+			java_library {
+				name: "bar",
+				srcs: ["bar.java"],
+				installable: true,
+			}
 		`)
 }
 
@@ -92,6 +115,18 @@
 					"apex2",
 				],
 			}
+
+			java_library {
+				name: "foo",
+				srcs: ["foo.java"],
+				installable: true,
+			}
+
+			java_library {
+				name: "bar",
+				srcs: ["bar.java"],
+				installable: true,
+			}
 		`)
 }
 
diff --git a/java/builder.go b/java/builder.go
index c4395e9..be4af55 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -42,7 +42,8 @@
 	// TODO(b/143658984): goma can't handle the --system argument to javac.
 	javac, javacRE = pctx.MultiCommandRemoteStaticRules("javac",
 		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" "$out" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
+			Command: `rm -rf "$outDir" "$annoDir" "$annoSrcJar" "$srcJarDir" "$out" && ` +
+				`mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
 				`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
 				`${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
@@ -50,6 +51,7 @@
 				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
 				`-source $javaVersion -target $javaVersion ` +
 				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
+				`$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar -C $annoDir -D $annoDir && ` +
 				`$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
 				`rm -rf "$srcJarDir"`,
 			CommandDeps: []string{
@@ -73,8 +75,15 @@
 				ExecStrategy: "${config.REJavacExecStrategy}",
 				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 			},
+			"$annoSrcJarTemplate": &remoteexec.REParams{
+				Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
+				Inputs:       []string{"${config.SoongZipCmd}", "$annoDir"},
+				OutputFiles:  []string{"$annoSrcJar"},
+				ExecStrategy: "${config.REJavacExecStrategy}",
+				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+			},
 		}, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
-			"outDir", "annoDir", "javaVersion"}, nil)
+			"outDir", "annoDir", "annoSrcJar", "javaVersion"}, nil)
 
 	_ = pctx.VariableFunc("kytheCorpus",
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
@@ -312,7 +321,7 @@
 }
 
 func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int,
-	srcFiles, srcJars android.Paths, flags javaBuilderFlags, deps android.Paths) {
+	srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) {
 
 	// Compile java sources into .class files
 	desc := "javac"
@@ -320,7 +329,7 @@
 		desc += strconv.Itoa(shardIdx)
 	}
 
-	transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, flags, deps, "javac", desc)
+	transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, flags, deps, "javac", desc)
 }
 
 // Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
@@ -494,7 +503,7 @@
 // suffix will be appended to various intermediate files and directories to avoid collisions when
 // this function is called twice in the same module directory.
 func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
-	shardIdx int, srcFiles, srcJars android.Paths,
+	shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath,
 	flags javaBuilderFlags, deps android.Paths,
 	intermediatesDir, desc string) {
 
@@ -541,11 +550,12 @@
 		rule = javacRE
 	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        rule,
-		Description: desc,
-		Output:      outputFile,
-		Inputs:      srcFiles,
-		Implicits:   deps,
+		Rule:           rule,
+		Description:    desc,
+		Output:         outputFile,
+		ImplicitOutput: annoSrcJar,
+		Inputs:         srcFiles,
+		Implicits:      deps,
 		Args: map[string]string{
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
@@ -556,6 +566,7 @@
 			"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(),
 			"outDir":        android.PathForModuleOut(ctx, intermediatesDir, outDir).String(),
 			"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(),
+			"annoSrcJar":    annoSrcJar.String(),
 			"javaVersion":   flags.javaVersion.String(),
 		},
 	})
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 2b0f57e..7b56a19 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -505,8 +505,7 @@
 		// No module has enabled dexpreopting, so we assume there will be no boot image to make.
 		return
 	}
-	archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
-	d.dexpreoptConfigForMake = android.PathForOutput(ctx, toDexpreoptDirName(archType), "dexpreopt.config")
+	d.dexpreoptConfigForMake = android.PathForOutput(ctx, getDexpreoptDirName(ctx), "dexpreopt.config")
 	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
 
 	global := dexpreopt.GetGlobalConfig(ctx)
@@ -885,11 +884,7 @@
 It is likely that the boot classpath is inconsistent.
 Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
 
-func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
-	if !image.isProfileGuided() {
-		return nil
-	}
-
+func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles android.Paths, dexLocations []string) android.WritablePath {
 	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
 	global := dexpreopt.GetGlobalConfig(ctx)
 
@@ -916,28 +911,39 @@
 	if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() {
 		profiles = append(profiles, path.Path())
 	}
-	bootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt")
+	bootImageProfile := android.PathForModuleOut(ctx, name, "boot-image-profile.txt")
 	rule.Command().Text("cat").Inputs(profiles).Text(">").Output(bootImageProfile)
 
-	profile := image.dir.Join(ctx, "boot.prof")
+	profile := android.PathForModuleOut(ctx, name, "boot.prof")
 
 	rule.Command().
 		Text(`ANDROID_LOG_TAGS="*:e"`).
 		Tool(globalSoong.Profman).
 		Flag("--output-profile-type=boot").
 		FlagWithInput("--create-profile-from=", bootImageProfile).
-		FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
-		FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
+		FlagForEachInput("--apk=", dexFiles).
+		FlagForEachArg("--dex-location=", dexLocations).
 		FlagWithOutput("--reference-profile-file=", profile)
 
+	rule.Build("bootJarsProfile_"+name, "profile boot jars "+name)
+
+	return profile
+}
+
+func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
+	if !image.isProfileGuided() {
+		return nil
+	}
+
+	profile := bootImageProfileRuleCommon(ctx, image.name, image.dexPathsDeps.Paths(), image.getAnyAndroidVariant().dexLocationsDeps)
+
 	if image == defaultBootImageConfig(ctx) {
+		rule := android.NewRuleBuilder(pctx, ctx)
 		rule.Install(profile, "/system/etc/boot-image.prof")
 		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
 		image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
 	}
 
-	rule.Build("bootJarsProfile", "profile boot jars")
-
 	return profile
 }
 
@@ -976,6 +982,8 @@
 
 func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) {
 	var allPhonies android.Paths
+	name := image.name
+	global := dexpreopt.GetGlobalConfig(ctx)
 	for _, image := range image.variants {
 		arch := image.target.Arch.ArchType
 		suffix := arch.String()
@@ -984,36 +992,39 @@
 			suffix = "host-" + suffix
 		}
 		// Create a rule to call oatdump.
-		output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
+		output := android.PathForOutput(ctx, name+"."+suffix+".oatdump.txt")
 		rule := android.NewRuleBuilder(pctx, ctx)
 		imageLocationsOnHost, _ := image.imageLocations()
-		rule.Command().
+		cmd := rule.Command().
 			BuiltTool("oatdump").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
 			FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
 			FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
 			FlagWithOutput("--output=", output).
 			FlagWithArg("--instruction-set=", arch.String())
-		rule.Build("dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
+		if global.EnableUffdGc && image.target.Os == android.Android {
+			cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+		}
+		rule.Build("dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String())
 
 		// Create a phony rule that depends on the output file and prints the path.
-		phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix)
+		phony := android.PathForPhony(ctx, "dump-oat-"+name+"-"+suffix)
 		rule = android.NewRuleBuilder(pctx, ctx)
 		rule.Command().
 			Implicit(output).
 			ImplicitOutput(phony).
 			Text("echo").FlagWithArg("Output in ", output.String())
-		rule.Build("phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
+		rule.Build("phony-dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String())
 
 		allPhonies = append(allPhonies, phony)
 	}
 
-	phony := android.PathForPhony(ctx, "dump-oat-boot")
+	phony := android.PathForPhony(ctx, "dump-oat-"+name)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        android.Phony,
 		Output:      phony,
 		Inputs:      allPhonies,
-		Description: "dump-oat-boot",
+		Description: "dump-oat-"+name,
 	})
 }
 
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 28f50d7..abbb96a 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -105,8 +105,7 @@
 func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
 	return ctx.Config().Once(bootImageConfigKey, func() interface{} {
 		targets := dexpreoptTargets(ctx)
-		archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
-		deviceDir := android.PathForOutput(ctx, toDexpreoptDirName(archType))
+		deviceDir := android.PathForOutput(ctx, getDexpreoptDirName(ctx))
 
 		configs := genBootImageConfigRaw(ctx)
 
@@ -218,8 +217,7 @@
 func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
 	return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
 		apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
-		archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
-		dir := android.PathForOutput(ctx, toDexpreoptDirName(archType), "apex_bootjars")
+		dir := android.PathForOutput(ctx, getDexpreoptDirName(ctx), "apex_bootjars")
 		dexPaths := apexBootJars.BuildPaths(ctx, dir)
 		dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
 
@@ -258,6 +256,11 @@
 	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
 }
 
-func toDexpreoptDirName(arch android.ArchType) string {
-	return "dexpreopt_" + arch.String()
+func getDexpreoptDirName(ctx android.PathContext) string {
+	prefix := "dexpreopt_"
+	targets := ctx.Config().Targets[android.Android]
+	if len(targets) > 0 {
+		return prefix+targets[0].Arch.ArchType.String()
+	}
+	return prefix+"unknown_target"
 }
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 6f3aa2b..56f16e0 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -44,18 +44,18 @@
 
 var PrepareApexBootJarConfigsAndModules = android.GroupFixturePreparers(
 	PrepareApexBootJarConfigs,
-	prepareApexBootJarModule("com.android.foo", "framework-foo"),
-	prepareApexBootJarModule("com.android.bar", "framework-bar"),
+	PrepareApexBootJarModule("com.android.foo", "framework-foo"),
+	PrepareApexBootJarModule("com.android.bar", "framework-bar"),
 )
 
 var ApexBootJarFragmentsForPlatformBootclasspath = fmt.Sprintf(`
 	{
 		apex: "%[1]s",
-		module: "%[1]s-bootclasspathfragment",
+		module: "%[1]s-bootclasspath-fragment",
 	},
 	{
 		apex: "%[2]s",
-		module: "%[2]s-bootclasspathfragment",
+		module: "%[2]s-bootclasspath-fragment",
 	},
 `, "com.android.foo", "com.android.bar")
 
@@ -64,15 +64,22 @@
 	"out/soong/.intermediates/packages/modules/com.android.foo/framework-foo/android_common_apex10000/aligned/framework-foo.jar",
 }
 
-func prepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
+func PrepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
 	moduleSourceDir := fmt.Sprintf("packages/modules/%s", apexName)
+	fragmentName := apexName+"-bootclasspath-fragment"
+	imageNameProp := ""
+	if apexName == "com.android.art" {
+		fragmentName = "art-bootclasspath-fragment"
+		imageNameProp = `image_name: "art",`
+	}
+
 	return android.GroupFixturePreparers(
 		android.FixtureAddTextFile(moduleSourceDir+"/Android.bp", fmt.Sprintf(`
 			apex {
 				name: "%[1]s",
 				key: "%[1]s.key",
 				bootclasspath_fragments: [
-					"%[1]s-bootclasspathfragment",
+					"%[3]s",
 				],
 				updatable: false,
 			}
@@ -84,7 +91,8 @@
 			}
 
 			bootclasspath_fragment {
-				name: "%[1]s-bootclasspathfragment",
+				name: "%[3]s",
+				%[4]s
 				contents: ["%[2]s"],
 				apex_available: ["%[1]s"],
 				hidden_api: {
@@ -100,7 +108,7 @@
 				compile_dex: true,
 				apex_available: ["%[1]s"],
 			}
-		`, apexName, moduleName)),
+		`, apexName, moduleName, fragmentName, imageNameProp)),
 		android.FixtureMergeMockFs(android.MockFS{
 			fmt.Sprintf("%s/apex_manifest.json", moduleSourceDir):          nil,
 			fmt.Sprintf("%s/%s.avbpubkey", moduleSourceDir, apexName):      nil,
@@ -192,7 +200,7 @@
 // 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)
+	imageConfig := genBootImageConfigs(pathCtx)["art"]
 	return imageConfig
 }
 
@@ -806,7 +814,7 @@
 		},
 		profileInstalls: []normalizedInstall{
 			{from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"},
-			{from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.prof", to: "/system/etc/boot-image.prof"},
+			{from: "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/boot/boot.prof", to: "/system/etc/boot-image.prof"},
 		},
 		profileLicenseMetadataFile: expectedLicenseMetadataFile,
 	}
@@ -1136,7 +1144,6 @@
 	android.AssertPathRelativeToTopEquals(t, "dir", expected.dir, imageConfig.dir)
 	android.AssertPathRelativeToTopEquals(t, "symbolsDir", expected.symbolsDir, imageConfig.symbolsDir)
 	android.AssertStringEquals(t, "installDir", expected.installDir, imageConfig.installDir)
-	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())
@@ -1238,7 +1245,7 @@
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art
 DEXPREOPT_IMAGE_NAMES=art boot mainline
-DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/dexpreopt_arm64/dex_bootjars/boot.prof:/system/etc/boot-image.prof
+DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/boot/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/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/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/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 151c94a..bb2388f 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -525,8 +525,7 @@
 		cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
 	}
 
-	cmd.Flag("--no-banner").
-		Flag("--color").
+	cmd.Flag("--color").
 		Flag("--quiet").
 		Flag("--format=v2").
 		FlagWithArg("--repeat-errors-max ", "10").
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index c6b921b..f31f5d1 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -1236,7 +1236,6 @@
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
 		BuiltTool("metalava").
-		Flag("--no-banner").
 		Inputs(removedTxtFiles).
 		FlagWithOutput("--dex-api ", output)
 	rule.Build("modular-hiddenapi-removed-dex-signatures"+suffix, "modular hiddenapi removed dex signatures"+suffix)
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index d4ee4fc..714634f 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -166,7 +166,7 @@
 
 	// Now match the apex part of the boot image configuration.
 	requiredApex := configuredBootJars.Apex(index)
-	if requiredApex == "platform" || requiredApex == "system_ext" {
+	if android.IsConfiguredJarForPlatform(requiredApex) {
 		if len(apexInfo.InApexVariants) != 0 {
 			// A platform variant is required but this is for an apex so ignore it.
 			return false
diff --git a/java/java.go b/java/java.go
index 50d48ab..d3762f6 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1716,8 +1716,7 @@
 		FlagWithArg("-encoding ", "UTF-8").
 		FlagWithInputList("--source-files ", srcs, " ")
 
-	cmd.Flag("--no-banner").
-		Flag("--color").
+	cmd.Flag("--color").
 		Flag("--quiet").
 		Flag("--format=v2").
 		Flag("--include-annotations").
@@ -1878,8 +1877,10 @@
 		flags.javacFlags = strings.Join(al.properties.Javacflags, " ")
 		flags.classpath = classpath(classPaths)
 
+		annoSrcJar := android.PathForModuleOut(ctx, ctx.ModuleName(), "anno.srcjar")
+
 		TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{},
-			android.Paths{al.stubsSrcJar}, flags, android.Paths{})
+			android.Paths{al.stubsSrcJar}, annoSrcJar, flags, android.Paths{})
 	}
 
 	builder := android.NewRuleBuilder(pctx, ctx)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index d830968..ac23aab 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -86,27 +86,27 @@
 
 		// Add a platform_bootclasspath that depends on the fragment.
 		fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(
-			"com.android.art", "mybootclasspathfragment", java.ApexBootJarFragmentsForPlatformBootclasspath),
+			"com.android.art", "art-bootclasspath-fragment", java.ApexBootJarFragmentsForPlatformBootclasspath),
 
 		java.PrepareForBootImageConfigTest,
 		java.PrepareApexBootJarConfigsAndModules,
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
-				bootclasspath_fragments: ["mybootclasspathfragment"],
+				bootclasspath_fragments: ["art-bootclasspath-fragment"],
 			}
 
 			apex {
 				name: "com.android.art",
 				key: "com.android.art.key",
 				bootclasspath_fragments: [
-					"mybootclasspathfragment",
+					"art-bootclasspath-fragment",
 				],
 				updatable: false,
 			}
 
 			bootclasspath_fragment {
-				name: "mybootclasspathfragment",
+				name: "art-bootclasspath-fragment",
 				image_name: "art",
 				contents: ["core1", "core2"],
 				apex_available: ["com.android.art"],
@@ -142,10 +142,10 @@
 	).RunTest(t)
 
 	// A preparer to update the test fixture used when processing an unpackage snapshot.
-	preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "mybootclasspathfragment")
+	preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "art-bootclasspath-fragment")
 
 	// Check that source on its own configures the bootImageConfig correctly.
-	java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/meta_lic")
+	java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/art-bootclasspath-fragment/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", "",
@@ -153,7 +153,7 @@
 // This is auto-generated. DO NOT EDIT.
 
 prebuilt_bootclasspath_fragment {
-    name: "mybootclasspathfragment",
+    name: "art-bootclasspath-fragment",
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
@@ -189,12 +189,12 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
-.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/art-bootclasspath-fragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .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
 		`),
@@ -213,7 +213,7 @@
 					java.ApexBootJarDexJarPaths...,
 				)...,
 			)
-			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/mybootclasspathfragment/android_common_com.android.art/meta_lic")
+			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/art-bootclasspath-fragment/android_common_com.android.art/meta_lic")
 			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
 		}),
 
@@ -221,7 +221,7 @@
 
 		// 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.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/meta_lic")
 			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
 		}),
 
@@ -229,7 +229,7 @@
 
 		// 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.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/prebuilt_art-bootclasspath-fragment/android_common_com.android.art/meta_lic")
 			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
 		}),
 	)
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 19987f2..30a1d37 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -223,4 +223,65 @@
   cleanup "${out_dir}"
 }
 
-test_sbom_aosp_cf_x86_64_phone
\ No newline at end of file
+function test_sbom_unbundled_apex {
+  # Setup
+  out_dir="$(setup)"
+
+  # run_soong to build com.android.adbd.apex
+  run_soong "module_arm64" "${out_dir}" "sbom deapexer" "com.android.adbd"
+
+  deapexer=${out_dir}/host/linux-x86/bin/deapexer
+  debugfs=${out_dir}/host/linux-x86/bin/debugfs_static
+  apex_file=${out_dir}/target/product/module_arm64/system/apex/com.android.adbd.apex
+  echo "============ Diffing files in $apex_file and SBOM"
+  set +e
+  # deapexer prints the list of all files and directories
+  # sed extracts the file/directory names
+  # grep removes directories
+  # sed removes leading ./ in file names
+  diff -I /system/apex/com.android.adbd.apex -I apex_manifest.pb \
+      <($deapexer --debugfs_path=$debugfs list --extents ${apex_file} | sed -E 's#(.*) \[.*\]$#\1#' | grep -v "/$" | sed -E 's#^\./(.*)#\1#' | sort -n) \
+      <(grep '"fileName": ' ${apex_file}.spdx.json | sed -E 's/.*"fileName": "(.*)",/\1/' | sort -n )
+
+  if [ $? != "0" ]; then
+    echo "Diffs found in $apex_file and SBOM"
+    exit 1
+  else
+    echo "No diffs."
+  fi
+  set -e
+
+  # Teardown
+  cleanup "${out_dir}"
+}
+
+function test_sbom_unbundled_apk {
+  # Setup
+  out_dir="$(setup)"
+
+  # run_soong to build Browser2.apk
+  run_soong "module_arm64" "${out_dir}" "sbom" "Browser2"
+
+  sbom_file=${out_dir}/target/product/module_arm64/system/product/app/Browser2/Browser2.apk.spdx.json
+  echo "============ Diffing files in Browser2.apk and SBOM"
+  set +e
+  # There is only one file in SBOM of APKs
+  diff \
+      <(echo "/system/product/app/Browser2/Browser2.apk" ) \
+      <(grep '"fileName": ' ${sbom_file} | sed -E 's/.*"fileName": "(.*)",/\1/' )
+
+  if [ $? != "0" ]; then
+    echo "Diffs found in $sbom_file"
+    exit 1
+  else
+    echo "No diffs."
+  fi
+  set -e
+
+  # Teardown
+  cleanup "${out_dir}"
+}
+
+test_sbom_aosp_cf_x86_64_phone
+test_sbom_unbundled_apex
+test_sbom_unbundled_apk
\ No newline at end of file