Merge "Skip TestDex2oatToolDeps on Darwin."
diff --git a/android/apex.go b/android/apex.go
index b01b700..4b74436 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -36,11 +36,16 @@
 // Accessible via `ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)`
 type ApexInfo struct {
 	// Name of the apex variation that this module (i.e. the apex variant of the module) is
-	// mutated into, or "" for a platform (i.e. non-APEX) variant. Note that a module can be
-	// included in multiple APEXes, in which case, the module is mutated into one or more
-	// variants, each of which is for an APEX. The variants then can later be deduped if they
-	// don't need to be compiled differently. This is an optimization done in
-	// mergeApexVariations.
+	// mutated into, or "" for a platform (i.e. non-APEX) variant. Note that this name and the
+	// Soong module name of the APEX can be different. That happens when there is
+	// `override_apex` that overrides `apex`. In that case, both Soong modules have the same
+	// apex variation name which usually is `com.android.foo`. This name is also the `name`
+	// in the path `/apex/<name>` where this apex is activated on at runtime.
+	//
+	// Also note that a module can be included in multiple APEXes, in which case, the module is
+	// mutated into one or more variants, each of which is for an APEX. The variants then can
+	// later be deduped if they don't need to be compiled differently. This is an optimization
+	// done in mergeApexVariations.
 	ApexVariationName string
 
 	// ApiLevel that this module has to support at minimum.
@@ -52,11 +57,19 @@
 	// The list of SDK modules that the containing apexBundle depends on.
 	RequiredSdks SdkRefs
 
-	// List of apexBundles that this apex variant of the module is associated with. Initially,
-	// the size of this list is one because one apex variant is associated with one apexBundle.
-	// When multiple apex variants are merged in mergeApexVariations, ApexInfo struct of the
-	// merged variant holds the list of apexBundles that are merged together.
-	InApexes []string
+	// List of Apex variant names that this module is associated with. This initially is the
+	// same as the `ApexVariationName` field.  Then when multiple apex variants are merged in
+	// mergeApexVariations, ApexInfo struct of the merged variant holds the list of apexBundles
+	// that are merged together.
+	InApexVariants []string
+
+	// List of APEX Soong module names that this module is part of. Note that the list includes
+	// different variations of the same APEX. For example, if module `foo` is included in the
+	// apex `com.android.foo`, and also if there is an override_apex module
+	// `com.mycompany.android.foo` overriding `com.android.foo`, then this list contains both
+	// `com.android.foo` and `com.mycompany.android.foo`.  If the APEX Soong module is a
+	// prebuilt, the name here doesn't have the `prebuilt_` prefix.
+	InApexModules []string
 
 	// Pointers to the ApexContents struct each of which is for apexBundle modules that this
 	// module is part of. The ApexContents gives information about which modules the apexBundle
@@ -93,23 +106,33 @@
 	return i.ApexVariationName == ""
 }
 
