Merge "[soong] new field in Android.bp to request APK signing V4"
diff --git a/README.md b/README.md
index b1bb425..3eac87b 100644
--- a/README.md
+++ b/README.md
@@ -419,7 +419,8 @@
     name: "acme_cc_defaults",
     module_type: "cc_defaults",
     config_namespace: "acme",
-    variables: ["board", "feature"],
+    variables: ["board"],
+    bool_variables: ["feature"],
     properties: ["cflags", "srcs"],
 }
 
@@ -427,10 +428,6 @@
     name: "board",
     values: ["soc_a", "soc_b"],
 }
-
-soong_config_bool_variable {
-    name: "feature",
-}
 ```
 
 This example describes a new `acme_cc_defaults` module type that extends the
diff --git a/android/apex.go b/android/apex.go
index eabe059..cbaf1c7 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -92,12 +92,10 @@
 	// APEX as this module
 	DepIsInSameApex(ctx BaseModuleContext, dep Module) bool
 
-	// Returns the highest version which is <= min_sdk_version.
-	// For example, with min_sdk_version is 10 and versionList is [9,11]
-	// it returns 9.
-	ChooseSdkVersion(versionList []string, useLatest bool) (string, error)
-
-	ShouldSupportAndroid10() bool
+	// Returns the highest version which is <= maxSdkVersion.
+	// For example, with maxSdkVersion is 10 and versionList is [9,11]
+	// it returns 9 as string
+	ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error)
 }
 
 type ApexProperties struct {
@@ -193,22 +191,14 @@
 	return true
 }
 
-func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, useLatest bool) (string, error) {
-	if useLatest {
-		return versionList[len(versionList)-1], nil
-	}
-	minSdkVersion := m.ApexProperties.Info.MinSdkVersion
+func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion int) (string, error) {
 	for i := range versionList {
 		ver, _ := strconv.Atoi(versionList[len(versionList)-i-1])
-		if ver <= minSdkVersion {
+		if ver <= maxSdkVersion {
 			return versionList[len(versionList)-i-1], nil
 		}
 	}
-	return "", fmt.Errorf("min_sdk_version is set %v, but not found in %v", minSdkVersion, versionList)
-}
-
-func (m *ApexModuleBase) ShouldSupportAndroid10() bool {
-	return !m.IsForPlatform() && (m.ApexProperties.Info.MinSdkVersion <= SdkVersion_Android10)
+	return "", fmt.Errorf("not found a version(<=%d) in versionList: %v", maxSdkVersion, versionList)
 }
 
 func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
diff --git a/android/config.go b/android/config.go
index 7953170..558c828 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1032,6 +1032,10 @@
 	return c.config.productVariables.DeviceKernelHeaders
 }
 
+func (c *deviceConfig) SamplingPGO() bool {
+	return Bool(c.config.productVariables.SamplingPGO)
+}
+
 func (c *config) NativeLineCoverage() bool {
 	return Bool(c.productVariables.NativeLineCoverage)
 }
diff --git a/android/defs.go b/android/defs.go
index 5c815e6..4552224 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -100,6 +100,9 @@
 	// Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
 	localPool = blueprint.NewBuiltinPool("local_pool")
 
+	// Used only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja.
+	remotePool = blueprint.NewBuiltinPool("remote_pool")
+
 	// Used for processes that need significant RAM to ensure there are not too many running in parallel.
 	highmemPool = blueprint.NewBuiltinPool("highmem_pool")
 )
diff --git a/android/module.go b/android/module.go
index 057a5c7..80f477b 100644
--- a/android/module.go
+++ b/android/module.go
@@ -894,6 +894,40 @@
 	return Bool(m.commonProperties.System_ext_specific)
 }
 
+func (m *ModuleBase) PartitionTag(config DeviceConfig) string {
+	partition := "system"
+	if m.SocSpecific() {
+		// A SoC-specific module could be on the vendor partition at
+		// "vendor" or the system partition at "system/vendor".
+		if config.VendorPath() == "vendor" {
+			partition = "vendor"
+		}
+	} else if m.DeviceSpecific() {
+		// A device-specific module could be on the odm partition at
+		// "odm", the vendor partition at "vendor/odm", or the system
+		// partition at "system/vendor/odm".
+		if config.OdmPath() == "odm" {
+			partition = "odm"
+		} else if strings.HasPrefix(config.OdmPath(), "vendor/") {
+			partition = "vendor"
+		}
+	} else if m.ProductSpecific() {
+		// A product-specific module could be on the product partition
+		// at "product" or the system partition at "system/product".
+		if config.ProductPath() == "product" {
+			partition = "product"
+		}
+	} else if m.SystemExtSpecific() {
+		// A system_ext-specific module could be on the system_ext
+		// partition at "system_ext" or the system partition at
+		// "system/system_ext".
+		if config.SystemExtPath() == "system_ext" {
+			partition = "system_ext"
+		}
+	}
+	return partition
+}
+
 func (m *ModuleBase) Enabled() bool {
 	if m.commonProperties.Enabled == nil {
 		return !m.Os().DefaultDisabled
@@ -1472,10 +1506,17 @@
 func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
 	argNames ...string) blueprint.Rule {
 
-	if m.config.UseRemoteBuild() && params.Pool == nil {
-		// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
-		// jobs to the local parallelism value
-		params.Pool = localPool
+	if m.config.UseRemoteBuild() {
+		if params.Pool == nil {
+			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
+			// jobs to the local parallelism value
+			params.Pool = localPool
+		} else if params.Pool == remotePool {
+			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
+			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
+			// parallelism.
+			params.Pool = nil
+		}
 	}
 
 	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 9005f07..6226548 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -446,7 +446,8 @@
 	if ctx.Config().UseGoma() && r.remoteable.Goma {
 		// When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool.
 	} else if ctx.Config().UseRBE() && r.remoteable.RBE {
-		// When USE_RBE=true is set and the rule is supported by RBE, allow jobs to run outside the local pool.
+		// When USE_RBE=true is set and the rule is supported by RBE, use the remotePool.
+		pool = remotePool
 	} else if r.highmem {
 		pool = highmemPool
 	} else if ctx.Config().UseRemoteBuild() {
diff --git a/android/singleton.go b/android/singleton.go
index 45a9b82..568398c 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -128,10 +128,17 @@
 }
 
 func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
-	if s.Config().UseRemoteBuild() && params.Pool == nil {
-		// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
-		// jobs to the local parallelism value
-		params.Pool = localPool
+	if s.Config().UseRemoteBuild() {
+		if params.Pool == nil {
+			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
+			// jobs to the local parallelism value
+			params.Pool = localPool
+		} else if params.Pool == remotePool {
+			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
+			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
+			// parallelism.
+			params.Pool = nil
+		}
 	}
 	rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
 	if s.Config().captureBuild {
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 198108d..fa1e204 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -88,7 +88,8 @@
 //         name: "acme_cc_defaults",
 //         module_type: "cc_defaults",
 //         config_namespace: "acme",
-//         variables: ["board", "feature"],
+//         variables: ["board"],
+//         bool_variables: ["feature"],
 //         properties: ["cflags", "srcs"],
 //     }
 //
@@ -97,10 +98,6 @@
 //         values: ["soc_a", "soc_b"],
 //     }
 //
-//     soong_config_bool_variable {
-//         name: "feature",
-//     }
-//
 // If an acme BoardConfig.mk file contained:
 //
 //     SOONG_CONFIG_NAMESPACES += acme
@@ -149,7 +146,8 @@
 //         name: "acme_cc_defaults",
 //         module_type: "cc_defaults",
 //         config_namespace: "acme",
-//         variables: ["board", "feature"],
+//         variables: ["board"],
+//         bool_variables: ["feature"],
 //         properties: ["cflags", "srcs"],
 //     }
 //
@@ -158,10 +156,6 @@
 //         values: ["soc_a", "soc_b"],
 //     }
 //
-//     soong_config_bool_variable {
-//         name: "feature",
-//     }
-//
 //     acme_cc_defaults {
 //         name: "acme_defaults",
 //         cflags: ["-DGENERIC"],
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 6ad88a2..1cf060d 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -43,7 +43,8 @@
 			name: "acme_test_defaults",
 			module_type: "test_defaults",
 			config_namespace: "acme",
-			variables: ["board", "feature1", "feature2", "FEATURE3"],
+			variables: ["board", "feature1", "FEATURE3"],
+			bool_variables: ["feature2"],
 			properties: ["cflags", "srcs"],
 		}
 
@@ -57,10 +58,6 @@
 		}
 
 		soong_config_bool_variable {
-			name: "feature2",
-		}
-
-		soong_config_bool_variable {
 			name: "FEATURE3",
 		}
 	`
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index aa4f5c5..2d6063d 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -109,6 +109,9 @@
 	// the list of SOONG_CONFIG variables that this module type will read
 	Variables []string
 
+	// the list of boolean SOONG_CONFIG variables that this module type will read
+	Bool_variables []string
+
 	// the list of properties that this module type will extend.
 	Properties []string
 }
@@ -146,6 +149,18 @@
 	}
 	v.ModuleTypes[props.Name] = mt
 
+	for _, name := range props.Bool_variables {
+		if name == "" {
+			return []error{fmt.Errorf("bool_variable name must not be blank")}
+		}
+
+		mt.Variables = append(mt.Variables, &boolVariable{
+			baseVariable: baseVariable{
+				variable: name,
+			},
+		})
+	}
+
 	return nil
 }
 
diff --git a/android/variable.go b/android/variable.go
index 91de956..8357d2f 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -252,6 +252,8 @@
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
+	SamplingPGO  *bool   `json:",omitempty"`
+
 	NativeLineCoverage   *bool    `json:",omitempty"`
 	Native_coverage      *bool    `json:",omitempty"`
 	ClangCoverage        *bool    `json:",omitempty"`
diff --git a/android/vts_config.go b/android/vts_config.go
index 9a1df7c..77fb9fe 100644
--- a/android/vts_config.go
+++ b/android/vts_config.go
@@ -53,7 +53,7 @@
 				fmt.Fprintf(w, "LOCAL_TEST_CONFIG := %s\n",
 					*me.properties.Test_config)
 			}
-			fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts %s\n",
+			fmt.Fprintf(w, "LOCAL_COMPATIBILITY_SUITE := vts10 %s\n",
 				strings.Join(me.properties.Test_suites, " "))
 		},
 	}
@@ -64,7 +64,7 @@
 	me.AddProperties(&me.properties)
 }
 
