Merge "We now support native code coverage in mixed build."
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index c0f4523..c1e92b8 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -382,15 +382,15 @@
 		defer r.Close()
 
 		mtDef, errs := soongconfig.Parse(r, from)
-		if ctx.Config().BuildMode == Bp2build {
-			ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(*mtDef)
-		}
-
 		if len(errs) > 0 {
 			reportErrors(ctx, from, errs...)
 			return (map[string]blueprint.ModuleFactory)(nil)
 		}
 
+		if ctx.Config().BuildMode == Bp2build {
+			ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(*mtDef)
+		}
+
 		globalModuleTypes := ctx.moduleFactories()
 
 		factories := make(map[string]blueprint.ModuleFactory)
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index a94b2b9..7029b93 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/cc"
+	"fmt"
 	"testing"
 )
 
@@ -36,6 +37,29 @@
 	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
 }
 
+func TestErrorInBpFileDoesNotPanic(t *testing.T) {
+	bp := `
+soong_config_module_type {
+    name: "library_linking_strategy_cc_defaults",
+    module_type: "cc_defaults",
+    config_namespace: "ANDROID",
+    variables: ["library_linking_strategy"],
+    properties: [
+        "shared_libs",
+        "static_libs",
+    ],
+}
+`
+
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for library_linking_strategy",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		ExpectedErr:                fmt.Errorf(`unknown variable "library_linking_strategy" in module type "library_linking_strategy_cc_defaults`),
+	})
+}
+
 func TestSoongConfigModuleType(t *testing.T) {
 	bp := `
 soong_config_module_type {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index eba709b..8e2d161 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -630,15 +630,8 @@
 
 	// Also disable CFI for VNDK variants of components
 	if ctx.isVndk() && ctx.useVndk() {
-		if ctx.static() {
-			// Cfi variant for static vndk should be captured as vendor snapshot,
-			// so don't strictly disable Cfi.
-			s.Cfi = nil
-			s.Diag.Cfi = nil
-		} else {
-			s.Cfi = nil
-			s.Diag.Cfi = nil
-		}
+		s.Cfi = nil
+		s.Diag.Cfi = nil
 	}
 
 	// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
@@ -1067,6 +1060,11 @@
 // as vendor snapshot. Such modules must create both cfi and non-cfi variants,
 // except for ones which explicitly disable cfi.
 func needsCfiForVendorSnapshot(mctx android.BaseModuleContext) bool {
+	if inList("hwaddress", mctx.Config().SanitizeDevice()) {
+		// cfi will not be built if SANITIZE_TARGET=hwaddress is set
+		return false
+	}
+
 	if snapshot.IsVendorProprietaryModule(mctx) {
 		return false
 	}
@@ -1163,10 +1161,12 @@
 		//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
 
 		// Check if it's a snapshot module supporting sanitizer
-		if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) {
-			return []string{"", s.sanitizer.variationName()}
-		} else {
-			return []string{""}
+		if ss, ok := c.linker.(snapshotSanitizer); ok {
+			if ss.isSanitizerAvailable(s.sanitizer) {
+				return []string{"", s.sanitizer.variationName()}
+			} else {
+				return []string{""}
+			}
 		}
 	}
 
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 570300b..32878ca 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -801,6 +801,10 @@
 
 	prebuilt.Init(module, VendorSnapshotImageSingleton, snapshotObjectSuffix)
 	module.AddProperties(&prebuilt.properties)
+
+	// vendor_snapshot_object module does not provide sanitizer variants
+	module.sanitize.Properties.Sanitize.Never = BoolPtr(true)
+
 	return module.Init()
 }
 
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 2dcf26e..9b12bfa 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -93,17 +93,18 @@
 	// Libraries
 	if sanitizable, ok := m.(PlatformSanitizeable); ok && sanitizable.IsSnapshotLibrary() {
 		if sanitizable.SanitizePropDefined() {
-			// scs and hwasan export both sanitized and unsanitized variants for static and header
-			// Always use unsanitized variants of them.
-			for _, t := range []SanitizerType{scs, Hwasan} {
-				if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(t) {
-					return false
-				}
+			// scs exports both sanitized and unsanitized variants for static and header
+			// Always use unsanitized variant of it.
+			if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(scs) {
+				return false
 			}
-			// cfi also exports both variants. But for static, we capture both.
+			// cfi and hwasan also export both variants. But for static, we capture both.
 			// This is because cfi static libraries can't be linked from non-cfi modules,
-			// and vice versa. This isn't the case for scs and hwasan sanitizers.
-			if !sanitizable.Static() && !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(cfi) {
+			// and vice versa.
+			// hwasan is captured as well to support hwasan build.
+			if !sanitizable.Static() &&
+				!sanitizable.Shared() &&
+				(sanitizable.IsSanitizerEnabled(cfi) || sanitizable.IsSanitizerEnabled(Hwasan)) {
 				return false
 			}
 		}
@@ -303,14 +304,22 @@
 				libPath := m.OutputFile().Path()
 				stem = libPath.Base()
 				if sanitizable, ok := m.(PlatformSanitizeable); ok {
-					if (sanitizable.Static() || sanitizable.Rlib()) && sanitizable.SanitizePropDefined() && sanitizable.IsSanitizerEnabled(cfi) {
-						// both cfi and non-cfi variant for static libraries can exist.
-						// attach .cfi to distinguish between cfi and non-cfi.
-						// e.g. libbase.a -> libbase.cfi.a
-						ext := filepath.Ext(stem)
-						stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
-						prop.Sanitize = "cfi"
-						prop.ModuleName += ".cfi"
+					if (sanitizable.Static() || sanitizable.Rlib()) && sanitizable.SanitizePropDefined() {
+						if sanitizable.IsSanitizerEnabled(cfi) {
+							// both cfi and non-cfi variant for static libraries can exist.
+							// attach .cfi to distinguish between cfi and non-cfi.
+							// e.g. libbase.a -> libbase.cfi.a
+							ext := filepath.Ext(stem)
+							stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
+							prop.Sanitize = "cfi"
+							prop.ModuleName += ".cfi"
+						} else if sanitizable.IsSanitizerEnabled(Hwasan) {
+							// Same for the hwasan
+							ext := filepath.Ext(stem)
+							stem = strings.TrimSuffix(stem, ext) + ".hwasan" + ext
+							prop.Sanitize = "hwasan"
+							prop.ModuleName += ".hwasan"
+						}
 					}
 				}
 				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 79405e9..619500e 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -1050,6 +1050,12 @@
 					"libsnapshot",
 					"note_memtag_heap_sync",
 				],
+				objects: [
+					"snapshot_object",
+				],
+				vndk_libs: [
+					"libclang_rt.hwasan",
+				],
 			},
 		},
 	}
@@ -1084,6 +1090,35 @@
 		},
 	}
 
