Merge "Remove some unblocked items from the denylist"
diff --git a/apex/apex.go b/apex/apex.go
index b7faa5b..55b0858 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2647,7 +2647,7 @@
 	//
 	// Module separator
 	//
-	m["com.android.bluetooth.updatable"] = []string{
+	m["com.android.bluetooth"] = []string{
 		"android.hardware.audio.common@5.0",
 		"android.hardware.bluetooth.a2dp@1.0",
 		"android.hardware.bluetooth.audio@2.0",
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 7ecf9b2..ce828e1 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path"
 	"sort"
 	"strings"
 	"testing"
@@ -442,6 +443,24 @@
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
 
+	t.Run("boot image disable generate profile", func(t *testing.T) {
+		result := android.GroupFixturePreparers(
+			commonPreparer,
+
+			// Configure some libraries in the art bootclasspath_fragment that match the source
+			// bootclasspath_fragment's contents property.
+			java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
+			addSource("foo", "bar"),
+			dexpreopt.FixtureDisableGenerateProfile(true),
+		).RunTest(t)
+
+		files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art_image")
+		for _, file := range files {
+			matched, _ := path.Match("etc/boot-image.prof", file.path)
+			android.AssertBoolEquals(t, "\"etc/boot-image.prof\" should not be in the APEX", matched, false)
+		}
+	})
+
 	t.Run("boot image files with preferred prebuilt", func(t *testing.T) {
 		result := android.GroupFixturePreparers(
 			commonPreparer,
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 5131cd3..47ae494 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -167,3 +167,10 @@
 		dexpreoptConfig.BootImageProfiles = android.PathsForSource(ctx, profiles)
 	})
 }
+
+// FixtureDisableGenerateProfile sets the DisableGenerateProfile property in the global config.
+func FixtureDisableGenerateProfile(disable bool) android.FixturePreparer {
+	return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+		dexpreoptConfig.DisableGenerateProfile = disable
+	})
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 75083e8..c599c4d 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -506,8 +506,18 @@
 		dst := dstBootJarsByModule[name]
 
 		if src == nil {
+			// A dex boot jar should be provided by the source java module. It needs to be installable or
+			// have compile_dex=true - cf. assignments to java.Module.dexJarFile.
+			//
+			// However, the source java module may be either replaced or overridden (using prefer:true) by
+			// a prebuilt java module with the same name. In that case the dex boot jar needs to be
+			// provided by the corresponding prebuilt APEX module. That APEX is the one that refers
+			// through a exported_(boot|systemserver)classpath_fragments property to a
+			// prebuilt_(boot|systemserver)classpath_fragment module, which in turn lists the prebuilt
+			// java module in the contents property. If that chain is broken then this dependency will
+			// fail.
 			if !ctx.Config().AllowMissingDependencies() {
-				ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
+				ctx.ModuleErrorf("module %s does not provide a dex boot jar (see comment next to this message in Soong for details)", name)
 			} else {
 				ctx.AddMissingDependencies([]string{name})
 			}