-// vts_config generates a Vendor Test Suite (VTS) configuration file from the
+// vts_config generates a Vendor Test Suite (VTS10) configuration file from the
 // <test_config> xml file and stores it in a subdirectory of $(HOST_OUT).
 func VtsConfigFactory() Module {
 	module := &VtsConfig{}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 5c15e8e..db1048e 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -22,6 +22,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/java"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -181,6 +182,9 @@
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
 			// we will have foo.apk.apk
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".apk"))
+			if app, ok := fi.module.(*java.AndroidApp); ok && len(app.JniCoverageOutputs()) > 0 {
+				fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " "))
+			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk")
 		} else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest {
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
diff --git a/apex/apex.go b/apex/apex.go
index 46aaa8b..3fd4905 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -95,26 +95,15 @@
 	//
 	m["com.android.adbd"] = []string{
 		"adbd",
-		"bcm_object",
-		"fmtlib",
 		"libadbconnection_server",
 		"libadbd",
 		"libadbd_auth",
 		"libadbd_core",
 		"libadbd_services",
 		"libasyncio",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
 		"libbuildversion",
-		"libc++",
 		"libcap",
-		"libcrypto",
-		"libcrypto_utils",
-		"libcutils",
-		"libcutils_headers",
 		"libdiagnose_usb",
-		"liblog_headers",
 		"libmdnssd",
 		"libminijail",
 		"libminijail_gen_constants",
@@ -126,8 +115,6 @@
 		"libpcre2",
 		"libprocessgroup_headers",
 		"libqemu_pipe",
-		"libsystem_headers",
-		"libutils_headers",
 	}
 	//
 	// Module separator
@@ -136,7 +123,6 @@
 		"art_cmdlineparser_headers",
 		"art_disassembler_headers",
 		"art_libartbase_headers",
-		"bcm_object",
 		"bionic_libc_platform_headers",
 		"core-repackaged-icu4j",
 		"cpp-define-generator-asm-support",
@@ -148,9 +134,7 @@
 		"conscrypt.module.intra.core.api.stubs",
 		"dex2oat_headers",
 		"dt_fd_forward_export",
-		"fmtlib",
 		"icu4c_extra_headers",
-		"jacocoagent",
 		"javavm_headers",
 		"jni_platform_headers",
 		"libPlatformProperties",
@@ -160,15 +144,6 @@
 		"libart_runtime_headers_ndk",
 		"libartd-disassembler",
 		"libasync_safe",
-		"libbacktrace",
-		"libbase",
-		"libbase_headers",
-		"libc++",
-		"libc++_static",
-		"libc++abi",
-		"libc++demangle",
-		"libc_headers",
-		"libcrypto",
 		"libdexfile_all_headers",
 		"libdexfile_external_headers",
 		"libdexfile_support",
@@ -181,7 +156,6 @@
 		"libicuuc_headers",
 		"libicuuc_stubdata",
 		"libjdwp_headers",
-		"liblog_headers",
 		"liblz4",
 		"liblzma",
 		"libmeminfo",
@@ -192,7 +166,6 @@
 		"libopenjdkjvmti_headers",
 		"libperfetto_client_experimental",
 		"libprocinfo",
-		"libprotobuf-cpp-lite",
 		"libunwind_llvm",
 		"libunwindstack",
 		"libv8",
@@ -229,13 +202,10 @@
 		"android.hidl.token@1.0-utils",
 		"avrcp-target-service",
 		"avrcp_headers",
-		"bcm_object",
 		"bluetooth-protos-lite",
 		"bluetooth.mapsapi",
 		"com.android.vcard",
 		"dnsresolver_aidl_interface-V2-java",
-		"fmtlib",
-		"guava",
 		"ipmemorystore-aidl-interfaces-V5-java",
 		"ipmemorystore-aidl-interfaces-java",
 		"internal_include_headers",
@@ -245,9 +215,6 @@
 		"libFraunhoferAAC",
 		"libaudio-a2dp-hw-utils",
 		"libaudio-hearing-aid-hw-utils",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
 		"libbinder_headers",
 		"libbluetooth",
 		"libbluetooth-types",
@@ -269,38 +236,23 @@
 		"libbtdevice",
 		"libbte",
 		"libbtif",
-		"libc++",
 		"libchrome",
-		"libcrypto",
-		"libcutils",
-		"libcutils_headers",
 		"libevent",
 		"libfmq",
 		"libg722codec",
 		"libgtest_prod",
 		"libgui_headers",
-		"libhidlbase",
-		"libhidlbase-impl-internal",
-		"libhidltransport-impl-internal",
-		"libhwbinder-impl-internal",
-		"libjsoncpp",
-		"liblog_headers",
 		"libmedia_headers",
 		"libmodpb64",
 		"libosi",
 		"libprocessgroup",
 		"libprocessgroup_headers",
-		"libprotobuf-cpp-lite",
-		"libprotobuf-java-lite",
-		"libprotobuf-java-micro",
 		"libstagefright_foundation_headers",
 		"libstagefright_headers",
 		"libstatslog",
 		"libstatssocket",
-		"libsystem_headers",
 		"libtinyxml2",
 		"libudrv-uipc",
-		"libutils_headers",
 		"libz",
 		"media_plugin_headers",
 		"net-utils-services-common",
@@ -320,12 +272,8 @@
 	// Module separator
 	//
 	m["com.android.conscrypt"] = []string{
-		"bcm_object",
 		"boringssl_self_test",
-		"libc++",
-		"libcrypto",
 		"libnativehelper_header_only",
-		"libssl",
 		"unsupportedappusage",
 	}
 	//
@@ -365,28 +313,11 @@
 		"android.hidl.memory.token@1.0",
 		"android.hidl.memory@1.0",
 		"android.hidl.safe_union@1.0",
-		"bcm_object",
-		"fmtlib",
 		"gemmlowp_headers",
 		"libarect",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
 		"libbuildversion",
-		"libc++",
-		"libcrypto",
-		"libcrypto_static",
-		"libcutils",
-		"libcutils_headers",
 		"libeigen",
 		"libfmq",
-		"libhidlbase",
-		"libhidlbase-impl-internal",
-		"libhidlmemory",
-		"libhidltransport-impl-internal",
-		"libhwbinder-impl-internal",
-		"libjsoncpp",
-		"liblog_headers",
 		"libmath",
 		"libneuralnetworks_common",
 		"libneuralnetworks_headers",
@@ -394,12 +325,10 @@
 		"libprocessgroup_headers",
 		"libprocpartition",
 		"libsync",
-		"libsystem_headers",
 		"libtextclassifier_hash",
 		"libtextclassifier_hash_headers",
 		"libtextclassifier_hash_static",
 		"libtflite_kernel_utils",
-		"libutils_headers",
 		"philox_random",
 		"philox_random_headers",
 		"tensorflow_headers",
@@ -431,9 +360,7 @@
 		"android.hidl.memory@1.0",
 		"android.hidl.token@1.0",
 		"android.hidl.token@1.0-utils",
-		"bcm_object",
 		"bionic_libc_platform_headers",
-		"fmtlib",
 		"gl_headers",
 		"libEGL",
 		"libEGL_blobCache",
@@ -455,23 +382,14 @@
 		"libaudiopolicy",
 		"libaudioutils",
 		"libaudioutils_fixedfft",
-		"libbacktrace",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
 		"libbinder_headers",
 		"libbluetooth-types-header",
 		"libbufferhub",
 		"libbufferhub_headers",
 		"libbufferhubqueue",
-		"libc++",
-		"libc_headers",
 		"libc_malloc_debug_backtrace",
 		"libcamera_client",
 		"libcamera_metadata",
-		"libcrypto",
-		"libcutils",
-		"libcutils_headers",
 		"libdexfile_external_headers",
 		"libdexfile_support",
 		"libdvr_headers",
@@ -483,14 +401,7 @@
 		"libgui",
 		"libgui_headers",
 		"libhardware_headers",
-		"libhidlbase",
-		"libhidlbase-impl-internal",
-		"libhidlmemory",
-		"libhidltransport-impl-internal",
-		"libhwbinder-impl-internal",
 		"libinput",
-		"libjsoncpp",
-		"liblog_headers",
 		"liblzma",
 		"libmath",
 		"libmedia",
@@ -538,11 +449,9 @@
 		"libstagefright_mpeg2extractor",
 		"libstagefright_mpeg2support",
 		"libsync",
-		"libsystem_headers",
 		"libui",
 		"libui_headers",
 		"libunwindstack",
-		"libutils_headers",
 		"libvibrator",
 		"libvorbisidec",
 		"libwavextractor",
@@ -582,7 +491,6 @@
 		"android.hidl.safe_union@1.0",
 		"android.hidl.token@1.0",
 		"android.hidl.token@1.0-utils",
-		"fmtlib",
 		"libEGL",
 		"libFLAC",
 		"libFLAC-config",
@@ -599,15 +507,10 @@
 		"libavcenc",
 		"libavservices_minijail",
 		"libavservices_minijail",
-		"libbacktrace",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
 		"libbinder_headers",
 		"libbinderthreadstateutils",
 		"libbluetooth-types-header",
 		"libbufferhub_headers",
-		"libc++",
 		"libc_scudo",
 		"libcap",
 		"libcodec2",
@@ -647,8 +550,6 @@
 		"libcodec2_soft_vp9dec",
 		"libcodec2_soft_vp9enc",
 		"libcodec2_vndk",
-		"libcutils",
-		"libcutils_headers",
 		"libdexfile_support",
 		"libdvr_headers",
 		"libfmq",
@@ -664,15 +565,8 @@
 		"libhardware_headers",
 		"libhevcdec",
 		"libhevcenc",
-		"libhidlbase",
-		"libhidlbase-impl-internal",
-		"libhidlmemory",
-		"libhidltransport-impl-internal",
-		"libhwbinder-impl-internal",
 		"libion",
 		"libjpeg",
-		"libjsoncpp",
-		"liblog_headers",
 		"liblzma",
 		"libmath",
 		"libmedia_codecserviceregistrant",
@@ -710,11 +604,9 @@
 		"libstagefright_m4vh263enc",
 		"libstagefright_mp3dec",
 		"libsync",
-		"libsystem_headers",
 		"libui",
 		"libui_headers",
 		"libunwindstack",
-		"libutils_headers",
 		"libvorbisidec",
 		"libvpx",
 		"libyuv",
@@ -730,7 +622,6 @@
 		"MediaProvider",
 		"MediaProviderGoogle",
 		"fmtlib_ndk",
-		"guava",
 		"libbase_ndk",
 		"libfuse",
 		"libfuse_jni",
@@ -754,7 +645,6 @@
 		"kotlinx-coroutines-android-nodeps",
 		"kotlinx-coroutines-core",
 		"kotlinx-coroutines-core-nodeps",
-		"libprotobuf-java-lite",
 		"permissioncontroller-statsd",
 	}
 	//
@@ -762,14 +652,9 @@
 	//
 	m["com.android.runtime"] = []string{
 		"bionic_libc_platform_headers",
-		"fmtlib",
 		"libarm-optimized-routines-math",
 		"libasync_safe",
 		"libasync_safe_headers",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
-		"libc++",
 		"libc_aeabi",
 		"libc_bionic",
 		"libc_bionic_ndk",
@@ -783,7 +668,6 @@
 		"libc_freebsd",
 		"libc_freebsd_large_stack",
 		"libc_gdtoa",
-		"libc_headers",
 		"libc_init_dynamic",
 		"libc_init_static",
 		"libc_jemalloc_wrapper",
@@ -798,8 +682,6 @@
 		"libc_syscalls",
 		"libc_tzcode",
 		"libc_unwind_static",
-		"libcutils",
-		"libcutils_headers",
 		"libdebuggerd",
 		"libdebuggerd_common_headers",
 		"libdebuggerd_handler_core",
@@ -812,7 +694,6 @@
 		"libjemalloc5",
 		"liblinker_main",
 		"liblinker_malloc",
-		"liblog_headers",
 		"liblz4",
 		"liblzma",
 		"libprocessgroup_headers",
@@ -820,11 +701,9 @@
 		"libpropertyinfoparser",
 		"libscudo",
 		"libstdc++",
-		"libsystem_headers",
 		"libsystemproperties",
 		"libtombstoned_client_static",
 		"libunwindstack",
-		"libutils_headers",
 		"libz",
 		"libziparchive",
 	}