-// InApex tells whether this apex variant of the module is part of the given apexBundle or not.
-func (i ApexInfo) InApex(apex string) bool {
-	for _, a := range i.InApexes {
-		if a == apex {
+// InApexVariant tells whether this apex variant of the module is part of the given apexVariant or
+// not.
+func (i ApexInfo) InApexVariant(apexVariant string) bool {
+	for _, a := range i.InApexVariants {
+		if a == apexVariant {
 			return true
 		}
 	}
 	return false
 }
 
-// InApexByBaseName tells whether this apex variant of the module is part of the given APEX or not,
-// where the APEX is specified by its canonical base name, i.e. typically beginning with
+// InApexByBaseName tells whether this apex variant of the module is part of the given apexVariant
+// or not, where the APEX is specified by its canonical base name, i.e. typically beginning with
 // "com.android.". In particular this function doesn't differentiate between source and prebuilt
 // APEXes, where the latter may have "prebuilt_" prefixes.
-func (i ApexInfo) InApexByBaseName(apex string) bool {
-	for _, a := range i.InApexes {
-		if RemoveOptionalPrebuiltPrefix(a) == apex {
+func (i ApexInfo) InApexVariantByBaseName(apexVariant string) bool {
+	for _, a := range i.InApexVariants {
+		if RemoveOptionalPrebuiltPrefix(a) == apexVariant {
+			return true
+		}
+	}
+	return false
+}
+
+func (i ApexInfo) InApexModule(apexModuleName string) bool {
+	for _, a := range i.InApexModules {
+		if a == apexModuleName {
 			return true
 		}
 	}
@@ -345,8 +368,21 @@
 func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
 	m.apexInfosLock.Lock()
 	defer m.apexInfosLock.Unlock()
-	for _, v := range m.apexInfos {
+	for i, v := range m.apexInfos {
 		if v.ApexVariationName == apex.ApexVariationName {
+			if len(apex.InApexModules) != 1 {
+				panic(fmt.Errorf("Newly created apexInfo must be for a single APEX"))
+			}
+			// Even when the ApexVariantNames are the same, the given ApexInfo might
+			// actually be for different APEX. This can happen when an APEX is
+			// overridden via override_apex. For example, there can be two apexes
+			// `com.android.foo` (from the `apex` module type) and
+			// `com.mycompany.android.foo` (from the `override_apex` module type), both
+			// of which has the same ApexVariantName `com.android.foo`. Add the apex
+			// name to the list so that it's not lost.
+			if !InList(apex.InApexModules[0], v.InApexModules) {
+				m.apexInfos[i].InApexModules = append(m.apexInfos[i].InApexModules, apex.InApexModules[0])
+			}
 			return
 		}
 	}
@@ -496,21 +532,23 @@
 		// Merge the ApexInfo together. If a compatible ApexInfo exists then merge the information from
 		// this one into it, otherwise create a new merged ApexInfo from this one and save it away so
 		// other ApexInfo instances can be merged into it.
-		apexName := apexInfo.ApexVariationName
+		variantName := apexInfo.ApexVariationName
 		mergedName := apexInfo.mergedName(ctx)
 		if index, exists := seen[mergedName]; exists {
 			// Variants having the same mergedName are deduped
-			merged[index].InApexes = append(merged[index].InApexes, apexName)
+			merged[index].InApexVariants = append(merged[index].InApexVariants, variantName)
+			merged[index].InApexModules = append(merged[index].InApexModules, apexInfo.InApexModules...)
 			merged[index].ApexContents = append(merged[index].ApexContents, apexInfo.ApexContents...)
 			merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
 		} else {
 			seen[mergedName] = len(merged)
 			apexInfo.ApexVariationName = mergedName
-			apexInfo.InApexes = CopyOf(apexInfo.InApexes)
+			apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
+			apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
 			apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
 			merged = append(merged, apexInfo)
 		}
-		aliases = append(aliases, [2]string{apexName, mergedName})
+		aliases = append(aliases, [2]string{variantName, mergedName})
 	}
 	return merged, aliases
 }
@@ -583,15 +621,15 @@
 // in the same APEX have unique APEX variations so that the module can link against the right
 // variant.
 func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) {
-	// anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes
-	// list in common. It is used instead of DepIsInSameApex because it needs to determine if
-	// the dep is in the same APEX due to being directly included, not only if it is included
-	// _because_ it is a dependency.
+	// anyInSameApex returns true if the two ApexInfo lists contain any values in an
+	// InApexVariants list in common. It is used instead of DepIsInSameApex because it needs to
+	// determine if the dep is in the same APEX due to being directly included, not only if it
+	// is included _because_ it is a dependency.
 	anyInSameApex := func(a, b []ApexInfo) bool {
 		collectApexes := func(infos []ApexInfo) []string {
 			var ret []string
 			for _, info := range infos {
-				ret = append(ret, info.InApexes...)
+				ret = append(ret, info.InApexVariants...)
 			}
 			return ret
 		}
diff --git a/android/apex_test.go b/android/apex_test.go
index 109b1c8..e112369 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
 		{
 			name: "single",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
 			},
 			wantAliases: [][2]string{
 				{"foo", "apex10000"},
@@ -45,11 +45,11 @@
 		{
 			name: "merge",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, nil, false}},
+				{"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
 			wantAliases: [][2]string{
 				{"bar", "apex10000_baz_1"},
 				{"foo", "apex10000_baz_1"},
@@ -58,12 +58,12 @@
 		{
 			name: "don't merge version",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
 			},
 			wantMerged: []ApexInfo{
-				{"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
-				{"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex30"},
@@ -73,11 +73,11 @@
 		{
 			name: "merge updatable",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -87,12 +87,12 @@
 		{
 			name: "don't merge sdks",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
-				{"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000_baz_2"},
@@ -102,15 +102,15 @@
 		{
 			name: "don't merge when for prebuilt_apex",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
 				// This one should not be merged in with the others because it is for
 				// a prebuilt_apex.
-				{"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+				{"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
-				{"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+				{"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
diff --git a/android/bazel.go b/android/bazel.go
index 4da899b..2d4755f 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -160,8 +160,6 @@
 	// Per-module denylist to always opt modules out of both bp2build and mixed builds.
 	bp2buildModuleDoNotConvertList = []string{
 		// Things that transitively depend on unconverted libc_* modules.
-		"libc_nomalloc", // http://b/186825031, cc_library_static, depends on //bionic/libc:libc_common (http://b/186821517)
-
 		"libbionic_spawn_benchmark", // http://b/186824595, cc_library_static, depends on //external/google-benchmark (http://b/186822740)
 		//                                                                also depends on //system/logging/liblog:liblog (http://b/186822772)
 
@@ -233,7 +231,8 @@
 		"libpropertyinfoparser",            // cparsons@, cc_library_static, wrong include paths
 		"libarm-optimized-routines-string", // jingwen@, cc_library_static, OK for bp2build but b/186615213 (asflags not handled in  bp2build), version script assignment of 'LIBC' to symbol 'memcmp' failed: symbol not defined (also for memrchr, strnlen)
 		"fmtlib_ndk",                       // http://b/187040371, cc_library_static, OK for bp2build but format-inl.h:11:10: fatal error: 'cassert' file not found for mixed builds
-	}
+		"libc_nomalloc",                    // cc_library_static, OK for bp2build but ld.lld: error: undefined symbol: pthread_mutex_lock (and others)
+    }
 
 	// Used for quicker lookups
 	bp2buildModuleDoNotConvert  = map[string]bool{}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 8cddbb2..a1206dc 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -333,7 +333,7 @@
 	// The actual platform values here may be overridden by configuration
 	// transitions from the buildroot.
 	cmdFlags = append(cmdFlags,
-		fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_x86_64"))
+		fmt.Sprintf("--platforms=%s", "//build/bazel/platforms:android_arm"))
 	cmdFlags = append(cmdFlags,
 		fmt.Sprintf("--extra_toolchains=%s", "//prebuilts/clang/host/linux-x86:all"))
 	// This should be parameterized on the host OS, but let's restrict to linux
@@ -567,7 +567,7 @@
 // Returns the path where the contents of the @soong_injection repository live.
 // It is used by Soong to tell Bazel things it cannot over the command line.
 func (p *bazelPaths) injectedFilesDir() string {
-	return filepath.Join(p.buildDir, "soong_injection")
+	return filepath.Join(p.buildDir, bazel.SoongInjectionDirName)
 }
 
 // Returns the path of the synthetic Bazel workspace that contains a symlink
diff --git a/android/config.go b/android/config.go
index 79917ad..4847182 100644
--- a/android/config.go
+++ b/android/config.go
@@ -35,6 +35,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android/soongconfig"
+	"android/soong/bazel"
 	"android/soong/remoteexec"
 )
 
@@ -169,7 +170,7 @@
 
 // loadFromConfigFile loads and decodes configuration options from a JSON file
 // in the current working directory.
-func loadFromConfigFile(configurable jsonConfigurable, filename string) error {
+func loadFromConfigFile(configurable *productVariables, filename string) error {
 	// Try to open the file
 	configFileReader, err := os.Open(filename)
 	defer configFileReader.Close()
@@ -194,13 +195,20 @@
 		}
 	}
 
-	// No error
-	return nil
+	if Bool(configurable.GcovCoverage) && Bool(configurable.ClangCoverage) {
+		return fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
+	}
+
+	configurable.Native_coverage = proptools.BoolPtr(
+		Bool(configurable.GcovCoverage) ||
+			Bool(configurable.ClangCoverage))
+
+	return saveToBazelConfigFile(configurable, filepath.Dir(filename))
 }
 
 // atomically writes the config file in case two copies of soong_build are running simultaneously
 // (for example, docs generation and ninja manifest generation)
-func saveToConfigFile(config jsonConfigurable, filename string) error {
+func saveToConfigFile(config *productVariables, filename string) error {
 	data, err := json.MarshalIndent(&config, "", "    ")
 	if err != nil {
 		return fmt.Errorf("cannot marshal config data: %s", err.Error())
@@ -229,6 +237,35 @@
 	return nil
 }
 
+func saveToBazelConfigFile(config *productVariables, outDir string) error {
+	dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config")
+	err := createDirIfNonexistent(dir, os.ModePerm)
+	if err != nil {
+		return fmt.Errorf("Could not create dir %s: %s", dir, err)
+	}
+
+	data, err := json.MarshalIndent(&config, "", "    ")
+	if err != nil {
+		return fmt.Errorf("cannot marshal config data: %s", err.Error())
+	}
+
+	bzl := []string{
+		bazel.GeneratedBazelFileWarning,
+		fmt.Sprintf(`_product_vars = json.decode("""%s""")`, data),
+		"product_vars = _product_vars\n",
+	}
+	err = ioutil.WriteFile(filepath.Join(dir, "product_variables.bzl"), []byte(strings.Join(bzl, "\n")), 0644)
+	if err != nil {
+		return fmt.Errorf("Could not write .bzl config file %s", err)
+	}
+	err = ioutil.WriteFile(filepath.Join(dir, "BUILD"), []byte(bazel.GeneratedBazelFileWarning), 0644)
+	if err != nil {
+		return fmt.Errorf("Could not write BUILD config file %s", err)
+	}
+
+	return nil
+}
+
 // NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that
 // use the android package.
 func NullConfig(buildDir string) Config {
@@ -448,14 +485,6 @@
 		config.AndroidFirstDeviceTarget = firstTarget(config.Targets[Android], "lib64", "lib32")[0]
 	}
 
-	if Bool(config.productVariables.GcovCoverage) && Bool(config.productVariables.ClangCoverage) {
-		return Config{}, fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
-	}
-
-	config.productVariables.Native_coverage = proptools.BoolPtr(
-		Bool(config.productVariables.GcovCoverage) ||
-			Bool(config.productVariables.ClangCoverage))
-
 	config.BazelContext, err = NewBazelContext(config)
 	config.bp2buildPackageConfig = bp2buildDefaultConfig
 	config.bp2buildModuleTypeConfig = make(map[string]bool)
diff --git a/android/paths.go b/android/paths.go
index fb75117..88d625a 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1990,6 +1990,10 @@
 
 func CreateOutputDirIfNonexistent(path WritablePath, perm os.FileMode) error {
 	dir := absolutePath(path.String())
+	return createDirIfNonexistent(dir, perm)
+}
+
+func createDirIfNonexistent(dir string, perm os.FileMode) error {
 	if _, err := os.Stat(dir); os.IsNotExist(err) {
 		return os.MkdirAll(dir, os.ModePerm)
 	} else {
diff --git a/android/variable.go b/android/variable.go
index e830845..672576a 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -282,7 +282,7 @@
 	NativeCoverageExcludePaths []string `json:",omitempty"`
 
 	// Set by NewConfig
-	Native_coverage *bool
+	Native_coverage *bool `json:",omitempty"`
 
 	SanitizeHost       []string `json:",omitempty"`
 	SanitizeDevice     []string `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 7b2e19d..da4f472 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -906,12 +906,16 @@
 
 	// This is the main part of this mutator. Mark the collected dependencies that they need to
 	// be built for this apexBundle.
+
+	// Note that there are many different names.
+	// ApexVariationName: this is the name of the apex variation
 	apexInfo := android.ApexInfo{
-		ApexVariationName: mctx.ModuleName(),
+		ApexVariationName: mctx.ModuleName(), // could be com.android.foo
 		MinSdkVersion:     minSdkVersion,
 		RequiredSdks:      a.RequiredSdks(),
 		Updatable:         a.Updatable(),
-		InApexes:          []string{mctx.ModuleName()},
+		InApexVariants:    []string{mctx.ModuleName()}, // could be com.android.foo
+		InApexModules:     []string{a.Name()},          // could be com.mycompany.android.foo
 		ApexContents:      []*android.ApexContents{apexContents},
 	}
 	mctx.WalkDeps(func(child, parent android.Module) bool {
@@ -1604,7 +1608,7 @@
 		}
 
 		ai := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
-		externalDep := !android.InList(ctx.ModuleName(), ai.InApexes)
+		externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
 
 		// Visit actually
 		return do(ctx, parent, am, externalDep)
@@ -2149,7 +2153,10 @@
 
 	// Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the
 	// hidden API encpding.
-	dexBootJar := bootclasspathFragmentInfo.DexBootJarPathForContentModule(javaModule)
+	dexBootJar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(javaModule)
+	if err != nil {
+		ctx.ModuleErrorf("%s", err)
+	}
 
 	// Create an apexFile as for a normal java module but with the dex boot jar provided by the
 	// bootclasspath_fragment.
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 7bb3ff6..9a8c7d0 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -433,6 +433,14 @@
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
 		prepareForTestWithMyapex,
+		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+		java.FixtureConfigureBootJars("myapex:foo", "myapex:bar"),
+		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+		// is disabled.
+		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("foo"),
 	).RunTestWithBp(t, `
 		apex {
 			name: "myapex",
@@ -449,10 +457,11 @@
 			private_key: "testkey.pem",
 		}
 
-		java_library {
+		java_sdk_library {
 			name: "foo",
 			srcs: ["b.java"],
-			installable: true,
+			shared_library: false,
+			public: {enabled: true},
 			apex_available: [
 				"myapex",
 			],
@@ -491,6 +500,30 @@
 		`myapex.key`,
 		`mybootclasspathfragment`,
 	})
+
+	apex := result.ModuleForTests("myapex", "android_common_myapex_image")
+	apexRule := apex.Rule("apexRule")
+	copyCommands := apexRule.Args["copy_commands"]
+
+	// Make sure that the fragment provides the hidden API encoded dex jars to the APEX.
+	fragment := result.Module("mybootclasspathfragment", "android_common_apex10000")
+
+	info := result.ModuleProvider(fragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+
+	checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
+		module := result.Module(name, "android_common_apex10000")
+		dexJar, err := info.DexBootJarPathForContentModule(module)
+		if err != nil {
+			t.Error(err)
+		}
+		android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar)
+
+		expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name)
+		android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand)
+	}
+
+	checkFragmentExportedDexJar("foo", "out/soong/.intermediates/foo/android_common_apex10000/hiddenapi/foo.jar")
+	checkFragmentExportedDexJar("bar", "out/soong/.intermediates/bar/android_common_apex10000/hiddenapi/bar.jar")
 }
 
 // TODO(b/177892522) - add test for host apex.
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 52b1689..ce12f46 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -20,6 +20,7 @@
 	"android/soong/android"
 	"android/soong/java"
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 // Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
@@ -174,6 +175,141 @@
 	})
 }
 
+// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
+// AlwaysUsePrebuiltSdk() returns true. The structure of the modules in this test matches what
+// currently exists in some places in the Android build but it is not the intended structure. It is
+// in fact an invalid structure that should cause build failures. However, fixing that structure
+// will take too long so in the meantime this tests the workarounds to avoid build breakages.
+//
+// The main issues with this structure are:
+// 1. There is no prebuilt_bootclasspath_fragment referencing the "foo" java_sdk_library_import.
+// 2. There is no prebuilt_apex/apex_set which makes the dex implementation jar available to the
+//    prebuilt_bootclasspath_fragment and the "foo" java_sdk_library_import.
+//
+// Together these cause the following symptoms:
+// 1. The "foo" java_sdk_library_import does not have a dex implementation jar.
+// 2. The "foo" java_sdk_library_import does not have a myapex variant.
+//
+// TODO(b/179354495): Fix the structure in this test once the main Android build has been fixed.
+func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForTestWithPlatformBootclasspath,
+		prepareForTestWithMyapex,
+		// Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
+		// of AlwaysUsePrebuiltsSdk() but does not have an appropriate apex variant and does not provide
+		// a boot dex jar. The second is a normal library that is unaffected. The order matters because
+		// if the dependency on myapex:foo is filtered out because of either of those conditions then
+		// the dependencies resolved by the platform_bootclasspath will not match the configured list
+		// and so will fail the test.
+		java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
+		}),
+		java.FixtureWithPrebuiltApis(map[string][]string{
+			"current": {},
+			"30":      {"foo"},
+		}),
+	).RunTestWithBp(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			bootclasspath_fragments: [
+				"mybootclasspath-fragment",
+			],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+			installable: true,
+			apex_available: ["myapex"],
+			permitted_packages: ["bar"],
+		}
+
+		java_sdk_library {
+			name: "foo",
+			srcs: ["b.java"],
+			shared_library: false,
+			public: {
+				enabled: true,
+			},
+			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
+		}
+
+		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
+		// because AlwaysUsePrebuiltSdks() is true.
+		java_sdk_library_import {
+			name: "foo",
+			prefer: false,
+			shared_library: false,
+			public: {
+				jars: ["sdk_library/public/foo-stubs.jar"],
+				stub_srcs: ["sdk_library/public/foo_stub_sources"],
+				current_api: "sdk_library/public/foo.txt",
+				removed_api: "sdk_library/public/foo-removed.txt",
+				sdk_version: "current",
+			},
+			apex_available: ["myapex"],
+		}
+
+		// This always depends on the source foo module, its dependencies are not affected by the
+		// AlwaysUsePrebuiltSdks().
+		bootclasspath_fragment {
+			name: "mybootclasspath-fragment",
+			apex_available: [
+				"myapex",
+			],
+			contents: [
+				"foo", "bar",
+			],
+		}
+
+		platform_bootclasspath {
+			name: "myplatform-bootclasspath",
+		}
+`,
+	)
+
+	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
+		// The configured contents of BootJars.
+		"platform:prebuilt_foo", // Note: This is the platform not myapex variant.
+		"myapex:bar",
+	})
+
+	// Make sure that the myplatform-bootclasspath has the correct dependencies.
+	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+		// The following are stubs.
+		"platform:prebuilt_sdk_public_current_android",
+		"platform:prebuilt_sdk_system_current_android",
+		"platform:prebuilt_sdk_test_current_android",
+
+		// Not a prebuilt as no prebuilt existed when it was added.
+		"platform:legacy.core.platform.api.stubs",
+
+		// Needed for generating the boot image.
+		`platform:dex2oatd`,
+
+		// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
+		// modules when available as it does not know which one will be preferred.
+		//
+		// The source module has an APEX variant but the prebuilt does not.
+		"myapex:foo",
+		"platform:prebuilt_foo",
+
+		// Only a source module exists.
+		"myapex:bar",
+	})
+}
+
 // CheckModuleDependencies checks the dependencies of the selected module against the expected list.
 //
 // The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9d632a9..6125ef5 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -230,7 +230,8 @@
 	// Create an ApexInfo for the prebuilt_apex.
 	apexInfo := android.ApexInfo{
 		ApexVariationName: android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName()),
-		InApexes:          []string{mctx.ModuleName()},
+		InApexVariants:    []string{mctx.ModuleName()},
+		InApexModules:     []string{mctx.ModuleName()},
 		ApexContents:      []*android.ApexContents{apexContents},
 		ForPrebuiltApex:   true,
 	}
diff --git a/bazel/constants.go b/bazel/constants.go
index 15c75cf..6beb496 100644
--- a/bazel/constants.go
+++ b/bazel/constants.go
@@ -18,6 +18,10 @@
 
 	// Run bazel as a ninja executer
 	BazelNinjaExecRunName = RunName("bazel-ninja-exec")
+
+	SoongInjectionDirName = "soong_injection"
+
+	GeneratedBazelFileWarning = "# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT"
 )
 
 // String returns the name of the run.
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 59c5acd..ee36982 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/bazel"
 	"fmt"
 	"os"
 )
@@ -32,7 +33,7 @@
 	bp2buildFiles := CreateBazelFiles(nil, buildToTargets, ctx.mode)
 	writeFiles(ctx, bp2buildDir, bp2buildFiles)
 
-	soongInjectionDir := android.PathForOutput(ctx, "soong_injection")
+	soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
 	writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles())
 
 	return metrics
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 63a6c2e..71660a8 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -324,11 +324,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
-		if Errored(t, "", errs) {
+		if errored(t, "", errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, "", errs) {
+		if errored(t, "", errs) {
 			continue
 		}
 
@@ -925,11 +925,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
@@ -957,17 +957,6 @@
 	}
 }
 
-func Errored(t *testing.T, desc string, errs []error) bool {
-	t.Helper()
-	if len(errs) > 0 {
-		for _, err := range errs {
-			t.Errorf("%s: %s", desc, err)
-		}
-		return true
-	}
-	return false
-}
-
 type bp2buildMutator = func(android.TopDownMutatorContext)
 
 func TestBp2BuildInlinesDefaults(t *testing.T) {
@@ -1483,11 +1472,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
@@ -1606,11 +1595,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 32b12e4..204c519 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -22,8 +22,6 @@
 	"testing"
 )
 
-var buildDir string
-
 func setUp() {
 	var err error
 	buildDir, err = ioutil.TempDir("", "bazel_queryview_test")
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index da5444c..a1ffabc 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -617,11 +617,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 1202da6..a3965ed 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -385,11 +385,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index bb12462..4fcf5e4 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1132,11 +1132,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index ea8b9f1..ebc9c94 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -228,11 +228,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
@@ -411,11 +411,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 2054e06..ed509bf 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -128,11 +128,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index 37f542e..575bf58 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -101,11 +101,11 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, toParse)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 		_, errs = ctx.ResolveDependencies(config)
-		if Errored(t, testCase.description, errs) {
+		if errored(t, testCase.description, errs) {
 			continue
 		}
 
diff --git a/bp2build/testing.go b/bp2build/testing.go
index b925682..e575bc6 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -1,6 +1,8 @@
 package bp2build
 
 import (
+	"testing"
+
 	"android/soong/android"
 	"android/soong/bazel"
 )
@@ -10,6 +12,8 @@
 	bp2buildConfig = android.Bp2BuildConfig{
 		android.BP2BUILD_TOPLEVEL: android.Bp2BuildDefaultTrueRecursively,
 	}
+
+	buildDir string
 )
 
 type nestedProps struct {
@@ -39,6 +43,17 @@
 	props customProps
 }
 
+func errored(t *testing.T, desc string, errs []error) bool {
+	t.Helper()
+	if len(errs) > 0 {
+		for _, err := range errs {
+			t.Errorf("%s: %s", desc, err)
+		}
+		return true
+	}
+	return false
+}
+
 // OutputFiles is needed because some instances of this module use dist with a
 // tag property which requires the module implements OutputFileProducer.
 func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 02d6428..75543ac 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -91,12 +91,15 @@
 		allDeps = append(allDeps, lib.SharedProperties.Shared.Static_libs...)
 		allDeps = append(allDeps, lib.SharedProperties.Shared.Whole_static_libs...)
 		allDeps = append(allDeps, lib.SharedProperties.Shared.Shared_libs...)
-		allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
 
 		allDeps = append(allDeps, lib.StaticProperties.Static.Static_libs...)
 		allDeps = append(allDeps, lib.StaticProperties.Static.Whole_static_libs...)
 		allDeps = append(allDeps, lib.StaticProperties.Static.Shared_libs...)
-		allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
+
+		// TODO(b/186024507, b/186489250): Temporarily exclude adding
+		// system_shared_libs deps until libc and libm builds.
+		// allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...)
+		// allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...)
 	}
 
 	ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
diff --git a/cc/cc.go b/cc/cc.go
index a0ad0d6..8a34dad 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2833,7 +2833,7 @@
 						// Add the dependency to the APEX(es) providing the library so that
 						// m <module> can trigger building the APEXes as well.
 						depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo)
-						for _, an := range depApexInfo.InApexes {
+						for _, an := range depApexInfo.InApexVariants {
 							c.Properties.ApexesProvidingSharedLibs = append(
 								c.Properties.ApexesProvidingSharedLibs, an)
 						}
diff --git a/cc/linker.go b/cc/linker.go
index 196806d..5bd21ed 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -393,7 +393,7 @@
 	if ctx.minSdkVersion() == "current" {
 		return true
 	}
-	parsedSdkVersion, err := android.ApiLevelFromUser(ctx, ctx.minSdkVersion())
+	parsedSdkVersion, err := nativeApiLevelFromUser(ctx, ctx.minSdkVersion())
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version",
 			"Invalid min_sdk_version value (must be int or current): %q",
@@ -424,7 +424,7 @@
 			// ANDROID_RELR relocations were supported at API level >= 28.
 			// Relocation packer was supported at API level >= 23.
 			// Do the best we can...
-			if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, android.FirstShtRelrVersion) {
+			if (!ctx.useSdk() && ctx.minSdkVersion() == "") || CheckSdkVersionAtLeast(ctx, android.FirstShtRelrVersion) {
 				flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android+relr")
 			} else if CheckSdkVersionAtLeast(ctx, android.FirstAndroidRelrVersion) {
 				flags.Global.LdFlags = append(flags.Global.LdFlags,
diff --git a/java/base.go b/java/base.go
index 0d2f1ac..f7989b8 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1217,12 +1217,6 @@
 				return
 			}
 
-			// Initialize the hiddenapi structure.
-			j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex)
-
-			// Encode hidden API flags in dex file.
-			dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
-
 			// merge dex jar with resources if necessary
 			if j.resourceJar != nil {
 				jars := android.Paths{dexOutputFile, j.resourceJar}
@@ -1238,6 +1232,12 @@
 				}
 			}
 
+			// Initialize the hiddenapi structure.
+			j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex)
+
+			// Encode hidden API flags in dex file, if needed.
+			dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
+
 			j.dexJarFile = dexOutputFile
 
 			// Dexpreopting
diff --git a/java/boot_jars.go b/java/boot_jars.go
index 1fb3deb..7abda80 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -89,7 +89,7 @@
 		name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
 		if apex, ok := moduleToApex[name]; ok {
 			apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
-			if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexByBaseName(apex) {
+			if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexModule(apex) {
 				// The module name/apex variant should be unique in the system but double check
 				// just in case something has gone wrong.
 				if existing, ok := nameToApexVariant[name]; ok {
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 02833ab..634959a 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -29,7 +29,7 @@
 
 func registerBootclasspathBuildComponents(ctx android.RegistrationContext) {
 	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator)
+		ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator).Parallel()
 	})
 }
 
@@ -95,6 +95,15 @@
 	if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
 		ctx.AddVariationDependencies(variations, tag, prebuiltName)
 		addedDep = true
+	} else if ctx.Config().AlwaysUsePrebuiltSdks() && len(variations) > 0 {
+		// TODO(b/179354495): Remove this code path once the Android build has been fully migrated to
+		//  use bootclasspath_fragment properly.
+		// Some prebuilt java_sdk_library modules do not yet have an APEX variations so try and add a
+		// dependency on the non-APEX variant.
+		if ctx.OtherModuleDependencyVariantExists(nil, prebuiltName) {
+			ctx.AddVariationDependencies(nil, tag, prebuiltName)
+			addedDep = true
+		}
 	}
 
 	// If no appropriate variant existing for this, so no dependency could be added, then it is an
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 5d8a8e5..6b395fb 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -273,6 +273,10 @@
 	// Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur
 	// when SkipDexpreoptBootJars(ctx) returns true.
 	imageConfig *bootImageConfig
+
+	// Map from the name of the context module (as returned by Name()) to the hidden API encoded dex
+	// jar path.
+	contentModuleDexJarPaths map[string]android.Path
 }
 
 func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
@@ -299,10 +303,14 @@
 // 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.
-func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) android.Path {
-	j := module.(UsesLibraryDependency)
-	dexJar := j.DexJarBuildPath()
-	return dexJar
+func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) {
+	name := module.Name()
+	if dexJar, ok := i.contentModuleDexJarPaths[name]; ok {
+		return dexJar, nil
+	} else {
+		return nil, fmt.Errorf("unknown bootclasspath_fragment content module %s, expected one of %s",
+			name, strings.Join(android.SortedStringKeys(i.contentModuleDexJarPaths), ", "))
+	}
 }
 
 func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
@@ -380,6 +388,28 @@
 	// Perform hidden API processing.
 	b.generateHiddenAPIBuildActions(ctx, contents)
 
+	// Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
+	// prebuilt which will not use the image config.
+	imageConfig := b.getImageConfig(ctx)
+
+	// A prebuilt fragment cannot contribute to the apex.
+	if !android.IsModulePrebuilt(ctx.Module()) {
+		// Provide the apex content info.
+		b.provideApexContentInfo(ctx, imageConfig, contents)
+	}
+}
+
+// provideApexContentInfo creates, initializes and stores the apex content info for use by other
+// modules.
+func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module) {
+	// Construct the apex content info from the config.
+	info := BootclasspathFragmentApexContentInfo{
+		imageConfig: imageConfig,
+	}
+
+	// Populate the apex content info with paths to the dex jars.
+	b.populateApexContentInfoDexJars(ctx, &info, contents)
+
 	if !SkipDexpreoptBootJars(ctx) {
 		// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
 		// GenerateSingletonBuildActions method as it cannot create it for itself.
@@ -387,11 +417,20 @@
 
 		// Only generate the boot image if the configuration does not skip it.
 		b.generateBootImageBuildActions(ctx, contents)
+	}
 
-		// Make the boot image info available for other modules
-		ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, BootclasspathFragmentApexContentInfo{
-			imageConfig: b.getImageConfig(ctx),
-		})
+	// Make the apex content info available for other modules.
+	ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
+}
+
+// populateApexContentInfoDexJars adds paths to the dex jars provided by this fragment to the
+// apex content info.
+func (b *BootclasspathFragmentModule) populateApexContentInfoDexJars(ctx android.ModuleContext, info *BootclasspathFragmentApexContentInfo, contents []android.Module) {
+	info.contentModuleDexJarPaths = map[string]android.Path{}
+	for _, m := range contents {
+		j := m.(UsesLibraryDependency)
+		dexJar := j.DexJarBuildPath()
+		info.contentModuleDexJarPaths[m.Name()] = dexJar
 	}
 }
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index e9f7c44..e1a3650 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -766,7 +766,7 @@
 			if len(pp) > 0 {
 				updatablePackages = append(updatablePackages, pp...)
 			} else {
-				ctx.ModuleErrorf("Missing permitted_packages")
+				ctx.OtherModuleErrorf(module, "Missing permitted_packages")
 			}
 		}
 	}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 1e83824..c9e3c29 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -235,7 +235,7 @@
 		  echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})";
 		done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags &&
 		${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" &&
-		${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
+		${config.MergeZipsCmd} -j -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
 	CommandDeps: []string{
 		"${config.HiddenAPI}",
 		"${config.SoongZipCmd}",
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 2dceb65..f5afe5d 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"strings"
 
 	"android/soong/android"
@@ -560,7 +561,25 @@
 	for _, module := range contents {
 		bootDexJar := module.bootDexJar()
 		if bootDexJar == nil {
-			ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+			if ctx.Config().AlwaysUsePrebuiltSdks() {
+				// TODO(b/179354495): Remove this work around when it is unnecessary.
+				// Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
+				// create a fake one that will cause a build error only if it is used.
+				fake := android.PathForModuleOut(ctx, "fake/boot-dex/%s.jar", module.Name())
+
+				// Create an error rule that pretends to create the output file but will actually fail if it
+				// is run.
+				ctx.Build(pctx, android.BuildParams{
+					Rule:   android.ErrorRule,
+					Output: fake,
+					Args: map[string]string{
+						"error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
+					},
+				})
+				bootDexJars = append(bootDexJars, fake)
+			} else {
+				ctx.ModuleErrorf("module %s does not provide a dex jar", module)
+			}
 		} else {
 			bootDexJars = append(bootDexJars, bootDexJar)
 		}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 848aa59..bdf055a 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -167,11 +167,11 @@
 	// Now match the apex part of the boot image configuration.
 	requiredApex := configuredBootJars.Apex(index)
 	if requiredApex == "platform" || requiredApex == "system_ext" {
-		if len(apexInfo.InApexes) != 0 {
+		if len(apexInfo.InApexVariants) != 0 {
 			// A platform variant is required but this is for an apex so ignore it.
 			return false
 		}
-	} else if !apexInfo.InApexByBaseName(requiredApex) {
+	} else if !apexInfo.InApexVariantByBaseName(requiredApex) {
 		// An apex variant for a specific apex is required but this is the wrong apex.
 		return false
 	}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index c8fafed..10bf179 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -225,7 +225,7 @@
 		fromUpdatableApex := apexInfo.Updatable
 		if fromUpdatableApex {
 			// error: this jar is part of an updatable apex
-			ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexes)
+			ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexVariants)
 		} else {
 			// ok: this jar is part of the platform or a non-updatable apex
 		}
@@ -242,8 +242,15 @@
 		} else {
 			name := ctx.OtherModuleName(m)
 			if apexInfo.IsForPlatform() {
-				// error: this jar is part of the platform
-				ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+				// If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will
+				// include platform variants of a prebuilt module due to workarounds elsewhere. In that case
+				// do not treat this as an error.
+				// TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment
+				//  modules is complete.
+				if !ctx.Config().AlwaysUsePrebuiltSdks() {
+					// error: this jar is part of the platform
+					ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name)
+				}
 			} else {
 				// TODO(b/177892522): Treat this as an error.
 				// Cannot do that at the moment because framework-wifi and framework-tethering are in the
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 99eacf4..b5b6232 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1546,7 +1546,7 @@
 func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	otherApexInfo := ctx.OtherModuleProvider(other, android.ApexInfoProvider).(android.ApexInfo)
-	return len(otherApexInfo.InApexes) > 0 && reflect.DeepEqual(apexInfo.InApexes, otherApexInfo.InApexes)
+	return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
 }
 
 func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
diff --git a/java/testing.go b/java/testing.go
index 51a1c62..1fef337 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -378,7 +378,7 @@
 	if apexInfo.IsForPlatform() {
 		apex = "platform"
 	} else {
-		apex = apexInfo.InApexes[0]
+		apex = apexInfo.InApexVariants[0]
 	}
 
 	return fmt.Sprintf("%s:%s", apex, name)
diff --git a/tests/lib.sh b/tests/lib.sh
index e561a3d..35ccea9 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -114,6 +114,7 @@
   symlink_directory prebuilts/jdk
 
   symlink_file WORKSPACE
+  symlink_file BUILD
   symlink_file tools/bazel
 }