+	vndk_prebuilt_shared {
+		name: "libclang_rt.hwasan",
+		version: "28",
+		target_arch: "arm64",
+		vendor_available: true,
+		product_available: true,
+		vndk: {
+			enabled: true,
+		},
+		arch: {
+			arm64: {
+				srcs: ["libclang_rt.hwasan.so"],
+			},
+		},
+	}
+
+	vendor_snapshot_object {
+		name: "snapshot_object",
+		vendor: true,
+		target_arch: "arm64",
+		version: "28",
+		arch: {
+			arm64: {
+				src: "snapshot_object.o",
+			},
+		},
+		stl: "none",
+	}
+
 	cc_test {
 		name: "vstest",
 		gtest: false,
@@ -1100,15 +1135,18 @@
 	mockFS := map[string][]byte{
 		"vendor/Android.bp":              []byte(bp),
 		"vendor/libc++demangle.a":        nil,
+		"vendor/libclang_rt.hwasan.so":   nil,
 		"vendor/libsnapshot.a":           nil,
 		"vendor/libsnapshot.cfi.a":       nil,
 		"vendor/libsnapshot.hwasan.a":    nil,
 		"vendor/note_memtag_heap_sync.a": nil,
+		"vendor/snapshot_object.o":       nil,
 	}
 
 	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
+	config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
 	ctx := testCcWithConfig(t, config)
 
 	// Check non-cfi, cfi and hwasan variant.
@@ -1130,6 +1168,11 @@
 	if !staticHwasanCfiModule.HiddenFromMake() || !staticHwasanCfiModule.PreventInstall() {
 		t.Errorf("Hwasan and Cfi cannot enabled at the same time.")
 	}
+
+	snapshotObjModule := ctx.ModuleForTests("snapshot_object.vendor_object.28.arm64", "android_vendor.28_arm64_armv8-a").Module()
+	snapshotObjMkEntries := android.AndroidMkEntriesForTest(t, ctx, snapshotObjModule)
+	// snapshot object must not add ".hwasan" suffix
+	assertString(t, snapshotObjMkEntries[0].EntryMap["LOCAL_MODULE"][0], "snapshot_object")
 }
 
 func TestVendorSnapshotExclude(t *testing.T) {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index baad58e..b0660df 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -54,6 +54,7 @@
 func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
 	ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
+	ctx.RegisterModuleType("prebuilt_etc_cacerts", PrebuiltEtcCaCertsFactory)
 	ctx.RegisterModuleType("prebuilt_root", PrebuiltRootFactory)
 	ctx.RegisterModuleType("prebuilt_root_host", PrebuiltRootHostFactory)
 	ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
@@ -455,6 +456,17 @@
 	return module
 }
 
+// prebuilt_etc_host is for a host prebuilt artifact that is installed in
+// <partition>/etc/<sub_dir> directory.
+func PrebuiltEtcCaCertsFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "cacerts")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	android.InitBazelModule(module)
+	return module
+}
+
 // prebuilt_root is for a prebuilt artifact that is installed in
 // <partition>/ directory. Can't have any sub directories.
 func PrebuiltRootFactory() android.Module {
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 1365d4a..e123f24 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -72,6 +72,9 @@
 	// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
 	Avb_algorithm *string
 
+	// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
+	Avb_hash_algorithm *string
+
 	// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
 	Partition_name *string
 
@@ -333,7 +336,11 @@
 		addStr("avb_algorithm", algorithm)
 		key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
 		addPath("avb_key_path", key)
-		addStr("avb_add_hashtree_footer_args", "--do_not_generate_fec")
+		avb_add_hashtree_footer_args := "--do_not_generate_fec"
+		if hashAlgorithm := proptools.String(f.properties.Avb_hash_algorithm); hashAlgorithm != "" {
+			avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
+		}
+		addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args)
 		partitionName := proptools.StringDefault(f.properties.Partition_name, f.Name())
 		addStr("partition_name", partitionName)
 		addStr("avb_salt", f.salt())