@@ -832,34 +711,19 @@
 	// Module separator
 	//
 	m["com.android.resolv"] = []string{
-		"bcm_object",
 		"dnsresolver_aidl_interface-unstable-ndk_platform",
-		"fmtlib",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
-		"libc++",
-		"libcrypto",
-		"libcutils",
-		"libcutils_headers",
 		"libgtest_prod",
-		"libjsoncpp",
-		"liblog_headers",
 		"libnativehelper_header_only",
 		"libnetd_client_headers",
 		"libnetd_resolv",
 		"libnetdutils",
 		"libprocessgroup",
 		"libprocessgroup_headers",
-		"libprotobuf-cpp-lite",
-		"libssl",
 		"libstatslog_resolv",
 		"libstatspush_compat",
 		"libstatssocket",
 		"libstatssocket_headers",
-		"libsystem_headers",
 		"libsysutils",
-		"libutils_headers",
 		"netd_event_listener_interface-ndk_platform",
 		"server_configurable_flags",
 		"stats_proto",
@@ -868,28 +732,13 @@
 	// Module separator
 	//
 	m["com.android.tethering"] = []string{
-		"libbase",
-		"libc++",
 		"libnativehelper_compat_libc++",
 		"android.hardware.tetheroffload.config@1.0",
-		"fmtlib",
-		"libbacktrace_headers",
-		"libbase_headers",
 		"libcgrouprc",
 		"libcgrouprc_format",
-		"libcutils",
-		"libcutils_headers",
-		"libhidlbase",
-		"libhidlbase-impl-internal",
-		"libhidltransport-impl-internal",
-		"libhwbinder-impl-internal",
-		"libjsoncpp",
-		"liblog_headers",
 		"libprocessgroup",
 		"libprocessgroup_headers",
-		"libsystem_headers",
 		"libtetherutilsjni",
-		"libutils_headers",
 		"libvndksupport",
 		"tethering-aidl-interfaces-java",
 	}
@@ -925,20 +774,9 @@
 		"ipmemorystore-aidl-interfaces-V3-java",
 		"ipmemorystore-aidl-interfaces-java",
 		"ksoap2",
-		"libbacktrace_headers",
-		"libbase",
-		"libbase_headers",
-		"libc++",
-		"libcutils",
-		"libcutils_headers",
-		"liblog_headers",
 		"libnanohttpd",
 		"libprocessgroup",
 		"libprocessgroup_headers",
-		"libprotobuf-java-lite",
-		"libprotobuf-java-nano",
-		"libsystem_headers",
-		"libutils_headers",
 		"libwifi-jni",
 		"net-utils-services-common",
 		"netd_aidl_interface-V2-java",
@@ -966,34 +804,14 @@
 	// Module separator
 	//
 	m["com.android.os.statsd"] = []string{
-		"libbacktrace_headers",
-		"libbase_headers",
-		"libc++",
-		"libcutils",
-		"libcutils_headers",
-		"liblog_headers",
 		"libprocessgroup_headers",
 		"libstatssocket",
-		"libsystem_headers",
-		"libutils_headers",
 	}
 	//
 	// Module separator
 	//
 	m[android.AvailableToAnyApex] = []string{
-		"crtbegin_dynamic",
-		"crtbegin_dynamic1",
-		"crtbegin_so",
-		"crtbegin_so1",
-		"crtbegin_static",
-		"crtbrand",
-		"crtend_android",
-		"crtend_so",
 		"libatomic",
-		"libc++_static",
-		"libc++abi",
-		"libc++demangle",
-		"libc_headers",
 		"libclang_rt",
 		"libgcc_stripped",
 		"libprofile-clang-extras",
@@ -1973,10 +1791,14 @@
 	return true
 }
 
+// Function called while walking an APEX's payload dependencies.
+//
+// Return true if the `to` module should be visited, false otherwise.
+type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
+
 // Visit dependencies that contributes to the payload of this APEX
-func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
-	do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
-	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
+func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
+	ctx.WalkDeps(func(child, parent android.Module) bool {
 		am, ok := child.(android.ApexModule)
 		if !ok || !am.CanHaveApexVariants() {
 			return false
@@ -1985,22 +1807,18 @@
 		// Check for the direct dependencies that contribute to the payload
 		if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
 			if dt.payload {
-				do(ctx, parent, am, false /* externalDep */)
-				return true
+				return do(ctx, parent, am, false /* externalDep */)
 			}
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
 			return false
 		}
 
 		// Check for the indirect dependencies if it is considered as part of the APEX
 		if am.ApexName() != "" {
-			do(ctx, parent, am, false /* externalDep */)
-			return true
+			return do(ctx, parent, am, false /* externalDep */)
 		}
 
-		do(ctx, parent, am, true /* externalDep */)
-
-		// As soon as the dependency graph crosses the APEX boundary, don't go further.
-		return false
+		return do(ctx, parent, am, true /* externalDep */)
 	})
 }
 
@@ -2023,24 +1841,43 @@
 		return
 	}
 
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	// Coverage build adds additional dependencies for the coverage-only runtime libraries.
+	// Requiring them and their transitive depencies with apex_available is not right
+	// because they just add noise.
+	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || a.IsNativeCoverageNeeded(ctx) {
+		return
+	}
+
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+		if externalDep {
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
+		}
+
 		apexName := ctx.ModuleName()
 		fromName := ctx.OtherModuleName(from)
 		toName := ctx.OtherModuleName(to)
-		if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
-			return
+		if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
+			return true
 		}
-		ctx.ModuleErrorf("%q requires %q that is not available for the APEX.", fromName, toName)
+		message := ""
+		for _, m := range ctx.GetWalkPath()[1:] {
+			message = fmt.Sprintf("%s\n    -> %s", message, m.String())
+		}
+		ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
+		// Visit this module's dependencies to check and report any issues with their availability.
+		return true
 	})
 }
 
 // Collects the list of module names that directly or indirectly contributes to the payload of this APEX
 func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
 	a.depInfos = make(map[string]depInfo)
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if from.Name() == to.Name() {
 			// This can happen for cc.reuseObjTag. We are not interested in tracking this.
-			return
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return !externalDep
 		}
 
 		if info, exists := a.depInfos[to.Name()]; exists {
@@ -2056,6 +1893,9 @@
 				isExternal: externalDep,
 			}
 		}
+
+		// As soon as the dependency graph crosses the APEX boundary, don't go further.
+		return !externalDep
 	})
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 0bae124..b97e38d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -882,7 +882,7 @@
 		shouldNotLink []string
 	}{
 		{
-			name:          "should link to test latest",
+			name:          "should link to the latest",
 			minSdkVersion: "current",
 			shouldLink:    "30",
 			shouldNotLink: []string{"29"},
@@ -1222,7 +1222,7 @@
 	expectNoLink("libz", "shared", "libz", "shared")
 }
 
-func TestQApexesUseLatestStubsInBundledBuilds(t *testing.T) {
+func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
@@ -1249,16 +1249,18 @@
 				versions: ["29", "30"],
 			},
 		}
-	`)
+	`, func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+	})
 	expectLink := func(from, from_variant, to, to_variant string) {
 		ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
 		libFlags := ld.Args["libFlags"]
 		ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
 	}
-	expectLink("libx", "shared_myapex", "libbar", "shared_30")
+	expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30")
 }
 
-func TestQTargetApexUseStaticUnwinder(t *testing.T) {
+func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
 			name: "myapex",
@@ -1277,8 +1279,7 @@
 			name: "libx",
 			apex_available: [ "myapex" ],
 		}
-
-	`, withUnbundledBuild)
+	`)
 
 	// ensure apex variant of c++ is linked with static unwinder
 	cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module)
@@ -1289,7 +1290,7 @@
 }
 
 func TestInvalidMinSdkVersion(t *testing.T) {
-	testApexError(t, `"libz" .*: min_sdk_version is set 29.*`, `
+	testApexError(t, `"libz" .*: not found a version\(<=29\)`, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1319,9 +1320,9 @@
 				versions: ["30"],
 			},
 		}
-	`, withUnbundledBuild)
+	`)
 
-	testApexError(t, `"myapex" .*: min_sdk_version: should be .*`, `
+	testApexError(t, `"myapex" .*: min_sdk_version: should be "current" or <number>`, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -1842,7 +1843,7 @@
 	// non-APEX variant does not have __ANDROID_APEX__ defined
 	mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
 	ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
-	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
+	ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
 
 	// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
 	mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
@@ -3501,7 +3502,7 @@
 	}`)
 }
 
-func TestApexAvailable(t *testing.T) {
+func TestApexAvailable_DirectDep(t *testing.T) {
 	// libfoo is not available to myapex, but only to otherapex
 	testApexError(t, "requires \"libfoo\" that is not available for the APEX", `
 	apex {
@@ -3534,9 +3535,17 @@
 		system_shared_libs: [],
 		apex_available: ["otherapex"],
 	}`)
+}
 
+func TestApexAvailable_IndirectDep(t *testing.T) {
 	// libbbaz is an indirect dep
-	testApexError(t, "requires \"libbaz\" that is not available for the APEX", `
+	testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path:
+.*-> libfoo.*link:shared.*
+.*-> libfoo.*link:static.*
+.*-> libbar.*link:shared.*
+.*-> libbar.*link:static.*
+.*-> libbaz.*link:shared.*
+.*-> libbaz.*link:static.*`, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -3570,7 +3579,9 @@
 		stl: "none",
 		system_shared_libs: [],
 	}`)
+}
 
+func TestApexAvailable_InvalidApexName(t *testing.T) {
 	testApexError(t, "\"otherapex\" is not a valid module name", `
 	apex {
 		name: "myapex",
@@ -3591,7 +3602,7 @@
 		apex_available: ["otherapex"],
 	}`)
 
-	ctx, _ := testApex(t, `
+	testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -3627,7 +3638,9 @@
 			versions: ["10", "20", "30"],
 		},
 	}`)
+}
 
+func TestApexAvailable_CreatedForPlatform(t *testing.T) {
 	// check that libfoo and libbar are created only for myapex, but not for the platform
 	// TODO(jiyong) the checks for the platform variant are removed because we now create
 	// the platform variant regardless of the apex_availability. Instead, we will make sure that
@@ -3639,7 +3652,7 @@
 	//	ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
 	//	ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
 
-	ctx, _ = testApex(t, `
+	ctx, _ := testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
@@ -3661,8 +3674,10 @@
 	// check that libfoo is created only for the platform
 	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
 	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
+}
 
-	ctx, _ = testApex(t, `
+func TestApexAvailable_CreatedForApex(t *testing.T) {
+	testApex(t, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
diff --git a/apex/builder.go b/apex/builder.go
index 67bc206..5a2134a 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -230,12 +230,16 @@
 func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
 	var noticeFiles android.Paths
 
-	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if externalDep {
-			return
+			// As soon as the dependency graph crosses the APEX boundary, don't go further.
+			return false
 		}
+
 		notices := to.NoticeFiles()
 		noticeFiles = append(noticeFiles, notices...)
+
+		return true
 	})
 
 	if len(noticeFiles) == 0 {
diff --git a/apex/key.go b/apex/key.go
index ffde315..607cac5 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -133,17 +133,18 @@
 		module := apexModulesMap[key]
 		if m, ok := module.(*apexBundle); ok {
 			fmt.Fprintf(&filecontent,
-				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n",
 				m.Name()+".apex",
 				m.public_key_file.String(),
 				m.private_key_file.String(),
 				m.container_certificate_file.String(),
-				m.container_private_key_file.String())
+				m.container_private_key_file.String(),
+				m.PartitionTag(ctx.DeviceConfig()))
 		} else if m, ok := module.(*Prebuilt); ok {
 			fmt.Fprintf(&filecontent,
-				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n",
 				m.InstallFilename(),
-				"PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED")
+				"PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", m.PartitionTag(ctx.DeviceConfig()))
 		}
 	}
 
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 59d1502..4cdfb31 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -60,6 +60,10 @@
 func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	cflags := []string{
 		"-nostdlibinc",
+
+		// Make paths in deps files relative
+		"-no-canonical-prefixes",
+
 		"-O2",
 		"-isystem bionic/libc/include",
 		"-isystem bionic/libc/kernel/uapi",
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 0516279..a1c5de1 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -124,6 +124,10 @@
 		Name: "removeHidlInterfaceTypes",
 		Fix:  removeHidlInterfaceTypes,
 	},
+	{
+		Name: "removeSoongConfigBoolVariable",
+		Fix:  removeSoongConfigBoolVariable,
+	},
 }
 
 func NewFixRequest() FixRequest {
@@ -714,6 +718,78 @@
 	return nil
 }
 
+func removeSoongConfigBoolVariable(f *Fixer) error {
+	found := map[string]bool{}
+	newDefs := make([]parser.Definition, 0, len(f.tree.Defs))
+	for _, def := range f.tree.Defs {
+		if mod, ok := def.(*parser.Module); ok && mod.Type == "soong_config_bool_variable" {
+			if name, ok := getLiteralStringPropertyValue(mod, "name"); ok {
+				found[name] = true
+			} else {
+				return fmt.Errorf("Found soong_config_bool_variable without a name")
+			}
+		} else {
+			newDefs = append(newDefs, def)
+		}
+	}
+	f.tree.Defs = newDefs
+
+	if len(found) == 0 {
+		return nil
+	}
+
+	return runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error {
+		if mod.Type != "soong_config_module_type" {
+			return nil
+		}
+
+		variables, ok := getLiteralListProperty(mod, "variables")
+		if !ok {
+			return nil
+		}
+
+		boolValues := strings.Builder{}
+		empty := true
+		for _, item := range variables.Values {
+			nameValue, ok := item.(*parser.String)
+			if !ok {
+				empty = false
+				continue
+			}
+			if found[nameValue.Value] {
+				patchList.Add(item.Pos().Offset, item.End().Offset+2, "")
+
+				boolValues.WriteString(`"`)
+				boolValues.WriteString(nameValue.Value)
+				boolValues.WriteString(`",`)
+			} else {
+				empty = false
+			}
+		}
+		if empty {
+			*patchList = parser.PatchList{}
+
+			prop, _ := mod.GetProperty("variables")
+			patchList.Add(prop.Pos().Offset, prop.End().Offset+2, "")
+		}
+		if boolValues.Len() == 0 {
+			return nil
+		}
+
+		bool_variables, ok := getLiteralListProperty(mod, "bool_variables")
+		if ok {
+			patchList.Add(bool_variables.RBracePos.Offset, bool_variables.RBracePos.Offset, ","+boolValues.String())
+		} else {
+			patchList.Add(variables.RBracePos.Offset+2, variables.RBracePos.Offset+2,
+				fmt.Sprintf(`bool_variables: [%s],`, boolValues.String()))
+		}
+
+		return nil
+	})(f)
+
+	return nil
+}
+
 // Converts the default source list property, 'srcs', to a single source property with a given name.
 // "LOCAL_MODULE" reference is also resolved during the conversion process.
 func convertToSingleSource(mod *parser.Module, srcPropertyName string) {
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 38cefdd..64a7b93 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -918,3 +918,67 @@
 		})
 	}
 }
+
+func TestRemoveSoongConfigBoolVariable(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		out  string
+	}{
+		{
+			name: "remove bool",
+			in: `
+				soong_config_module_type {
+					name: "foo",
+					variables: ["bar", "baz"],
+				}
+
+				soong_config_bool_variable {
+					name: "bar",
+				}
+
+				soong_config_string_variable {
+					name: "baz",
+				}
+			`,
+			out: `
+				soong_config_module_type {
+					name: "foo",
+					variables: [
+						"baz"
+					],
+					bool_variables: ["bar"],
+				}
+
+				soong_config_string_variable {
+					name: "baz",
+				}
+			`,
+		},
+		{
+			name: "existing bool_variables",
+			in: `
+				soong_config_module_type {
+					name: "foo",
+					variables: ["baz"],
+					bool_variables: ["bar"],
+				}
+
+				soong_config_bool_variable {
+					name: "baz",
+				}
+			`,
+			out: `
+				soong_config_module_type {
+					name: "foo",
+					bool_variables: ["bar", "baz"],
+				}
+			`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			runPass(t, test.in, test.out, removeSoongConfigBoolVariable)
+		})
+	}
+}
diff --git a/cc/cc.go b/cc/cc.go
index de07229..c42914b 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -488,6 +488,9 @@
 	makeLinkType string
 	// Kythe (source file indexer) paths for this compilation module
 	kytheFiles android.Paths
+
+	// For apex variants, this is set as apex.min_sdk_version
+	apexSdkVersion int
 }
 
 func (c *Module) Toc() android.OptionalPath {
@@ -583,6 +586,13 @@
 	return c.depsInLinkOrder
 }
 
+func (c *Module) StubsSymbolFile() android.OptionalPath {
+	if library, ok := c.linker.(*libraryDecorator); ok {
+		return library.stubsSymbolFile
+	}
+	return android.OptionalPath{}
+}
+
 func (c *Module) StubsVersions() []string {
 	if c.linker != nil {
 		if library, ok := c.linker.(*libraryDecorator); ok {
@@ -1209,7 +1219,7 @@
 }
 
 func (ctx *moduleContextImpl) apexSdkVersion() int {
-	return ctx.mod.ApexProperties.Info.MinSdkVersion
+	return ctx.mod.apexSdkVersion
 }
 
 func (ctx *moduleContextImpl) hasStubsVariants() bool {
@@ -1847,7 +1857,10 @@
 		}, depTag, lib)
 	}
 
-	if deps.StaticUnwinderIfLegacy && ctx.Config().UnbundledBuild() {
+	// staticUnwinderDep is treated as staticDep for Q apexes
+	// so that native libraries/binaries are linked with static unwinder
+	// because Q libc doesn't have unwinder APIs
+	if deps.StaticUnwinderIfLegacy {
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, staticUnwinderDepTag, staticUnwinder(actx))
@@ -2231,9 +2244,22 @@
 			}
 		}
 
+		// For the dependency from platform to apex, use the latest stubs
+		c.apexSdkVersion = android.FutureApiLevel
+		if !c.IsForPlatform() {
+			c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion
+		}
+
+		if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+			// In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+			// so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+			// (b/144430859)
+			c.apexSdkVersion = android.FutureApiLevel
+		}
+
 		if depTag == staticUnwinderDepTag {
-			// Use static unwinder for legacy (min_sdk_version = 29) apexes  (b/144430859)
-			if c.ShouldSupportAndroid10() {
+			// Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
+			if c.apexSdkVersion <= android.SdkVersion_Android10 {
 				depTag = StaticDepTag
 			} else {
 				return
@@ -2287,8 +2313,7 @@
 
 				// when to use (unspecified) stubs, check min_sdk_version and choose the right one
 				if useThisDep && depIsStubs && !explicitlyVersioned {
-					useLatest := c.IsForPlatform() || (c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild())
-					versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), useLatest)
+					versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion)
 					if err != nil {
 						ctx.OtherModuleErrorf(dep, err.Error())
 						return
@@ -2311,8 +2336,7 @@
 						// if this is for use_vendor apex && dep has stubsVersions
 						// apply the same rule of apex sdk enforcement to choose right version
 						var err error
-						useLatest := c.ShouldSupportAndroid10() && !ctx.Config().UnbundledBuild()
-						versionToUse, err = c.ChooseSdkVersion(versions, useLatest)
+						versionToUse, err = c.ChooseSdkVersion(versions, c.apexSdkVersion)
 						if err != nil {
 							ctx.OtherModuleErrorf(dep, err.Error())
 							return
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 25225b5..8eb79e3 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -15,9 +15,11 @@
 package config
 
 import (
+	"fmt"
 	"os/exec"
 	"path/filepath"
 	"strings"
+	"sync"
 
 	"android/soong/android"
 )
@@ -89,28 +91,20 @@
 )
 
 func init() {
-	pctx.VariableFunc("macSdkPath", func(ctx android.PackageVarContext) string {
-		xcodeselect := ctx.Config().HostSystemTool("xcode-select")
-		bytes, err := exec.Command(xcodeselect, "--print-path").Output()
-		if err != nil {
-			ctx.Errorf("xcode-select failed with: %q", err.Error())
-		}
-		return strings.TrimSpace(string(bytes))
-	})
 	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
-		return xcrunSdk(ctx, "--show-sdk-path")
+		return getMacTools(ctx).sdkRoot
 	})
 	pctx.StaticVariable("macMinVersion", "10.10")
 	pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
-		return xcrun(ctx, "--find", "ar")
+		return getMacTools(ctx).arPath
 	})
 
 	pctx.VariableFunc("MacStripPath", func(ctx android.PackageVarContext) string {
-		return xcrun(ctx, "--find", "strip")
+		return getMacTools(ctx).stripPath
 	})
 
 	pctx.VariableFunc("MacToolPath", func(ctx android.PackageVarContext) string {
-		return filepath.Dir(xcrun(ctx, "--find", "ld"))
+		return getMacTools(ctx).toolPath
 	})
 
 	pctx.StaticVariable("DarwinGccVersion", darwinGccVersion)
@@ -126,38 +120,66 @@
 	pctx.StaticVariable("DarwinYasmFlags", "-f macho -m amd64")
 }
 
-func xcrun(ctx android.PackageVarContext, args ...string) string {
-	xcrun := ctx.Config().HostSystemTool("xcrun")
-	bytes, err := exec.Command(xcrun, args...).Output()
-	if err != nil {
-		ctx.Errorf("xcrun failed with: %q", err.Error())
-	}
-	return strings.TrimSpace(string(bytes))
+type macPlatformTools struct {
+	once sync.Once
+	err  error
+
+	sdkRoot   string
+	arPath    string
+	stripPath string
+	toolPath  string
 }
 
-func xcrunSdk(ctx android.PackageVarContext, arg string) string {
-	xcrun := ctx.Config().HostSystemTool("xcrun")
-	if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" {
-		if !inList(selected, darwinSupportedSdkVersions) {
-			ctx.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+var macTools = &macPlatformTools{}
+
+func getMacTools(ctx android.PackageVarContext) *macPlatformTools {
+	macTools.once.Do(func() {
+		xcrunTool := ctx.Config().HostSystemTool("xcrun")
+
+		xcrun := func(args ...string) string {
+			if macTools.err != nil {
+				return ""
+			}
+
+			bytes, err := exec.Command(xcrunTool, args...).Output()
+			if err != nil {
+				macTools.err = fmt.Errorf("xcrun %q failed with: %q", args, err)
+				return ""
+			}
+
+			return strings.TrimSpace(string(bytes))
+		}
+
+		xcrunSdk := func(arg string) string {
+			if selected := ctx.Config().Getenv("MAC_SDK_VERSION"); selected != "" {
+				if !inList(selected, darwinSupportedSdkVersions) {
+					macTools.err = fmt.Errorf("MAC_SDK_VERSION %s isn't supported: %q", selected, darwinSupportedSdkVersions)
+					return ""
+				}
+
+				return xcrun("--sdk", "macosx"+selected, arg)
+			}
+
+			for _, sdk := range darwinSupportedSdkVersions {
+				bytes, err := exec.Command(xcrunTool, "--sdk", "macosx"+sdk, arg).Output()
+				if err == nil {
+					return strings.TrimSpace(string(bytes))
+				}
+			}
+			macTools.err = fmt.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
 			return ""
 		}
 
-		bytes, err := exec.Command(xcrun, "--sdk", "macosx"+selected, arg).Output()
-		if err != nil {
-			ctx.Errorf("MAC_SDK_VERSION %s is not installed", selected)
-		}
-		return strings.TrimSpace(string(bytes))
-	}
+		macTools.sdkRoot = xcrunSdk("--show-sdk-path")
 
-	for _, sdk := range darwinSupportedSdkVersions {
-		bytes, err := exec.Command(xcrun, "--sdk", "macosx"+sdk, arg).Output()
-		if err == nil {
-			return strings.TrimSpace(string(bytes))
-		}
+		macTools.arPath = xcrun("--find", "ar")
+		macTools.stripPath = xcrun("--find", "strip")
+		macTools.toolPath = filepath.Dir(xcrun("--find", "ld"))
+	})
+	if macTools.err != nil {
+		ctx.Errorf("%q", macTools.err)
 	}
-	ctx.Errorf("Could not find a supported mac sdk: %q", darwinSupportedSdkVersions)
-	return ""
+	return macTools
 }
 
 type toolchainDarwin struct {
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 6a9b709..b7173a3 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -198,6 +198,11 @@
 	return installLocation
 }
 
+// Get the device-only shared library symbols install directory.
+func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, archString string) string {
+	return filepath.Join("$(PRODUCT_OUT)/symbols/data/fuzz/", archString, "/lib/", libraryPath.Base())
+}
+
 func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
 	fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
 		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -269,6 +274,12 @@
 		fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
 			sharedLibraryInstallLocation(
 				lib, ctx.Host(), ctx.Arch().ArchType.String()))
+
+		// Also add the dependency on the shared library symbols dir.
+		if !ctx.Host() {
+			fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+				sharedLibrarySymbolsInstallLocation(lib, ctx.Arch().ArchType.String()))
+		}
 	}
 }
 
@@ -419,12 +430,24 @@
 				continue
 			}
 			sharedLibraryInstalled[installDestination] = true
+
 			// Escape all the variables, as the install destination here will be called
 			// via. $(eval) in Make.
 			installDestination = strings.ReplaceAll(
 				installDestination, "$", "$$")
 			s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
 				library.String()+":"+installDestination)
+
+			// Ensure that on device, the library is also reinstalled to the /symbols/
+			// dir. Symbolized DSO's are always installed to the device when fuzzing, but
+			// we want symbolization tools (like `stack`) to be able to find the symbols
+			// in $ANDROID_PRODUCT_OUT/symbols automagically.
+			if !ccModule.Host() {
+				symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
+				symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
+				s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
+					library.String()+":"+symbolsInstallDestination)
+			}
 		}
 
 		// The executable.
diff --git a/cc/library.go b/cc/library.go
index cd64fd1..26e86f9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -367,6 +367,9 @@
 	// Location of the file that should be copied to dist dir when requested
 	distFile android.OptionalPath
 
+	// stubs.symbol_file
+	stubsSymbolFile android.OptionalPath
+
 	versionScriptPath android.ModuleGenPath
 
 	post_install_cmds []string
@@ -376,7 +379,7 @@
 	useCoreVariant       bool
 	checkSameCoreVariant bool
 
-	// Decorated interafaces
+	// Decorated interfaces
 	*baseCompiler
 	*baseLinker
 	*baseInstaller
@@ -603,6 +606,7 @@
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	if library.buildStubs() {
+		library.stubsSymbolFile = android.OptionalPathForModuleSrc(ctx, library.Properties.Stubs.Symbol_file)
 		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex")
 		library.versionScriptPath = versionScript
 		return objs
@@ -1024,8 +1028,9 @@
 }
 
 func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android.Path {
+	// The logic must be consistent with classifySourceAbiDump.
 	isNdk := ctx.isNdk()
-	isLlndkOrVndk := ctx.isLlndkPublic(ctx.Config()) || ctx.isVndk()
+	isLlndkOrVndk := ctx.isLlndkPublic(ctx.Config()) || (ctx.useVndk() && ctx.isVndk())
 
 	refAbiDumpTextFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, false)
 	refAbiDumpGzipFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, isNdk, isLlndkOrVndk, true)
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 0a11af1..4e4df5b 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -269,12 +269,21 @@
 	for property, dirs := range includeDirs {
 		outputProperties.AddProperty(property, dirs)
 	}
+
+	if len(libInfo.StubsVersion) > 0 {
+		symbolFilePath := filepath.Join(nativeEtcDir, libInfo.StubsSymbolFile.Path().Base())
+		builder.CopyToSnapshot(libInfo.StubsSymbolFile.Path(), symbolFilePath)
+		stubsSet := outputProperties.AddPropertySet("stubs")
+		stubsSet.AddProperty("symbol_file", symbolFilePath)
+		stubsSet.AddProperty("versions", []string{libInfo.StubsVersion})
+	}
 }
 
 const (
 	nativeIncludeDir          = "include"
 	nativeGeneratedIncludeDir = "include_gen"
 	nativeStubDir             = "lib"
+	nativeEtcDir              = "etc"
 )
 
 // path to the native library. Relative to <sdk_root>/<api_dir>
@@ -335,6 +344,13 @@
 	// This field is exported as its contents may not be arch specific.
 	SystemSharedLibs []string
 
+	// The specific stubs version for the lib variant, or empty string if stubs
+	// are not in use.
+	StubsVersion string
+
+	// The stubs symbol file.
+	StubsSymbolFile android.OptionalPath
+
 	// outputFile is not exported as it is always arch specific.
 	outputFile android.Path
 }
@@ -370,6 +386,11 @@
 		p.SystemSharedLibs = specifiedDeps.systemSharedLibs
 	}
 	p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+
+	if ccModule.HasStubsVariants() {
+		p.StubsVersion = ccModule.StubsVersion()
+		p.StubsSymbolFile = ccModule.StubsSymbolFile()
+	}
 }
 
 func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
diff --git a/cc/pgo.go b/cc/pgo.go
index d5c4b87..88903bb 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -88,20 +88,21 @@
 	return []interface{}{&pgo.Properties}
 }
 
-func (props *PgoProperties) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
 
-	if props.isInstrumentation() {
-		flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
-		// The profile runtime is added below in deps().  Add the below
-		// flag, which is the only other link-time action performed by
-		// the Clang driver during link.
-		flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
-	}
-	if props.isSampling() {
-		flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
-	}
+	flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
+	// The profile runtime is added below in deps().  Add the below
+	// flag, which is the only other link-time action performed by
+	// the Clang driver during link.
+	flags.Local.LdFlags = append(flags.Local.LdFlags, "-u__llvm_profile_runtime")
+	return flags
+}
+func (props *PgoProperties) addSamplingProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+	flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
+
+	flags.Local.CFlags = append(flags.Local.CFlags, profileSamplingFlag)
+	flags.Local.LdFlags = append(flags.Local.LdFlags, profileSamplingFlag)
 	return flags
 }
 
@@ -286,8 +287,12 @@
 	props := pgo.Properties
 
 	// Add flags to profile this module based on its profile_kind
-	if props.ShouldProfileModule {
-		return props.addProfileGatherFlags(ctx, flags)
+	if props.ShouldProfileModule && props.isInstrumentation() {
+		return props.addInstrumentationProfileGatherFlags(ctx, flags)
+	} else if props.ShouldProfileModule && props.isSampling() {
+		return props.addSamplingProfileGatherFlags(ctx, flags)
+	} else if ctx.DeviceConfig().SamplingPGO() {
+		return props.addSamplingProfileGatherFlags(ctx, flags)
 	}
 
 	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 242d835..0b018c1 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -22,6 +22,25 @@
 	"github.com/google/blueprint"
 )
 
+func testPrebuilt(t *testing.T, bp string, fs map[string][]byte) *android.TestContext {
+	config := TestConfig(buildDir, android.Android, nil, bp, fs)
+	ctx := CreateTestContext()
+
+	// Enable androidmk support.
+	// * Register the singleton
+	// * Configure that we are inside make
+	// * Add CommonOS to ensure that androidmk processing works.
+	android.RegisterAndroidMkBuildComponents(ctx)
+	android.SetInMakeForTests(config)
+
+	ctx.Register(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+	return ctx
+}
+
 func TestPrebuilt(t *testing.T) {
 	bp := `
 		cc_library {
@@ -84,7 +103,15 @@
 		}
 	`
 
-	ctx := testPrebuilt(t, bp)
+	ctx := testPrebuilt(t, bp, map[string][]byte{
+		"liba.so": nil,
+		"libb.a":  nil,
+		"libd.so": nil,
+		"libe.a":  nil,
+		"libf.a":  nil,
+		"libf.so": nil,
+		"crtx.o":  nil,
+	})
 
 	// Verify that all the modules exist and that their dependencies were connected correctly
 	liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
@@ -143,35 +170,6 @@
 	}
 }
 
-func testPrebuilt(t *testing.T, bp string) *android.TestContext {
-
-	fs := map[string][]byte{
-		"liba.so": nil,
-		"libb.a":  nil,
-		"libd.so": nil,
-		"libe.a":  nil,
-		"libf.a":  nil,
-		"libf.so": nil,
-		"crtx.o":  nil,
-	}
-	config := TestConfig(buildDir, android.Android, nil, bp, fs)
-	ctx := CreateTestContext()
-
-	// Enable androidmk support.
-	// * Register the singleton
-	// * Configure that we are inside make
-	// * Add CommonOS to ensure that androidmk processing works.
-	android.RegisterAndroidMkBuildComponents(ctx)
-	android.SetInMakeForTests(config)
-
-	ctx.Register(config)
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-	return ctx
-}
-
 func TestPrebuiltLibraryShared(t *testing.T) {
 	ctx := testPrebuilt(t, `
 	cc_prebuilt_library_shared {
@@ -181,7 +179,9 @@
         none: true,
     },
 	}
-	`)
+	`, map[string][]byte{
+		"libf.so": nil,
+	})
 
 	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
 	assertString(t, shared.OutputFile().String(), "libf.so")
@@ -193,7 +193,9 @@
 		name: "libtest",
 		srcs: ["libf.a"],
 	}
-	`)
+	`, map[string][]byte{
+		"libf.a": nil,
+	})
 
 	static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
 	assertString(t, static.OutputFile().String(), "libf.a")
@@ -213,7 +215,10 @@
         none: true,
     },
 	}
-	`)
+	`, map[string][]byte{
+		"libf.a":  nil,
+		"libf.so": nil,
+	})
 
 	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
 	assertString(t, shared.OutputFile().String(), "libf.so")
diff --git a/cc/testing.go b/cc/testing.go
index b8a7eab..f85795b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -67,6 +67,20 @@
 			src: "",
 		}
 
+		cc_prebuilt_library_shared {
+			name: "libclang_rt.hwasan-aarch64-android",
+			nocrt: true,
+			vendor_available: true,
+			recovery_available: true,
+			system_shared_libs: [],
+			stl: "none",
+			srcs: [""],
+			check_elf_files: false,
+			sanitize: {
+				never: true,
+			},
+		}
+
 		toolchain_library {
 			name: "libclang_rt.builtins-i686-android",
 			vendor_available: true,
@@ -215,6 +229,10 @@
 			vendor_available: true,
 			recovery_available: true,
 			host_supported: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
 		}
 		cc_library {
 			name: "libc++",
@@ -243,6 +261,10 @@
 			host_supported: false,
 			vendor_available: true,
 			recovery_available: true,
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
 		}
 		cc_library {
 			name: "libunwind_llvm",
@@ -254,8 +276,21 @@
 			recovery_available: true,
 		}
 
+		cc_defaults {
+			name: "crt_defaults",
+			recovery_available: true,
+			vendor_available: true,
+			native_bridge_supported: true,
+			stl: "none",
+			apex_available: [
+				"//apex_available:platform",
+				"//apex_available:anyapex",
+			],
+		}
+
 		cc_object {
 			name: "crtbegin_so",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -264,6 +299,7 @@
 
 		cc_object {
 			name: "crtbegin_dynamic",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -272,6 +308,7 @@
 
 		cc_object {
 			name: "crtbegin_static",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -280,6 +317,7 @@
 
 		cc_object {
 			name: "crtend_so",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
@@ -288,6 +326,7 @@
 
 		cc_object {
 			name: "crtend_android",
+			defaults: ["crt_defaults"],
 			recovery_available: true,
 			vendor_available: true,
 			native_bridge_supported: true,
diff --git a/java/androidmk.go b/java/androidmk.go
index a220cce..136bb36 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -72,6 +72,7 @@
 	if !hideFromMake {
 		mainEntries = android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
+			DistFile:   android.OptionalPathForPath(library.distFile),
 			OutputFile: android.OptionalPathForPath(library.outputFile),
 			Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
@@ -275,7 +276,7 @@
 }
 
 func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries {
-	if !app.IsForPlatform() {
+	if !app.IsForPlatform() || app.appProperties.HideFromMake {
 		return []android.AndroidMkEntries{android.AndroidMkEntries{
 			Disabled: true,
 		}}
@@ -288,6 +289,7 @@
 			func(entries *android.AndroidMkEntries) {
 				// App module names can be overridden.
 				entries.SetString("LOCAL_MODULE", app.installApkName)
+				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall)
 				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage)
 				if app.dexJarFile != nil {
 					entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile)
@@ -347,6 +349,9 @@
 				for _, jniLib := range app.installJniLibs {
 					entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name)
 				}
+				if len(app.jniCoverageOutputs) > 0 {
+					entries.AddStrings("LOCAL_PREBUILT_COVERAGE_ARCHIVE", app.jniCoverageOutputs.Strings()...)
+				}
 				if len(app.dexpreopter.builtInstalled) > 0 {
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", app.dexpreopter.builtInstalled)
 				}
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index acc6bf0..7daa624 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -133,3 +134,38 @@
 		t.Errorf("Unexpected required modules - expected: %q, actual: %q", expected, actual)
 	}
 }
+
+func TestDistWithTag(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_library {
+			name: "foo_without_tag",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dist: {
+				targets: ["hi"],
+			},
+		}
+		java_library {
+			name: "foo_with_tag",
+			srcs: ["a.java"],
+			compile_dex: true,
+			dist: {
+				targets: ["hi"],
+				tag: ".jar",
+			},
+		}
+	`)
+
+	without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module())
+	with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module())
+
+	if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 {
+		t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries))
+	}
+	if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") {
+		t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile)
+	}
+	if without_tag_entries[0].DistFile.Valid() {
+		t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile)
+	}
+}
diff --git a/java/app.go b/java/app.go
index e278b9c..0a4d9e4 100755
--- a/java/app.go
+++ b/java/app.go
@@ -105,6 +105,11 @@
 	// If set, find and merge all NOTICE files that this module and its dependencies have and store
 	// it in the APK as an asset.
 	Embed_notices *bool
+
+	// cc.Coverage related properties
+	PreventInstall    bool `blueprint:"mutated"`
+	HideFromMake      bool `blueprint:"mutated"`
+	IsCoverageVariant bool `blueprint:"mutated"`
 }
 
 // android_app properties that can be overridden by override_android_app
@@ -133,7 +138,8 @@
 
 	overridableAppProperties overridableAppProperties
 
-	installJniLibs []jniLib
+	installJniLibs     []jniLib
+	jniCoverageOutputs android.Paths
 
 	bundleFile android.Path
 
@@ -171,6 +177,10 @@
 	return a.certificate
 }
 
+func (a *AndroidApp) JniCoverageOutputs() android.Paths {
+	return a.jniCoverageOutputs
+}
+
 var _ AndroidLibraryDependency = (*AndroidApp)(nil)
 
 type Certificate struct {
@@ -373,6 +383,11 @@
 		if a.shouldEmbedJnis(ctx) {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
 			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
+			for _, jni := range jniLibs {
+				if jni.coverageFile.Valid() {
+					a.jniCoverageOutputs = append(a.jniCoverageOutputs, jni.coverageFile.Path())
+				}
+			}
 		} else {
 			a.installJniLibs = jniLibs
 		}
@@ -589,9 +604,10 @@
 
 				if lib.Valid() {
 					jniLibs = append(jniLibs, jniLib{
-						name:   ctx.OtherModuleName(module),
-						path:   path,
-						target: module.Target(),
+						name:         ctx.OtherModuleName(module),
+						path:         path,
+						target:       module.Target(),
+						coverageFile: dep.CoverageOutputFile(),
 					})
 				} else {
 					ctx.ModuleErrorf("dependency %q missing output file", otherName)
@@ -645,6 +661,24 @@
 	return Bool(a.appProperties.Privileged)
 }
 
+func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+	return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+}
+
+func (a *AndroidApp) PreventInstall() {
+	a.appProperties.PreventInstall = true
+}
+
+func (a *AndroidApp) HideFromMake() {
+	a.appProperties.HideFromMake = true
+}
+
+func (a *AndroidApp) MarkAsCoverageVariant(coverage bool) {
+	a.appProperties.IsCoverageVariant = coverage
+}
+
+var _ cc.Coverage = (*AndroidApp)(nil)
+
 // android_app compiles sources and Android resources into an Android application package `.apk` file.
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 40cfe4f..fba0b97 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -127,7 +127,8 @@
 	global := dexpreopt.GetGlobalConfig(ctx)
 	bootImage := defaultBootImageConfig(ctx)
 	dexFiles := bootImage.dexPathsDeps.Paths()
-	dexLocations := bootImage.dexLocationsDeps
+	// The dex locations for all Android variants are identical.
+	dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
 	if global.UseArtImage {
 		bootImage = artBootImageConfig(ctx)
 	}
@@ -155,6 +156,8 @@
 		images = append(images, variant.images)
 		imagesDeps = append(imagesDeps, variant.imagesDeps)
 	}
+	// The image locations for all Android variants are identical.
+	imageLocations := bootImage.getAnyAndroidVariant().imageLocations()
 
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
 
@@ -198,7 +201,7 @@
 		Archs:                   archs,
 		DexPreoptImages:         images,
 		DexPreoptImagesDeps:     imagesDeps,
-		DexPreoptImageLocations: bootImage.imageLocations,
+		DexPreoptImageLocations: imageLocations,
 
 		PreoptBootClassPathDexFiles:     dexFiles,
 		PreoptBootClassPathDexLocations: dexLocations,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index a3b264e..d00864d 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -28,28 +29,10 @@
 	android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
 }
 
-// The image "location" is a symbolic path that with multiarchitecture
-// support doesn't really exist on the device. Typically it is
-// /system/framework/boot.art and should be the same for all supported
-// architectures on the device. The concrete architecture specific
-// content actually ends up in a "filename" that contains an
-// architecture specific directory name such as arm, arm64, x86, x86_64.
-//
-// Here are some example values for an x86_64 / x86 configuration:
-//
-// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools
-// will then reconstruct the real path, so the rules must have a dependency on the real path.
-
 // Target-independent description of pre-compiled boot image.
 type bootImageConfig struct {
-	// Whether this image is an extension.
-	extension bool
+	// If this image is an extension, the image that it extends.
+	extends *bootImageConfig
 
 	// Image name (used in directory names and ninja rule names).
 	name string
@@ -69,17 +52,10 @@
 	// The names of jars that constitute this image.
 	modules []string
 
-	// The "locations" of jars.
-	dexLocations     []string // for this image
-	dexLocationsDeps []string // for the dependency images and in this image
-
 	// File paths to jars.
 	dexPaths     android.WritablePaths // for this image
 	dexPathsDeps android.WritablePaths // for the dependency images and in this image
 
-	// The "locations" of the dependency images and in this image.
-	imageLocations []string
-
 	// File path to a zip archive with all image files (or nil, if not needed).
 	zip android.WritablePath
 
@@ -97,6 +73,10 @@
 	// Target for which the image is generated.
 	target android.Target
 
+	// The "locations" of jars.
+	dexLocations     []string // for this image
+	dexLocationsDeps []string // for the dependency images and in this image
+
 	// Paths to image files.
 	images     android.OutputPath  // first image file
 	imagesDeps android.OutputPaths // all files
@@ -119,13 +99,23 @@
 	return nil
 }
 
+// Return any (the first) variant which is for the device (as opposed to for the host)
+func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant {
+	for _, variant := range image.variants {
+		if variant.target.Os == android.Android {
+			return variant
+		}
+	}
+	return nil
+}
+
 func (image bootImageConfig) moduleName(idx int) string {
 	// Dexpreopt on the boot class path produces multiple files. The first dex file
 	// is converted into 'name'.art (to match the legacy assumption that 'name'.art
 	// exists), and the rest are converted to 'name'-<jar>.art.
 	m := image.modules[idx]
 	name := image.stem
-	if idx != 0 || image.extension {
+	if idx != 0 || image.extends != nil {
 		name += "-" + stemOf(m)
 	}
 	return name
@@ -150,6 +140,24 @@
 	return ret
 }
 
+// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
+// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the
+// same for all supported architectures on the device. The concrete architecture specific files
+// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64.
+//
+// For example a physical file
+// "/apex/com.android.art/javalib/x86/boot.art" has "image location"
+// "/apex/com.android.art/javalib/boot.art" (which is not an actual file).
+//
+// The location is passed as an argument to the ART tools like dex2oat instead of the real path.
+// ART tools will then reconstruct the architecture-specific real path.
+func (image *bootImageVariant) imageLocations() (imageLocations []string) {
+	if image.extends != nil {
+		imageLocations = image.extends.getVariant(image.target).imageLocations()
+	}
+	return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType))
+}
+
 func concat(lists ...[]string) []string {
 	var size int
 	for _, l := range lists {
@@ -274,6 +282,7 @@
 
 	profile := bootImageProfileRule(ctx, image, missingDeps)
 	bootFrameworkProfileRule(ctx, image, missingDeps)
+	updatableBcpPackagesRule(ctx, image, missingDeps)
 
 	var allFiles android.Paths
 	for _, variant := range image.variants {
@@ -351,7 +360,7 @@
 		cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path())
 	}
 
-	if image.extension {
+	if image.extends != nil {
 		artImage := image.primaryImages
 		cmd.
 			Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
@@ -478,7 +487,7 @@
 			Tool(globalSoong.Profman).
 			FlagWithInput("--create-profile-from=", bootImageProfile).
 			FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
-			FlagForEachArg("--dex-location=", image.dexLocationsDeps).
+			FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
 			FlagWithOutput("--reference-profile-file=", profile)
 
 		rule.Install(profile, "/system/etc/boot-image.prof")
@@ -529,7 +538,7 @@
 			Flag("--generate-boot-profile").
 			FlagWithInput("--create-profile-from=", bootFrameworkProfile).
 			FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
-			FlagForEachArg("--dex-location=", image.dexLocationsDeps).
+			FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
 			FlagWithOutput("--reference-profile-file=", profile)
 
 		rule.Install(profile, "/system/etc/boot-image.bprof")
@@ -542,6 +551,61 @@
 
 var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule")
 
+func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
+	if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+		return nil
+	}
+
+	return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} {
+		global := dexpreopt.GetGlobalConfig(ctx)
+		updatableModules := dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)
+
+		// Collect `permitted_packages` for updatable boot jars.
+		var updatablePackages []string
+		ctx.VisitAllModules(func(module android.Module) {
+			if j, ok := module.(*Library); ok {
+				name := ctx.ModuleName(module)
+				if i := android.IndexList(name, updatableModules); i != -1 {
+					pp := j.properties.Permitted_packages
+					if len(pp) > 0 {
+						updatablePackages = append(updatablePackages, pp...)
+					} else {
+						ctx.Errorf("Missing permitted_packages for %s", name)
+					}
+					// Do not match the same library repeatedly.
+					updatableModules = append(updatableModules[:i], updatableModules[i+1:]...)
+				}
+			}
+		})
+
+		// Sort updatable packages to ensure deterministic ordering.
+		sort.Strings(updatablePackages)
+
+		updatableBcpPackagesName := "updatable-bcp-packages.txt"
+		updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName)
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.WriteFile,
+			Output: updatableBcpPackages,
+			Args: map[string]string{
+				// WriteFile automatically adds the last end-of-line.
+				"content": strings.Join(updatablePackages, "\\n"),
+			},
+		})
+
+		rule := android.NewRuleBuilder()
+		rule.MissingDeps(missingDeps)
+		rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName)
+		// TODO: Rename `profileInstalls` to `extraInstalls`?
+		// Maybe even move the field out of the bootImageConfig into some higher level type?
+		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
+
+		return updatableBcpPackages
+	}).(android.WritablePath)
+}
+
+var updatableBcpPackagesRuleKey = android.NewOnceKey("updatableBcpPackagesRule")
+
 func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) {
 	var allPhonies android.Paths
 	for _, image := range image.variants {
@@ -559,7 +623,7 @@
 			BuiltTool(ctx, "oatdumpd").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
 			FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
-			FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps.Paths()).
+			FlagWithArg("--image=", strings.Join(image.imageLocations(), ":")).Implicits(image.imagesDeps.Paths()).
 			FlagWithOutput("--output=", output).
 			FlagWithArg("--instruction-set=", arch.String())
 		rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
@@ -573,10 +637,7 @@
 			Text("echo").FlagWithArg("Output in ", output.String())
 		rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
 
-		// TODO: We need to make imageLocations per-variant to make oatdump work on host.
-		if image.target.Os == android.Android {
-			allPhonies = append(allPhonies, phony)
-		}
+		allPhonies = append(allPhonies, phony)
 	}
 
 	phony := android.PathForPhony(ctx, "dump-oat-boot")
@@ -612,25 +673,25 @@
 	if image != nil {
 		ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
 		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " "))
-		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " "))
+		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " "))
 
 		var imageNames []string
 		for _, current := range append(d.otherImages, image) {
 			imageNames = append(imageNames, current.name)
-			for _, current := range current.variants {
+			for _, variant := range current.variants {
 				suffix := ""
-				if current.target.Os.Class == android.Host {
+				if variant.target.Os.Class == android.Host {
 					suffix = "_host"
 				}
-				sfx := current.name + suffix + "_" + current.target.Arch.ArchType.String()
-				ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls.String())
-				ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images.String())
-				ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps.Strings(), " "))
-				ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs.String())
-				ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls.String())
+				sfx := variant.name + suffix + "_" + variant.target.Arch.ArchType.String()
+				ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String())
+				ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.images.String())
+				ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " "))
+				ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String())
+				ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String())
 			}
-
-			ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":"))
+			imageLocations := current.getAnyAndroidVariant().imageLocations()
+			ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":"))
 			ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
 		}
 		ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index ffce2a9..1315aba 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -79,6 +79,14 @@
 	return moduleName
 }
 
+func getDexLocation(ctx android.PathContext, target android.Target, subdir string, name string) string {
+	if target.Os.Class == android.Host {
+		return filepath.Join("out", "host", ctx.Config().PrebuiltOS(), subdir, name)
+	} else {
+		return filepath.Join("/", subdir, name)
+	}
+}
+
 var (
 	bootImageConfigKey     = android.NewOnceKey("bootImageConfig")
 	artBootImageName       = "art"
@@ -104,36 +112,23 @@
 		artSubdir := "apex/com.android.art/javalib"
 		frameworkSubdir := "system/framework"
 
-		var artLocations, frameworkLocations []string
-		for _, m := range artModules {
-			artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar"))
-		}
-		for _, m := range frameworkModules {
-			frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar"))
-		}
-
 		// ART config for the primary boot image in the ART apex.
 		// It includes the Core Libraries.
 		artCfg := bootImageConfig{
-			extension:        false,
-			name:             artBootImageName,
-			stem:             "boot",
-			installSubdir:    artSubdir,
-			modules:          artModules,
-			dexLocations:     artLocations,
-			dexLocationsDeps: artLocations,
+			name:          artBootImageName,
+			stem:          "boot",
+			installSubdir: artSubdir,
+			modules:       artModules,
 		}
 
 		// Framework config for the boot image extension.
 		// It includes framework libraries and depends on the ART config.
 		frameworkCfg := bootImageConfig{
-			extension:        true,
-			name:             frameworkBootImageName,
-			stem:             "boot",
-			installSubdir:    frameworkSubdir,
-			modules:          frameworkModules,
-			dexLocations:     frameworkLocations,
-			dexLocationsDeps: append(artLocations, frameworkLocations...),
+			extends:       &artCfg,
+			name:          frameworkBootImageName,
+			stem:          "boot",
+			installSubdir: frameworkSubdir,
+			modules:       frameworkModules,
 		}
 
 		configs := map[string]*bootImageConfig{
@@ -149,8 +144,6 @@
 			// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
 			imageName := c.firstModuleNameOrStem() + ".art"
 
-			c.imageLocations = []string{c.dir.Join(ctx, "android", c.installSubdir, imageName).String()}
-
 			// The path to bootclasspath dex files needs to be known at module
 			// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
 			// Set up known paths for them, the singleton rules will copy them there.
@@ -171,6 +164,10 @@
 					images:          imageDir.Join(ctx, imageName),
 					imagesDeps:      c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
 				}
+				for _, m := range c.modules {
+					variant.dexLocations = append(variant.dexLocations, getDexLocation(ctx, target, c.installSubdir, stemOf(m)+".jar"))
+				}
+				variant.dexLocationsDeps = variant.dexLocations
 				c.variants = append(c.variants, variant)
 			}
 
@@ -181,8 +178,8 @@
 		frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
 		for i := range targets {
 			frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images
+			frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...)
 		}
-		frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
 
 		return configs
 	}).(map[string]*bootImageConfig)
@@ -206,7 +203,7 @@
 			updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p)
 		}
 
-		bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...)
+		bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...)
 		return bootclasspath
 	})
 }
@@ -221,7 +218,7 @@
 
 func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
 	ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":"))
-	ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocationsDeps, ":"))
+	ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":"))
 	ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":"))
 
 	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":"))
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 7e7e955..c7f7cbd 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -211,23 +211,30 @@
 // the greylists.
 func flagsRule(ctx android.SingletonContext) android.Path {
 	var flagsCSV android.Paths
-
-	var greylistIgnoreConflicts android.Path
+	var greylistRemovedApis android.Paths
 
 	ctx.VisitAllModules(func(module android.Module) {
 		if h, ok := module.(hiddenAPIIntf); ok {
 			if csv := h.flagsCSV(); csv != nil {
 				flagsCSV = append(flagsCSV, csv)
 			}
-		} else if ds, ok := module.(*Droidstubs); ok && ctx.ModuleName(module) == "hiddenapi-lists-docs" {
-			greylistIgnoreConflicts = ds.removedDexApiFile
+		} else if ds, ok := module.(*Droidstubs); ok {
+			// Track @removed public and system APIs via corresponding droidstubs targets.
+			// These APIs are not present in the stubs, however, we have to keep allowing access
+			// to them at runtime.
+			if m := ctx.ModuleName(module); m == "api-stubs-docs" || m == "system-api-stubs-docs" {
+				greylistRemovedApis = append(greylistRemovedApis, ds.removedDexApiFile)
+			}
 		}
 	})
 
-	if greylistIgnoreConflicts == nil {
-		ctx.Errorf("failed to find removed_dex_api_filename from hiddenapi-lists-docs module")
-		return nil
-	}
+	combinedRemovedApis := android.PathForOutput(ctx, "hiddenapi", "combined-removed-dex.txt")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.Cat,
+		Inputs:      greylistRemovedApis,
+		Output:      combinedRemovedApis,
+		Description: "Combine removed apis for " + combinedRemovedApis.String(),
+	})
 
 	rule := android.NewRuleBuilder()
 
@@ -242,8 +249,7 @@
 		Inputs(flagsCSV).
 		FlagWithInput("--greylist ",
 			android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")).
-		FlagWithInput("--greylist-ignore-conflicts ",
-			greylistIgnoreConflicts).
+		FlagWithInput("--greylist-ignore-conflicts ", combinedRemovedApis).
 		FlagWithInput("--greylist-max-q ",
 			android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")).
 		FlagWithInput("--greylist-max-p ",
diff --git a/java/java.go b/java/java.go
index 8ce982e..c81b781 100644
--- a/java/java.go
+++ b/java/java.go
@@ -425,6 +425,8 @@
 
 	// list of the xref extraction files
 	kytheFiles android.Paths
+
+	distFile android.Path
 }
 
 func (j *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -544,9 +546,10 @@
 }
 
 type jniLib struct {
-	name   string
-	path   android.Path
-	target android.Target
+	name         string
+	path         android.Path
+	target       android.Target
+	coverageFile android.OptionalPath
 }
 
 func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
@@ -1781,9 +1784,18 @@
 // Java libraries (.jar file)
 //
 
+type LibraryProperties struct {
+	Dist struct {
+		// The tag of the output of this module that should be output.
+		Tag *string `android:"arch_variant"`
+	} `android:"arch_variant"`
+}
+
 type Library struct {
 	Module
 
+	libraryProperties LibraryProperties
+
 	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
 }
 
@@ -1827,6 +1839,15 @@
 		j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
 			ctx.ModuleName()+".jar", j.outputFile, extraInstallDeps...)
 	}
+
+	// Verify Dist.Tag is set to a supported output
+	if j.libraryProperties.Dist.Tag != nil {
+		distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag)
+		if err != nil {
+			ctx.PropertyErrorf("dist.tag", "%s", err.Error())
+		}
+		j.distFile = distFiles[0]
+	}
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1947,7 +1968,8 @@
 		&module.Module.properties,
 		&module.Module.deviceProperties,
 		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties)
+		&module.Module.protoProperties,
+		&module.libraryProperties)
 
 	android.InitApexModule(module)
 	android.InitSdkAwareModule(module)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 6921114..52c9004 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -18,7 +18,6 @@
 	"android/soong/android"
 
 	"fmt"
-	"io"
 	"path"
 	"path/filepath"
 	"sort"
@@ -328,41 +327,6 @@
 	entriesList := module.Library.AndroidMkEntries()
 	entries := &entriesList[0]
 	entries.Required = append(entries.Required, module.xmlFileName())
-
-	entries.ExtraFooters = []android.AndroidMkExtraFootersFunc{
-		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
-			if !Bool(module.sdkLibraryProperties.No_dist) {
-				// Create a phony module that installs the impl library, for the case when this lib is
-				// in PRODUCT_PACKAGES.
-				owner := module.ModuleBase.Owner()
-				if owner == "" {
-					if Bool(module.sdkLibraryProperties.Core_lib) {
-						owner = "core"
-					} else {
-						owner = "android"
-					}
-				}
-
-				// Create dist rules to install the stubs libs and api files to the dist dir
-				for _, apiScope := range module.getActiveApiScopes() {
-					if scopePaths, ok := module.scopePaths[apiScope]; ok {
-						if len(scopePaths.stubsHeaderPath) == 1 {
-							fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-								scopePaths.stubsImplPath.Strings()[0]+
-								":"+path.Join("apistubs", owner, apiScope.name,
-								module.BaseModuleName()+".jar")+")")
-						}
-						if scopePaths.apiFilePath != nil {
-							fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-								scopePaths.apiFilePath.String()+
-								":"+path.Join("apistubs", owner, apiScope.name, "api",
-								module.BaseModuleName()+".txt")+")")
-						}
-					}
-				}
-			}
-		},
-	}
 	return entriesList
 }
 
@@ -386,6 +350,17 @@
 	return module.BaseModuleName() + sdkXmlFileSuffix
 }
 
+// The dist path of the stub artifacts
+func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
+	if module.ModuleBase.Owner() != "" {
+		return path.Join("apistubs", module.ModuleBase.Owner(), apiScope.name)
+	} else if Bool(module.sdkLibraryProperties.Core_lib) {
+		return path.Join("apistubs", "core", apiScope.name)
+	} else {
+		return path.Join("apistubs", "android", apiScope.name)
+	}
+}
+
 // Get the sdk version for use when compiling the stubs library.
 func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -438,6 +413,12 @@
 			Srcs       []string
 			Javacflags []string
 		}
+		Dist struct {
+			Targets []string
+			Dest    *string
+			Dir     *string
+			Tag     *string
+		}
 	}{}
 
 	props.Name = proptools.StringPtr(module.stubsName(apiScope))
@@ -466,6 +447,13 @@
 	} else if module.SystemExtSpecific() {
 		props.System_ext_specific = proptools.BoolPtr(true)
 	}
+	// Dist the class jar artifact for sdk builds.
+	if !Bool(module.sdkLibraryProperties.No_dist) {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.BaseModuleName()))
+		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
+		props.Dist.Tag = proptools.StringPtr(".jar")
+	}
 
 	mctx.CreateModule(LibraryFactory, &props)
 }
@@ -497,6 +485,11 @@
 			Include_dirs       []string
 			Local_include_dirs []string
 		}
+		Dist struct {
+			Targets []string
+			Dest    *string
+			Dir     *string
+		}
 	}{}
 
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
@@ -578,6 +571,13 @@
 		module.latestRemovedApiFilegroupName(apiScope))
 	props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
 
+	// Dist the api txt artifact for sdk builds.
+	if !Bool(module.sdkLibraryProperties.No_dist) {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
+		props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+	}
+
 	mctx.CreateModule(DroidstubsFactory, &props)
 }
 
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 9e97a60..dd0966f 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,2 +1,3 @@
 per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
 per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
+per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index 7e3a82c..35a6ff3 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -58,6 +58,7 @@
 
     "DeviceName": "generic_arm64",
     "HostArch": "x86_64",
+    "HostSecondaryArch": "x86",
     "Aml_abis": true,
 
     "UseGoma": ${USE_GOMA}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 32176e5..9e6086f 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -32,6 +32,7 @@
 		"arm64/include/Arm64Test.h":     nil,
 		"libfoo.so":                     nil,
 		"aidl/foo/bar/Test.aidl":        nil,
+		"some/where/stubslib.map.txt":   nil,
 	}
 	return testSdkWithFs(t, bp, fs)
 }
@@ -1539,6 +1540,9 @@
 }
 
 func TestSystemSharedLibPropagation(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
 	result := testSdkWithCc(t, `
 		sdk {
 			name: "mysdk",
@@ -1736,3 +1740,65 @@
 }
 `))
 }
+
+func TestStubsLibrary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_shared_libs: ["stubslib"],
+		}
+
+		cc_library {
+			name: "stubslib",
+			stubs: {
+				symbol_file: "some/where/stubslib.map.txt",
+				versions: ["1", "2", "3"],
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_stubslib@current",
+    sdk_member_name: "stubslib",
+    installable: false,
+    stubs: {
+        symbol_file: "etc/stubslib.map.txt",
+        versions: ["3"],
+    },
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/stubslib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/stubslib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "stubslib",
+    prefer: false,
+    stubs: {
+        symbol_file: "etc/stubslib.map.txt",
+        versions: ["3"],
+    },
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/stubslib.so"],
+        },
+        arm: {
+            srcs: ["arm/lib/stubslib.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    native_shared_libs: ["mysdk_stubslib@current"],
+}
+`))
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 65dbb22..a2e35d9 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"io"
 	"path"
+	"sync"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -115,6 +116,7 @@
 
 type syspropLibrary struct {
 	android.ModuleBase
+	android.ApexModuleBase
 
 	properties syspropLibraryProperties
 
@@ -154,8 +156,21 @@
 var (
 	pctx         = android.NewPackageContext("android/soong/sysprop")
 	syspropCcTag = dependencyTag{name: "syspropCc"}
+
+	syspropLibrariesKey  = android.NewOnceKey("syspropLibraries")
+	syspropLibrariesLock sync.Mutex
 )
 
+func syspropLibraries(config android.Config) *[]string {
+	return config.Once(syspropLibrariesKey, func() interface{} {
+		return &[]string{}
+	}).(*[]string)
+}
+
+func SyspropLibraries(config android.Config) []string {
+	return append([]string{}, *syspropLibraries(config)...)
+}
+
 func init() {
 	android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
 }
@@ -195,6 +210,10 @@
 	return proptools.Bool(m.properties.Public_stub)
 }
 
+func (m *syspropLibrary) CurrentSyspropApiFile() android.Path {
+	return m.currentApiFile
+}
+
 func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	baseModuleName := m.BaseModuleName()
 
@@ -296,6 +315,7 @@
 		&m.properties,
 	)
 	android.InitAndroidModule(m)
+	android.InitApexModule(m)
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
 	return m
 }
@@ -323,6 +343,7 @@
 	Recovery_available *bool
 	Vendor_available   *bool
 	Host_supported     *bool
+	Apex_available     []string
 }
 
 type javaLibraryProperties struct {
@@ -411,6 +432,7 @@
 	ccProps.Recovery_available = m.properties.Recovery_available
 	ccProps.Vendor_available = m.properties.Vendor_available
 	ccProps.Host_supported = m.properties.Host_supported
+	ccProps.Apex_available = m.ApexProperties.Apex_available
 	ctx.CreateModule(cc.LibraryFactory, &ccProps)
 
 	scope := "internal"
@@ -463,6 +485,12 @@
 			Stem:        proptools.StringPtr(m.BaseModuleName()),
 		})
 	}
+
+	syspropLibrariesLock.Lock()
+	defer syspropLibrariesLock.Unlock()
+
+	libraries := syspropLibraries(ctx.Config())
+	*libraries = append(*libraries, ctx.ModuleName())
 }
 
 func syspropDepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 51da222..8503386 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -15,6 +15,8 @@
 package sysprop
 
 import (
+	"reflect"
+
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/java"
@@ -157,6 +159,7 @@
 	ctx := test(t, `
 		sysprop_library {
 			name: "sysprop-platform",
+			apex_available: ["//apex_available:platform"],
 			srcs: ["android/sysprop/PlatformProperties.sysprop"],
 			api_packages: ["android.sysprop"],
 			property_owner: "Platform",
@@ -305,7 +308,12 @@
 		"android_arm64_armv8-a_shared",
 		"android_arm64_armv8-a_static",
 	} {
-		ctx.ModuleForTests("libsysprop-platform", variant)
+		library := ctx.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
+		expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
+		if !reflect.DeepEqual(library.ApexProperties.Apex_available, expectedApexAvailableOnLibrary) {
+			t.Errorf("apex available property on libsysprop-platform must be %#v, but was %#v.",
+				expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
+		}
 
 		// core variant of vendor-owned sysprop_library is for product
 		ctx.ModuleForTests("libsysprop-vendor", variant)
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 95d049a..0bcdccb 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -99,6 +99,7 @@
 		hostOut("sdk_addon"),
 		hostOut("testcases"),
 		hostOut("vts"),
+		hostOut("vts10"),
 		hostOut("vts-core"),
 		productOut("*.img"),
 		productOut("*.zip"),
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index 2de772b..5ca83cc 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -54,6 +54,9 @@
 
 	working bool
 	group   string
+	srcDir  string
+	outDir  string
+	distDir string
 }
 
 func (c *Cmd) sandboxSupported() bool {
@@ -72,12 +75,20 @@
 			sandboxConfig.group = "nobody"
 		}
 
+		sandboxConfig.srcDir = absPath(c.ctx, ".")
+		sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
+		sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
+
 		cmd := exec.CommandContext(c.ctx.Context, nsjailPath,
 			"-H", "android-build",
 			"-e",
 			"-u", "nobody",
 			"-g", sandboxConfig.group,
-			"-B", "/",
+			"-R", "/",
+			"-B", sandboxConfig.srcDir,
+			"-B", "/tmp",
+			"-B", sandboxConfig.outDir,
+			"-B", sandboxConfig.distDir,
 			"--disable_clone_newcgroup",
 			"--",
 			"/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
@@ -144,8 +155,20 @@
 		"--rlimit_fsize", "soft",
 		"--rlimit_nofile", "soft",
 
-		// For now, just map everything. Eventually we should limit this, especially to make most things readonly.
-		"-B", "/",
+		// For now, just map everything. Make most things readonly.
+		"-R", "/",
+
+		// Mount source are read-write
+		"-B", sandboxConfig.srcDir,
+
+		//Mount out dir as read-write
+		"-B", sandboxConfig.outDir,
+
+		//Mount dist dir as read-write
+		"-B", sandboxConfig.distDir,
+
+		// Mount a writable tmp dir
+		"-B", "/tmp",
 
 		// Disable newcgroup for now, since it may require newer kernels
 		// TODO: try out cgroups