Merge "Unless overridden include LICENSE files in notices."
diff --git a/Android.bp b/Android.bp
index 2a4653a..0621475 100644
--- a/Android.bp
+++ b/Android.bp
@@ -207,6 +207,7 @@
         "cc/binary_sdk_member.go",
         "cc/fuzz.go",
         "cc/library.go",
+        "cc/library_headers.go",
         "cc/library_sdk_member.go",
         "cc/object.go",
         "cc/test.go",
@@ -232,6 +233,7 @@
         "cc/compiler_test.go",
         "cc/gen_test.go",
         "cc/genrule_test.go",
+        "cc/library_headers_test.go",
         "cc/library_test.go",
         "cc/object_test.go",
         "cc/prebuilt_test.go",
@@ -534,6 +536,7 @@
         "sdk/update.go",
     ],
     testSrcs: [
+        "sdk/bp_test.go",
         "sdk/cc_sdk_test.go",
         "sdk/exports_test.go",
         "sdk/java_sdk_test.go",
diff --git a/android/module.go b/android/module.go
index 0598ca4..847b02c 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1294,7 +1294,7 @@
 func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { return b.bp.OtherModuleName(m) }
 func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string  { return b.bp.OtherModuleDir(m) }
 func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
-	b.bp.OtherModuleErrorf(m, fmt, args)
+	b.bp.OtherModuleErrorf(m, fmt, args...)
 }
 func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
 	return b.bp.OtherModuleDependencyTag(m)
diff --git a/apex/apex.go b/apex/apex.go
index 42cc9a6..6d4b17b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1280,6 +1280,9 @@
 	// rules for making sure that the APEX is truely updatable. This will also disable the size optimizations
 	// like symlinking to the system libs. Default is false.
 	Updatable *bool
+
+	// The minimum SDK version that this apex must be compatibile with.
+	Min_sdk_version *string
 }
 
 type apexTargetBundleProperties struct {
@@ -2230,7 +2233,8 @@
 						return true // track transitive dependencies
 					}
 				} else if java.IsJniDepTag(depTag) {
-					return true
+					// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
+					return false
 				} else if java.IsXmlPermissionsFileDepTag(depTag) {
 					if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
 						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e694435..10fc8d6 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2871,27 +2871,39 @@
 		android_app {
 			name: "AppFoo",
 			srcs: ["foo/bar/MyClass.java"],
-			sdk_version: "none",
+			sdk_version: "current",
 			system_modules: "none",
 			jni_libs: ["libjni"],
+			stl: "none",
 			apex_available: [ "myapex" ],
 		}
 
 		android_app {
 			name: "AppFooPriv",
 			srcs: ["foo/bar/MyClass.java"],
-			sdk_version: "none",
+			sdk_version: "current",
 			system_modules: "none",
 			privileged: true,
+			stl: "none",
 			apex_available: [ "myapex" ],
 		}
 
 		cc_library_shared {
 			name: "libjni",
 			srcs: ["mylib.cpp"],
+			shared_libs: ["libfoo"],
 			stl: "none",
 			system_shared_libs: [],
 			apex_available: [ "myapex" ],
+			sdk_version: "current",
+		}
+
+		cc_library_shared {
+			name: "libfoo",
+			stl: "none",
+			system_shared_libs: [],
+			apex_available: [ "myapex" ],
+			sdk_version: "current",
 		}
 	`)
 
@@ -2902,16 +2914,19 @@
 	ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk")
 	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk")
 
-	// JNI libraries are embedded inside APK
-	appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni lib")
-	libjniOutput := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
-	ensureListContains(t, appZipRule.Implicits.Strings(), libjniOutput.String())
-	// ... uncompressed
+	appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni libs")
+	// JNI libraries are uncompressed
 	if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") {
-		t.Errorf("jni lib is not uncompressed for AppFoo")
+		t.Errorf("jni libs are not uncompressed for AppFoo")
 	}
-	// ... and not directly inside the APEX
-	ensureNotContains(t, copyCmds, "image.apex/lib64/libjni.so")
+	// JNI libraries including transitive deps are
+	for _, jni := range []string{"libjni", "libfoo"} {
+		jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
+		// ... embedded inside APK (jnilibs.zip)
+		ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
+		// ... and not directly inside the APEX
+		ensureNotContains(t, copyCmds, "image.apex/lib64/"+jni+".so")
+	}
 }
 
 func TestApexWithAppImports(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index b9736d3..9eaf656 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -383,6 +383,16 @@
 
 		targetSdkVersion := ctx.Config().DefaultAppTargetSdk()
 		minSdkVersion := ctx.Config().DefaultAppTargetSdk()
+
+		if proptools.Bool(a.properties.Legacy_android10_support) {
+			if !java.UseApiFingerprint(ctx, targetSdkVersion) {
+				targetSdkVersion = "29"
+			}
+			if !java.UseApiFingerprint(ctx, minSdkVersion) {
+				minSdkVersion = "29"
+			}
+		}
+
 		if java.UseApiFingerprint(ctx, targetSdkVersion) {
 			targetSdkVersion += fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
 			implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
diff --git a/cc/androidmk.go b/cc/androidmk.go
index a78e455..81004da 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -34,7 +34,7 @@
 type AndroidMkContext interface {
 	Name() string
 	Target() android.Target
-	subAndroidMk(*android.AndroidMkData, interface{})
+	subAndroidMk(*android.AndroidMkEntries, interface{})
 	Arch() android.Arch
 	Os() android.OsType
 	Host() bool
@@ -46,29 +46,29 @@
 }
 
 type subAndroidMkProvider interface {
-	AndroidMk(AndroidMkContext, *android.AndroidMkData)
+	AndroidMkEntries(AndroidMkContext, *android.AndroidMkEntries)
 }
 
-func (c *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (c *Module) subAndroidMk(entries *android.AndroidMkEntries, obj interface{}) {
 	if c.subAndroidMkOnce == nil {
 		c.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
 	}
 	if androidmk, ok := obj.(subAndroidMkProvider); ok {
 		if !c.subAndroidMkOnce[androidmk] {
 			c.subAndroidMkOnce[androidmk] = true
-			androidmk.AndroidMk(c, data)
+			androidmk.AndroidMkEntries(c, entries)
 		}
 	}
 }
 
-func (c *Module) AndroidMk() android.AndroidMkData {
+func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
 	if c.Properties.HideFromMake || !c.IsForPlatform() {
-		return android.AndroidMkData{
+		return []android.AndroidMkEntries{{
 			Disabled: true,
-		}
+		}}
 	}
 
-	ret := android.AndroidMkData{
+	entries := android.AndroidMkEntries{
 		OutputFile: c.outputFile,
 		// TODO(jiyong): add the APEXes providing shared libs to the required modules
 		// Currently, adding c.Properties.ApexesProvidingSharedLibs is causing multiple
@@ -77,29 +77,29 @@
 		Required: c.Properties.AndroidMkRuntimeLibs,
 		Include:  "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
 
-		Extra: []android.AndroidMkExtraFunc{
-			func(w io.Writer, outputFile android.Path) {
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
 				if len(c.Properties.Logtags) > 0 {
-					fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES :=", strings.Join(c.Properties.Logtags, " "))
+					entries.AddStrings("LOCAL_LOGTAGS_FILES", c.Properties.Logtags...)
 				}
 				if len(c.Properties.AndroidMkSharedLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES := "+strings.Join(c.Properties.AndroidMkSharedLibs, " "))
+					entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
 				}
 				if len(c.Properties.AndroidMkStaticLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkStaticLibs, " "))
+					entries.AddStrings("LOCAL_STATIC_LIBRARIES", c.Properties.AndroidMkStaticLibs...)
 				}
 				if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
-					fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " "))
+					entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...)
 				}
-				fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.makeLinkType)
+				entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
 				if c.UseVndk() {
-					fmt.Fprintln(w, "LOCAL_USE_VNDK := true")
+					entries.SetBool("LOCAL_USE_VNDK", true)
 					if c.IsVndk() && !c.static() {
-						fmt.Fprintln(w, "LOCAL_SOONG_VNDK_VERSION := "+c.VndkVersion())
+						entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion())
 						// VNDK libraries available to vendor are not installed because
 						// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
 						if !c.isVndkExt() {
-							fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+							entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 						}
 					}
 				}
@@ -108,22 +108,22 @@
 	}
 
 	for _, feature := range c.features {
-		c.subAndroidMk(&ret, feature)
+		c.subAndroidMk(&entries, feature)
 	}
 
-	c.subAndroidMk(&ret, c.compiler)
-	c.subAndroidMk(&ret, c.linker)
+	c.subAndroidMk(&entries, c.compiler)
+	c.subAndroidMk(&entries, c.linker)
 	if c.sanitize != nil {
-		c.subAndroidMk(&ret, c.sanitize)
+		c.subAndroidMk(&entries, c.sanitize)
 	}
-	c.subAndroidMk(&ret, c.installer)
+	c.subAndroidMk(&entries, c.installer)
 
-	ret.SubName += c.Properties.SubName
+	entries.SubName += c.Properties.SubName
 
-	return ret
+	return []android.AndroidMkEntries{entries}
 }
 
-func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, ret *android.AndroidMkData) {
+func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	var testFiles []string
 	for _, d := range data {
 		rel := d.Rel()
@@ -135,8 +135,8 @@
 		testFiles = append(testFiles, path+":"+rel)
 	}
 	if len(testFiles) > 0 {
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(testFiles, " "))
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.AddStrings("LOCAL_TEST_DATA", testFiles...)
 		})
 	}
 }
@@ -153,7 +153,7 @@
 	return overrides
 }
 
-func (library *libraryDecorator) androidMkWriteExportedFlags(w io.Writer) {
+func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) {
 	exportedFlags := library.exportedFlags()
 	for _, dir := range library.exportedDirs() {
 		exportedFlags = append(exportedFlags, "-I"+dir.String())
@@ -162,75 +162,92 @@
 		exportedFlags = append(exportedFlags, "-isystem "+dir.String())
 	}
 	if len(exportedFlags) > 0 {
-		fmt.Fprintln(w, "LOCAL_EXPORT_CFLAGS :=", strings.Join(exportedFlags, " "))
+		entries.AddStrings("LOCAL_EXPORT_CFLAGS", exportedFlags...)
 	}
 	exportedDeps := library.exportedDeps()
 	if len(exportedDeps) > 0 {
-		fmt.Fprintln(w, "LOCAL_EXPORT_C_INCLUDE_DEPS :=", strings.Join(exportedDeps.Strings(), " "))
+		entries.AddStrings("LOCAL_EXPORT_C_INCLUDE_DEPS", exportedDeps.Strings()...)
 	}
 }
 
-func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
 	if library.sAbiOutputFile.Valid() {
-		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiOutputFile.String())
+		entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
+			"$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiOutputFile.String())
 		if library.sAbiDiff.Valid() && !library.static() {
-			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
-			fmt.Fprintln(w, "HEADER_ABI_DIFFS +=", library.sAbiDiff.String())
+			entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
+				"$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiDiff.String())
+			entries.SetString("HEADER_ABI_DIFFS",
+				"$(HEADER_ABI_DIFFS) "+library.sAbiDiff.String())
 		}
 	}
 }
 
-func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+// TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries
+func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
+	if library.sAbiOutputFile.Valid() {
+		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
+			library.sAbiOutputFile.String())
+		if library.sAbiDiff.Valid() && !library.static() {
+			fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
+				library.sAbiDiff.String())
+			fmt.Fprintln(w, "HEADER_ABI_DIFFS := $(HEADER_ABI_DIFFS) ",
+				library.sAbiDiff.String())
+		}
+	}
+}
+
+func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	if library.static() {
-		ret.Class = "STATIC_LIBRARIES"
+		entries.Class = "STATIC_LIBRARIES"
 	} else if library.shared() {
-		ret.Class = "SHARED_LIBRARIES"
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-			fmt.Fprintln(w, "LOCAL_SOONG_TOC :=", library.toc().String())
+		entries.Class = "SHARED_LIBRARIES"
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
 			if !library.buildStubs() {
-				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+				entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
 			}
 			if len(library.Properties.Overrides) > 0 {
-				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
+				entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " "))
 			}
 			if len(library.post_install_cmds) > 0 {
-				fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(library.post_install_cmds, "&& "))
+				entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.post_install_cmds, "&& "))
 			}
 		})
 	} else if library.header() {
-		ret.Class = "HEADER_LIBRARIES"
+		entries.Class = "HEADER_LIBRARIES"
 	}
 
-	ret.DistFile = library.distFile
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		library.androidMkWriteExportedFlags(w)
-		library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+	entries.DistFile = library.distFile
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		library.androidMkWriteExportedFlags(entries)
+		library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
 
-		_, _, ext := android.SplitFileExt(outputFile.Base())
+		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
 
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
 
 		if library.coverageOutputFile.Valid() {
-			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", library.coverageOutputFile.String())
+			entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String())
 		}
 
 		if library.useCoreVariant {
-			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-			fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
-			fmt.Fprintln(w, "LOCAL_VNDK_DEPEND_ON_CORE_VARIANT := true")
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+			entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+			entries.SetBool("LOCAL_VNDK_DEPEND_ON_CORE_VARIANT", true)
 		}
 		if library.checkSameCoreVariant {
-			fmt.Fprintln(w, "LOCAL_CHECK_SAME_VNDK_VARIANTS := true")
+			entries.SetBool("LOCAL_CHECK_SAME_VNDK_VARIANTS", true)
 		}
 	})
 
 	if library.shared() && !library.buildStubs() {
-		ctx.subAndroidMk(ret, library.baseInstaller)
+		ctx.subAndroidMk(entries, library.baseInstaller)
 	} else {
-		ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 			if library.buildStubs() {
-				fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+				entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
 			}
 		})
 	}
@@ -238,90 +255,91 @@
 		android.DirectlyInAnyApex(ctx, ctx.Name()) && !ctx.InRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() &&
 		!ctx.static() {
 		if !library.buildStubs() {
-			ret.SubName = ".bootstrap"
+			entries.SubName = ".bootstrap"
 		}
 	}
 }
 
-func (object *objectLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Custom = func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-		out := ret.OutputFile.Path()
-		varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, data.SubName)
+func (object *objectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "STATIC_LIBRARIES"
+	entries.ExtraFooters = append(entries.ExtraFooters,
+		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			out := entries.OutputFile.Path()
+			varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
 
-		fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
-		fmt.Fprintln(w, ".KATI_READONLY: "+varname)
-	}
+			fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
+			fmt.Fprintln(w, ".KATI_READONLY: "+varname)
+		})
 }
 
-func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, binary.baseInstaller)
+func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, binary.baseInstaller)
 
-	ret.Class = "EXECUTABLES"
-	ret.DistFile = binary.distFile
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+	entries.Class = "EXECUTABLES"
+	entries.DistFile = binary.distFile
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
 		if len(binary.symlinks) > 0 {
-			fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(binary.symlinks, " "))
+			entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...)
 		}
 
 		if binary.coverageOutputFile.Valid() {
-			fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", binary.coverageOutputFile.String())
+			entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String())
 		}
 
 		if len(binary.Properties.Overrides) > 0 {
-			fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
+			entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " "))
 		}
 		if len(binary.post_install_cmds) > 0 {
-			fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD := "+strings.Join(binary.post_install_cmds, "&& "))
+			entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.post_install_cmds, "&& "))
 		}
 	})
 }
 
-func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, benchmark.binaryDecorator)
-	ret.Class = "NATIVE_TESTS"
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, benchmark.binaryDecorator)
+	entries.Class = "NATIVE_TESTS"
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if len(benchmark.Properties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+			entries.SetString("LOCAL_COMPATIBILITY_SUITE",
 				strings.Join(benchmark.Properties.Test_suites, " "))
 		}
 		if benchmark.testConfig != nil {
-			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", benchmark.testConfig.String())
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String())
 		}
-		fmt.Fprintln(w, "LOCAL_NATIVE_BENCHMARK := true")
+		entries.SetBool("LOCAL_NATIVE_BENCHMARK", true)
 		if !BoolDefault(benchmark.Properties.Auto_gen_config, true) {
-			fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
+			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
 		}
 	})
 
-	androidMkWriteTestData(benchmark.data, ctx, ret)
+	androidMkWriteTestData(benchmark.data, ctx, entries)
 }
 
-func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, test.binaryDecorator)
-	ret.Class = "NATIVE_TESTS"
+func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, test.binaryDecorator)
+	entries.Class = "NATIVE_TESTS"
 	if Bool(test.Properties.Test_per_src) {
-		ret.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
+		entries.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
 	}
-
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if len(test.Properties.Test_suites) > 0 {
-			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
+			entries.SetString("LOCAL_COMPATIBILITY_SUITE",
 				strings.Join(test.Properties.Test_suites, " "))
 		}
 		if test.testConfig != nil {
-			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", test.testConfig.String())
+			entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
 		}
 		if !BoolDefault(test.Properties.Auto_gen_config, true) {
-			fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true")
+			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
 		}
 	})
 
-	androidMkWriteTestData(test.data, ctx, ret)
+	androidMkWriteTestData(test.data, ctx, entries)
 }
 
-func (fuzz *fuzzBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, fuzz.binaryDecorator)
+func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, fuzz.binaryDecorator)
 
 	var fuzzFiles []string
 	for _, d := range fuzz.corpus {
@@ -344,199 +362,198 @@
 			filepath.Dir(fuzz.config.String())+":config.json")
 	}
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_IS_FUZZ_TARGET := true")
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
 		if len(fuzzFiles) > 0 {
-			fmt.Fprintln(w, "LOCAL_TEST_DATA := "+strings.Join(fuzzFiles, " "))
+			entries.AddStrings("LOCAL_TEST_DATA", fuzzFiles...)
 		}
 		if fuzz.installedSharedDeps != nil {
-			fmt.Fprintln(w, "LOCAL_FUZZ_INSTALLED_SHARED_DEPS :="+
-				strings.Join(fuzz.installedSharedDeps, " "))
+			entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
 		}
 	})
 }
 
-func (test *testLibrary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, test.libraryDecorator)
+func (test *testLibrary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, test.libraryDecorator)
 }
 
-func (library *toolchainLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "STATIC_LIBRARIES"
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		_, suffix, _ := android.SplitFileExt(outputFile.Base())
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+func (library *toolchainLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "STATIC_LIBRARIES"
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		_, suffix, _ := android.SplitFileExt(entries.OutputFile.Path().Base())
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
 	})
 }
 
-func (installer *baseInstaller) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	// Soong installation is only supported for host modules. Have Make
 	// installation trigger Soong installation.
 	if ctx.Target().Os.Class == android.Host {
-		ret.OutputFile = android.OptionalPathForPath(installer.path)
+		entries.OutputFile = android.OptionalPathForPath(installer.path)
 	}
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		path, file := filepath.Split(installer.path.ToMakePath().String())
 		stem, suffix, _ := android.SplitFileExt(file)
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
 	})
 }
 
-func (c *stubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
-	ret.Class = "SHARED_LIBRARIES"
+func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel
+	entries.Class = "SHARED_LIBRARIES"
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		path, file := filepath.Split(c.installPath.String())
 		stem, suffix, _ := android.SplitFileExt(file)
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
-		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
 	})
 }
 
-func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
+func (c *llndkStubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		c.libraryDecorator.androidMkWriteExportedFlags(w)
-		_, _, ext := android.SplitFileExt(outputFile.Base())
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
+		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
 
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
-		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
-		fmt.Fprintln(w, "LOCAL_SOONG_TOC :=", c.toc().String())
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+		entries.SetString("LOCAL_SOONG_TOC", c.toc().String())
 	})
 }
 
-func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
+func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
 
-	ret.SubName = c.androidMkSuffix
+	entries.SubName = c.androidMkSuffix
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		c.libraryDecorator.androidMkWriteExportedFlags(w)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
 
 		path, file := filepath.Split(c.path.ToMakePath().String())
 		stem, suffix, ext := android.SplitFileExt(file)
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
-		fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-		fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
-		fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
 		if c.tocFile.Valid() {
-			fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String())
+			entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
 		}
 	})
 }
 
-func (c *vendorSnapshotLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	// Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current
 	// and the version of the prebuilt is same as BOARD_VNDK_VERSION.
 	if c.shared() {
-		ret.Class = "SHARED_LIBRARIES"
+		entries.Class = "SHARED_LIBRARIES"
 	} else if c.static() {
-		ret.Class = "STATIC_LIBRARIES"
+		entries.Class = "STATIC_LIBRARIES"
 	} else if c.header() {
-		ret.Class = "HEADER_LIBRARIES"
+		entries.Class = "HEADER_LIBRARIES"
 	}
 
 	if c.androidMkVendorSuffix {
-		ret.SubName = vendorSuffix
+		entries.SubName = vendorSuffix
 	} else {
-		ret.SubName = ""
+		entries.SubName = ""
 	}
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		c.libraryDecorator.androidMkWriteExportedFlags(w)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
 
 		if c.shared() || c.static() {
 			path, file := filepath.Split(c.path.ToMakePath().String())
 			stem, suffix, ext := android.SplitFileExt(file)
-			fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
-			fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
-			fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+			entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+			entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+			entries.SetString("LOCAL_MODULE_STEM", stem)
 			if c.shared() {
-				fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path)
+				entries.SetString("LOCAL_MODULE_PATH", path)
 			}
 			if c.tocFile.Valid() {
-				fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String())
+				entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
 			}
 		}
 
 		if !c.shared() { // static or header
-			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 		}
 	})
 }
 
-func (c *vendorSnapshotBinaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "EXECUTABLES"
+func (c *vendorSnapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "EXECUTABLES"
 
 	if c.androidMkVendorSuffix {
-		ret.SubName = vendorSuffix
+		entries.SubName = vendorSuffix
 	} else {
-		ret.SubName = ""
+		entries.SubName = ""
 	}
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(c.Properties.Symlinks, " "))
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		entries.AddStrings("LOCAL_MODULE_SYMLINKS", c.Properties.Symlinks...)
 	})
 }
 
-func (c *ndkPrebuiltStlLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
+func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
 }
 
-func (c *vendorPublicLibraryStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Class = "SHARED_LIBRARIES"
-	ret.SubName = vendorPublicLibrarySuffix
+func (c *vendorPublicLibraryStubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
+	entries.SubName = vendorPublicLibrarySuffix
 
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		c.libraryDecorator.androidMkWriteExportedFlags(w)
-		_, _, ext := android.SplitFileExt(outputFile.Base())
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+		c.libraryDecorator.androidMkWriteExportedFlags(entries)
+		_, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base())
 
-		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext)
-		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
-		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
 	})
 }
 
-func (p *prebuiltLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+func (p *prebuiltLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		if p.properties.Check_elf_files != nil {
-			fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES :=", *p.properties.Check_elf_files)
+			entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files)
 		} else {
 			// soong_cc_prebuilt.mk does not include check_elf_file.mk by default
 			// because cc_library_shared and cc_binary use soong_cc_prebuilt.mk as well.
 			// In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to
 			// true if `p.properties.Check_elf_files` is not specified.
-			fmt.Fprintln(w, "LOCAL_CHECK_ELF_FILES := true")
+			entries.SetBool("LOCAL_CHECK_ELF_FILES", true)
 		}
 	})
 }
 
-func (p *prebuiltLibraryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, p.libraryDecorator)
+func (p *prebuiltLibraryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, p.libraryDecorator)
 	if p.shared() {
-		ctx.subAndroidMk(ret, &p.prebuiltLinker)
-		androidMkWriteAllowUndefinedSymbols(p.baseLinker, ret)
+		ctx.subAndroidMk(entries, &p.prebuiltLinker)
+		androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries)
 	}
 }
 
-func (p *prebuiltBinaryLinker) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
-	ctx.subAndroidMk(ret, p.binaryDecorator)
-	ctx.subAndroidMk(ret, &p.prebuiltLinker)
-	androidMkWriteAllowUndefinedSymbols(p.baseLinker, ret)
+func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	ctx.subAndroidMk(entries, p.binaryDecorator)
+	ctx.subAndroidMk(entries, &p.prebuiltLinker)
+	androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries)
 }
 
-func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, ret *android.AndroidMkData) {
-	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
-		allow := linker.Properties.Allow_undefined_symbols
-		if allow != nil {
-			fmt.Fprintln(w, "LOCAL_ALLOW_UNDEFINED_SYMBOLS :=", *allow)
-		}
-	})
+func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, entries *android.AndroidMkEntries) {
+	allow := linker.Properties.Allow_undefined_symbols
+	if allow != nil {
+		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow)
+		})
+	}
 }
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 53bc065..58d6ad0 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"strings"
 
 	"android/soong/android"
 	"github.com/google/blueprint"
@@ -98,7 +99,23 @@
 
 func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
 	pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
-	pbm.AddProperty("compile_multilib", "both")
+	archVariantCount := len(info.archVariantProperties)
+
+	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+	var multilib string
+	if archVariantCount == 2 {
+		multilib = "both"
+	} else if archVariantCount == 1 {
+		if strings.HasSuffix(info.archVariantProperties[0].archType, "64") {
+			multilib = "64"
+		} else {
+			multilib = "32"
+		}
+	}
+	if multilib != "" {
+		pbm.AddProperty("compile_multilib", multilib)
+	}
+
 	archProperties := pbm.AddPropertySet("arch")
 	for _, av := range info.archVariantProperties {
 		archTypeProperties := archProperties.AddPropertySet(av.archType)
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index f08a379..13b5511 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -234,7 +234,7 @@
 }
 
 func (toolchainLinuxX86) LibclangRuntimeLibraryArch() string {
-	return "i686"
+	return "i386"
 }
 
 func (toolchainLinuxX8664) LibclangRuntimeLibraryArch() string {
diff --git a/cc/library.go b/cc/library.go
index bca9a96..6ffb7fc 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -183,7 +183,6 @@
 	ctx.RegisterModuleType("cc_library", LibraryFactory)
 	ctx.RegisterModuleType("cc_library_host_static", LibraryHostStaticFactory)
 	ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
-	ctx.RegisterModuleType("cc_library_headers", LibraryHeaderFactory)
 }
 
 // cc_library creates both static and/or shared libraries for a device and/or
@@ -233,16 +232,6 @@
 	return module.Init()
 }
 
-// cc_library_headers contains a set of c/c++ headers which are imported by
-// other soong cc modules using the header_libs property. For best practices,
-// use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
-// Make.
-func LibraryHeaderFactory() android.Module {
-	module, library := NewLibrary(android.HostAndDeviceSupported)
-	library.HeaderOnly()
-	return module.Init()
-}
-
 type flagExporter struct {
 	Properties FlagExporterProperties
 
@@ -1314,22 +1303,28 @@
 	if cc_prebuilt {
 		library := mctx.Module().(*Module).linker.(prebuiltLibraryInterface)
 
-		// Always create both the static and shared variants for prebuilt libraries, and then disable the one
-		// that is not being used.  This allows them to share the name of a cc_library module, which requires that
-		// all the variants of the cc_library also exist on the prebuilt.
-		modules := mctx.CreateLocalVariations("static", "shared")
-		static := modules[0].(*Module)
-		shared := modules[1].(*Module)
+		// Differentiate between header only and building an actual static/shared library
+		if library.buildStatic() || library.buildShared() {
+			// Always create both the static and shared variants for prebuilt libraries, and then disable the one
+			// that is not being used.  This allows them to share the name of a cc_library module, which requires that
+			// all the variants of the cc_library also exist on the prebuilt.
+			modules := mctx.CreateLocalVariations("static", "shared")
+			static := modules[0].(*Module)
+			shared := modules[1].(*Module)
 
-		static.linker.(prebuiltLibraryInterface).setStatic()
-		shared.linker.(prebuiltLibraryInterface).setShared()
+			static.linker.(prebuiltLibraryInterface).setStatic()
+			shared.linker.(prebuiltLibraryInterface).setShared()
 
-		if !library.buildStatic() {
-			static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			if !library.buildStatic() {
+				static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			}
+			if !library.buildShared() {
+				shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			}
+		} else {
+			// Header only
 		}
-		if !library.buildShared() {
-			shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
-		}
+
 	} else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
 
 		// Non-cc.Modules may need an empty variant for their mutators.
diff --git a/cc/library_headers.go b/cc/library_headers.go
new file mode 100644
index 0000000..88cf7af
--- /dev/null
+++ b/cc/library_headers.go
@@ -0,0 +1,56 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import "android/soong/android"
+
+func init() {
+	RegisterLibraryHeadersBuildComponents(android.InitRegistrationContext)
+
+	// Register sdk member types.
+	android.RegisterSdkMemberType(headersLibrarySdkMemberType)
+}
+
+var headersLibrarySdkMemberType = &librarySdkMemberType{
+	SdkMemberTypeBase: android.SdkMemberTypeBase{
+		PropertyName: "native_header_libs",
+		SupportsSdk:  true,
+	},
+	prebuiltModuleType: "cc_prebuilt_library_headers",
+	linkTypes:          nil,
+}
+
+func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("cc_library_headers", LibraryHeaderFactory)
+	ctx.RegisterModuleType("cc_prebuilt_library_headers", prebuiltLibraryHeaderFactory)
+}
+
+// cc_library_headers contains a set of c/c++ headers which are imported by
+// other soong cc modules using the header_libs property. For best practices,
+// use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
+// Make.
+func LibraryHeaderFactory() android.Module {
+	module, library := NewLibrary(android.HostAndDeviceSupported)
+	library.HeaderOnly()
+	module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType}
+	return module.Init()
+}
+
+// cc_prebuilt_library_headers is a prebuilt version of cc_library_headers
+func prebuiltLibraryHeaderFactory() android.Module {
+	module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+	library.HeaderOnly()
+	return module.Init()
+}
diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go
new file mode 100644
index 0000000..564ef61
--- /dev/null
+++ b/cc/library_headers_test.go
@@ -0,0 +1,62 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestLibraryHeaders(t *testing.T) {
+	ctx := testCc(t, `
+	cc_library_headers {
+		name: "headers",
+		export_include_dirs: ["my_include"],
+	}
+	cc_library_static {
+		name: "lib",
+		srcs: ["foo.c"],
+		header_libs: ["headers"],
+	}
+	`)
+
+	// test if header search paths are correctly added
+	cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+	cflags := cc.Args["cFlags"]
+	if !strings.Contains(cflags, " -Imy_include ") {
+		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+	}
+}
+
+func TestPrebuiltLibraryHeaders(t *testing.T) {
+	ctx := testCc(t, `
+	cc_prebuilt_library_headers {
+		name: "headers",
+		export_include_dirs: ["my_include"],
+	}
+	cc_library_static {
+		name: "lib",
+		srcs: ["foo.c"],
+		header_libs: ["headers"],
+	}
+	`)
+
+	// test if header search paths are correctly added
+	cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc")
+	cflags := cc.Args["cFlags"]
+	if !strings.Contains(cflags, " -Imy_include ") {
+		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+	}
+}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index dd097cf..a36917e 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -65,12 +65,19 @@
 			if version == "" {
 				version = LatestStubsVersionFor(mctx.Config(), name)
 			}
-			for _, linkType := range mt.linkTypes {
+			if mt.linkTypes == nil {
 				mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
 					{Mutator: "image", Variation: android.CoreVariation},
-					{Mutator: "link", Variation: linkType},
 					{Mutator: "version", Variation: version},
 				}...), dependencyTag, name)
+			} else {
+				for _, linkType := range mt.linkTypes {
+					mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+						{Mutator: "image", Variation: android.CoreVariation},
+						{Mutator: "link", Variation: linkType},
+						{Mutator: "version", Variation: version},
+					}...), dependencyTag, name)
+				}
 			}
 		}
 	}
@@ -92,7 +99,7 @@
 // copy exported header files and stub *.so files
 func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
 	info := mt.organizeVariants(member)
-	buildSharedNativeLibSnapshot(sdkModuleContext, info, builder, member)
+	info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
 }
 
 // Organize the variants by architecture.
@@ -197,85 +204,148 @@
 	}
 }
 
-func buildSharedNativeLibSnapshot(sdkModuleContext android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder, member android.SdkMember) {
-	// a function for emitting include dirs
-	addExportedDirCopyCommandsForNativeLibs := func(lib nativeLibInfoProperties) {
-		// Do not include exportedGeneratedIncludeDirs in the list of directories whose
-		// contents are copied as they are copied from exportedGeneratedHeaders below.
-		includeDirs := lib.ExportedIncludeDirs
-		includeDirs = append(includeDirs, lib.ExportedSystemIncludeDirs...)
-		for _, dir := range includeDirs {
-			// lib.ArchType is "" for common properties.
-			targetDir := filepath.Join(lib.archType, nativeIncludeDir)
-
-			// TODO(jiyong) copy headers having other suffixes
-			headers, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.h", nil)
-			for _, file := range headers {
-				src := android.PathForSource(sdkModuleContext, file)
-				dest := filepath.Join(targetDir, file)
-				builder.CopyToSnapshot(src, dest)
-			}
-		}
-
-		genHeaders := lib.exportedGeneratedHeaders
-		for _, file := range genHeaders {
-			// lib.ArchType is "" for common properties.
-			targetDir := filepath.Join(lib.archType, nativeGeneratedIncludeDir)
-
-			dest := filepath.Join(targetDir, lib.name, file.Rel())
-			builder.CopyToSnapshot(file, dest)
-		}
-	}
-
-	addExportedDirCopyCommandsForNativeLibs(info.commonProperties)
-
-	// for each architecture
-	for _, av := range info.archVariantProperties {
-		builder.CopyToSnapshot(av.outputFile, nativeLibraryPathFor(av))
-
-		addExportedDirCopyCommandsForNativeLibs(av)
-	}
-
-	info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
-}
-
 func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
 
 	pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
 
-	addPossiblyArchSpecificProperties(info.commonProperties, pbm)
+	addPossiblyArchSpecificProperties(sdkModuleContext, builder, info.commonProperties, pbm)
 
 	archProperties := pbm.AddPropertySet("arch")
 	for _, av := range info.archVariantProperties {
 		archTypeProperties := archProperties.AddPropertySet(av.archType)
-		// Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
-		archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})
 
-		addPossiblyArchSpecificProperties(av, archTypeProperties)
+		// If the library has some link types then it produces an output binary file, otherwise it
+		// is header only.
+		if info.memberType.linkTypes != nil {
+			// Copy the generated library to the snapshot and add a reference to it in the .bp module.
+			nativeLibraryPath := nativeLibraryPathFor(av)
+			builder.CopyToSnapshot(av.outputFile, nativeLibraryPath)
+			archTypeProperties.AddProperty("srcs", []string{nativeLibraryPath})
+		}
+
+		// Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
+		addPossiblyArchSpecificProperties(sdkModuleContext, builder, av, archTypeProperties)
 	}
 	pbm.AddProperty("stl", "none")
 	pbm.AddProperty("system_shared_libs", []string{})
 }
 
-// Add properties that may, or may not, be arch specific.
-func addPossiblyArchSpecificProperties(libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
-	addExportedDirsForNativeLibs(libInfo, outputProperties, false /*systemInclude*/)
-	addExportedDirsForNativeLibs(libInfo, outputProperties, true /*systemInclude*/)
+type includeDirsProperty struct {
+	// Accessor to retrieve the paths
+	pathsGetter func(libInfo nativeLibInfoProperties) android.Paths
+
+	// The name of the property in the prebuilt library, "" means there is no property.
+	propertyName string
+
+	// The directory within the snapshot directory into which items should be copied.
+	snapshotDir string
+
+	// True if the items on the path should be copied.
+	copy bool
+
+	// True if the paths represent directories, files if they represent files.
+	dirs bool
 }
 
-// a function for emitting include dirs
-func addExportedDirsForNativeLibs(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
-	includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
-	if len(includeDirs) == 0 {
-		return
+var includeDirProperties = []includeDirsProperty{
+	{
+		// ExportedIncludeDirs lists directories that contains some header files to be
+		// copied into a directory in the snapshot. The snapshot directories must be added to
+		// the export_include_dirs property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
+		propertyName: "export_include_dirs",
+		snapshotDir:  nativeIncludeDir,
+		copy:         true,
+		dirs:         true,
+	},
+	{
+		// ExportedSystemIncludeDirs lists directories that contains some system header files to
+		// be copied into a directory in the snapshot. The snapshot directories must be added to
+		// the export_system_include_dirs property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
+		propertyName: "export_system_include_dirs",
+		snapshotDir:  nativeIncludeDir,
+		copy:         true,
+		dirs:         true,
+	},
+	{
+		// exportedGeneratedIncludeDirs lists directories that contains some header files
+		// that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
+		// of these directories do not need to be copied, but these directories do need adding to
+		// the export_include_dirs property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
+		propertyName: "export_include_dirs",
+		snapshotDir:  nativeGeneratedIncludeDir,
+		copy:         false,
+		dirs:         true,
+	},
+	{
+		// exportedGeneratedHeaders lists header files that are in one of the directories
+		// specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
+		// As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
+		// property in the prebuilt module in the snapshot.
+		pathsGetter:  func(libInfo nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
+		propertyName: "",
+		snapshotDir:  nativeGeneratedIncludeDir,
+		copy:         true,
+		dirs:         false,
+	},
+}
+
+// Add properties that may, or may not, be arch specific.
+func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+
+	// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
+	includeDirs := make(map[string][]string)
+
+	// Iterate over each include directory property, copying files and collating property
+	// values where necessary.
+	for _, propertyInfo := range includeDirProperties {
+		// Calculate the base directory in the snapshot into which the files will be copied.
+		// lib.ArchType is "" for common properties.
+		targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
+
+		propertyName := propertyInfo.propertyName
+
+		// Iterate over each path in one of the include directory properties.
+		for _, path := range propertyInfo.pathsGetter(libInfo) {
+
+			// Copy the files/directories when necessary.
+			if propertyInfo.copy {
+				if propertyInfo.dirs {
+					// When copying a directory glob and copy all the headers within it.
+					// TODO(jiyong) copy headers having other suffixes
+					headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil)
+					for _, file := range headers {
+						src := android.PathForSource(sdkModuleContext, file)
+						dest := filepath.Join(targetDir, file)
+						builder.CopyToSnapshot(src, dest)
+					}
+				} else {
+					// Otherwise, just copy the files.
+					dest := filepath.Join(targetDir, libInfo.name, path.Rel())
+					builder.CopyToSnapshot(path, dest)
+				}
+			}
+
+			// Only directories are added to a property.
+			if propertyInfo.dirs {
+				var snapshotPath string
+				if isGeneratedHeaderDirectory(path) {
+					snapshotPath = filepath.Join(targetDir, libInfo.name)
+				} else {
+					snapshotPath = filepath.Join(targetDir, path.String())
+				}
+
+				includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath)
+			}
+		}
 	}
-	var propertyName string
-	if !systemInclude {
-		propertyName = "export_include_dirs"
-	} else {
-		propertyName = "export_system_include_dirs"
+
+	// Add the collated include dir properties to the output.
+	for property, dirs := range includeDirs {
+		outputProperties.AddProperty(property, dirs)
 	}
-	properties.AddProperty(propertyName, includeDirs)
 }
 
 const (
@@ -290,31 +360,6 @@
 		nativeStubDir, lib.outputFile.Base())
 }
 
-// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
-func nativeIncludeDirPathsFor(lib nativeLibInfoProperties, systemInclude bool) []string {
-	var result []string
-	var includeDirs []android.Path
-	if !systemInclude {
-		// Include the generated include dirs in the exported include dirs.
-		includeDirs = append(lib.ExportedIncludeDirs, lib.exportedGeneratedIncludeDirs...)
-	} else {
-		includeDirs = lib.ExportedSystemIncludeDirs
-	}
-	for _, dir := range includeDirs {
-		var path string
-		if isGeneratedHeaderDirectory(dir) {
-			path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
-		} else {
-			path = filepath.Join(nativeIncludeDir, dir.String())
-		}
-
-		// lib.ArchType is "" for common properties.
-		path = filepath.Join(lib.archType, path)
-		result = append(result, path)
-	}
-	return result
-}
-
 // nativeLibInfoProperties represents properties of a native lib
 //
 // The exported (capitalized) fields will be examined and may be changed during common value extraction.
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index b0cf489..2c18ac3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -87,15 +87,16 @@
 
 func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
+
+	p.libraryDecorator.exportIncludes(ctx)
+	p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+	p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+	p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+	p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+	p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+
 	// TODO(ccross): verify shared library dependencies
 	if len(p.properties.Srcs) > 0 {
-		p.libraryDecorator.exportIncludes(ctx)
-		p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
-		p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
-		p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
-		p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
-		p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
-
 		builderFlags := flagsToBuilderFlags(flags)
 
 		in := p.Prebuilt.SingleSourcePath(ctx)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 5663aa7..6e809bf 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -179,6 +179,7 @@
 	SanitizerEnabled  bool     `blueprint:"mutated"`
 	SanitizeDep       bool     `blueprint:"mutated"`
 	MinimalRuntimeDep bool     `blueprint:"mutated"`
+	BuiltinsDep       bool     `blueprint:"mutated"`
 	UbsanRuntimeDep   bool     `blueprint:"mutated"`
 	InSanitizerDir    bool     `blueprint:"mutated"`
 	Sanitizers        []string `blueprint:"mutated"`
@@ -334,8 +335,8 @@
 		s.Diag.Cfi = nil
 	}
 
-	// Disable sanitizers that depend on the UBSan runtime for host builds.
-	if ctx.Host() {
+	// Disable sanitizers that depend on the UBSan runtime for windows/darwin builds.
+	if !ctx.Os().Linux() {
 		s.Cfi = nil
 		s.Diag.Cfi = nil
 		s.Misc_undefined = nil
@@ -439,12 +440,19 @@
 func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
 	minimalRuntimeLib := config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
 	minimalRuntimePath := "${config.ClangAsanLibDir}/" + minimalRuntimeLib
+	builtinsRuntimeLib := config.BuiltinsRuntimeLibrary(ctx.toolchain()) + ".a"
+	builtinsRuntimePath := "${config.ClangAsanLibDir}/" + builtinsRuntimeLib
 
-	if ctx.Device() && sanitize.Properties.MinimalRuntimeDep {
+	if sanitize.Properties.MinimalRuntimeDep {
 		flags.Local.LdFlags = append(flags.Local.LdFlags,
 			minimalRuntimePath,
 			"-Wl,--exclude-libs,"+minimalRuntimeLib)
 	}
+
+	if sanitize.Properties.BuiltinsDep {
+		flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...)
+	}
+
 	if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
 		return flags
 	}
@@ -547,11 +555,19 @@
 			// there will always be undefined symbols in intermediate libraries.
 			_, flags.Global.LdFlags = removeFromList("-Wl,--no-undefined", flags.Global.LdFlags)
 			flags.Local.LdFlags = append(flags.Local.LdFlags, sanitizeArg)
-		} else {
-			if enableMinimalRuntime(sanitize) {
-				flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
-				flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
-				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+
+			// non-Bionic toolchain prebuilts are missing UBSan's vptr and function sanitizers
+			if !ctx.toolchain().Bionic() {
+				flags.Local.CFlags = append(flags.Local.CFlags, "-fno-sanitize=vptr,function")
+			}
+		}
+
+		if enableMinimalRuntime(sanitize) {
+			flags.Local.CFlags = append(flags.Local.CFlags, strings.Join(minimalRuntimeFlags, " "))
+			flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--exclude-libs,"+minimalRuntimeLib)
+			if !ctx.toolchain().Bionic() {
+				flags.libFlags = append([]string{builtinsRuntimePath}, flags.libFlags...)
 			}
 		}
 
@@ -593,18 +609,18 @@
 	return flags
 }
 
-func (sanitize *sanitize) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+func (sanitize *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	// Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing
 	// both the sanitized and non-sanitized variants to make without a name conflict.
-	if ret.Class == "STATIC_LIBRARIES" || ret.Class == "HEADER_LIBRARIES" {
+	if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" {
 		if Bool(sanitize.Properties.Sanitize.Cfi) {
-			ret.SubName += ".cfi"
+			entries.SubName += ".cfi"
 		}
 		if Bool(sanitize.Properties.Sanitize.Hwaddress) {
-			ret.SubName += ".hwasan"
+			entries.SubName += ".hwasan"
 		}
 		if Bool(sanitize.Properties.Sanitize.Scs) {
-			ret.SubName += ".scs"
+			entries.SubName += ".scs"
 		}
 	}
 }
@@ -766,6 +782,10 @@
 					return false
 				}
 
+				if c.Os() == android.Linux {
+					c.sanitize.Properties.BuiltinsDep = true
+				}
+
 				return true
 			}
 
@@ -902,11 +922,14 @@
 				runtimeLibrary = config.ScudoRuntimeLibrary(toolchain)
 			}
 		} else if len(diagSanitizers) > 0 || c.sanitize.Properties.UbsanRuntimeDep ||
-			Bool(c.sanitize.Properties.Sanitize.Fuzzer) {
+			Bool(c.sanitize.Properties.Sanitize.Fuzzer) ||
+			Bool(c.sanitize.Properties.Sanitize.Undefined) ||
+			Bool(c.sanitize.Properties.Sanitize.All_undefined) {
 			runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)
 		}
 
-		if mctx.Device() && runtimeLibrary != "" {
+		if runtimeLibrary != "" && (toolchain.Bionic() || c.sanitize.Properties.UbsanRuntimeDep) {
+			// UBSan is supported on non-bionic linux host builds as well
 			if isLlndkLibrary(runtimeLibrary, mctx.Config()) && !c.static() && c.UseVndk() {
 				runtimeLibrary = runtimeLibrary + llndkLibrarySuffix
 			}
@@ -1079,11 +1102,17 @@
 	if !Bool(sanitize.Properties.Sanitize.Address) &&
 		!Bool(sanitize.Properties.Sanitize.Hwaddress) &&
 		!Bool(sanitize.Properties.Sanitize.Fuzzer) &&
+
 		(Bool(sanitize.Properties.Sanitize.Integer_overflow) ||
-			len(sanitize.Properties.Sanitize.Misc_undefined) > 0) &&
+			len(sanitize.Properties.Sanitize.Misc_undefined) > 0 ||
+			Bool(sanitize.Properties.Sanitize.Undefined) ||
+			Bool(sanitize.Properties.Sanitize.All_undefined)) &&
+
 		!(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
 			Bool(sanitize.Properties.Sanitize.Diag.Cfi) ||
+			Bool(sanitize.Properties.Sanitize.Diag.Undefined) ||
 			len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0) {
+
 		return true
 	}
 	return false
@@ -1091,6 +1120,7 @@
 
 func enableUbsanRuntime(sanitize *sanitize) bool {
 	return Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
+		Bool(sanitize.Properties.Sanitize.Diag.Undefined) ||
 		len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0
 }
 
diff --git a/cc/testing.go b/cc/testing.go
index 7b0305f..a22763a 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -25,6 +25,7 @@
 	RegisterCCBuildComponents(ctx)
 	RegisterBinaryBuildComponents(ctx)
 	RegisterLibraryBuildComponents(ctx)
+	RegisterLibraryHeadersBuildComponents(ctx)
 
 	ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
 	ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)
@@ -213,6 +214,7 @@
 			stl: "none",
 			vendor_available: true,
 			recovery_available: true,
+			host_supported: true,
 		}
 		cc_library {
 			name: "libc++",
@@ -222,6 +224,7 @@
 			stl: "none",
 			vendor_available: true,
 			recovery_available: true,
+			host_supported: true,
 			vndk: {
 				enabled: true,
 				support_system_process: true,
diff --git a/java/app.go b/java/app.go
index 8d32aba..ed4462c 100755
--- a/java/app.go
+++ b/java/app.go
@@ -495,7 +495,7 @@
 
 	dexJarFile := a.dexBuildActions(ctx)
 
-	jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx))
+	jniLibs, certificateDeps := collectAppDeps(ctx, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
 	jniJarFile := a.jniBuildActions(jniLibs, ctx)
 
 	if ctx.Failed() {
@@ -531,7 +531,8 @@
 	}
 }
 
-func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool) ([]jniLib, []Certificate) {
+func collectAppDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool,
+	checkNativeSdkVersion bool) ([]jniLib, []Certificate) {
 	var jniLibs []jniLib
 	var certificates []Certificate
 	seenModulePaths := make(map[string]bool)
@@ -553,6 +554,18 @@
 				}
 				seenModulePaths[path.String()] = true
 
+				if checkNativeSdkVersion {
+					if app, ok := ctx.Module().(interface{ sdkVersion() sdkSpec }); ok {
+						if app.sdkVersion().specified() &&
+							app.sdkVersion().kind != sdkCorePlatform &&
+							dep.SdkVersion() == "" {
+							ctx.PropertyErrorf("jni_libs",
+								"JNI dependency %q uses platform APIs, but this module does not",
+								otherName)
+						}
+					}
+				}
+
 				if lib.Valid() {
 					jniLibs = append(jniLibs, jniLib{
 						name:   ctx.OtherModuleName(module),
@@ -1049,7 +1062,7 @@
 		ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
 	}
 
-	_, certificates := collectAppDeps(ctx, false)
+	_, certificates := collectAppDeps(ctx, false, false)
 
 	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
 	// TODO: LOCAL_PACKAGE_SPLITS
@@ -1304,7 +1317,7 @@
 	r.aapt.buildActions(ctx, r, "--no-resource-deduping", "--no-resource-removal")
 
 	// Sign the built package
-	_, certificates := collectAppDeps(ctx, false)
+	_, certificates := collectAppDeps(ctx, false, false)
 	certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
 	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
 	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates)
diff --git a/java/app_test.go b/java/app_test.go
index dfd8571..0c6da7a 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -903,6 +903,7 @@
 			name: "libjni",
 			system_shared_libs: [],
 			stl: "none",
+			sdk_version: "current",
 		}
 
 		android_app {
@@ -2112,6 +2113,7 @@
 			system_shared_libs: [],
 			stl: "none",
 			notice: "LIB_NOTICE",
+			sdk_version: "current",
 		}
 
 		java_library {
diff --git a/java/config/config.go b/java/config/config.go
index 7f446e5..54c89cd 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -48,7 +48,7 @@
 		// TODO: Could this be all updatable bootclasspath jars?
 		"updatable-media",
 		"framework-sdkextensions",
-		"ike",
+		"android.net.ipsec.ike",
 	}
 )
 
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 6020aba..884a757 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -28,9 +28,10 @@
 }, "outFlag", "stubAPIFlags")
 
 type hiddenAPI struct {
-	flagsCSVPath    android.Path
-	metadataCSVPath android.Path
 	bootDexJarPath  android.Path
+	flagsCSVPath    android.Path
+	indexCSVPath    android.Path
+	metadataCSVPath android.Path
 }
 
 func (h *hiddenAPI) flagsCSV() android.Path {
@@ -45,17 +46,21 @@
 	return h.bootDexJarPath
 }
 
+func (h *hiddenAPI) indexCSV() android.Path {
+	return h.indexCSVPath
+}
+
 type hiddenAPIIntf interface {
-	flagsCSV() android.Path
-	metadataCSV() android.Path
 	bootDexJar() android.Path
+	flagsCSV() android.Path
+	indexCSV() android.Path
+	metadataCSV() android.Path
 }
 
 var _ hiddenAPIIntf = (*hiddenAPI)(nil)
 
-func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath, implementationJar android.Path,
-	uncompressDex bool) android.ModuleOutPath {
-
+func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath,
+	implementationJar android.Path, uncompressDex bool) android.ModuleOutPath {
 	if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
 		name := ctx.ModuleName()
 
@@ -77,9 +82,8 @@
 			// Derive the greylist from classes jar.
 			flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
 			metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
-			hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, implementationJar)
-			h.flagsCSVPath = flagsCSV
-			h.metadataCSVPath = metadataCSV
+			indexCSV := android.PathForModuleOut(ctx, "hiddenapi", "index.csv")
+			h.hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, indexCSV, implementationJar)
 
 			// If this module is actually on the boot jars list and not providing
 			// hiddenapi information for a module on the boot jars list then encode
@@ -96,9 +100,7 @@
 	return dexJar
 }
 
-func hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV android.WritablePath,
-	classesJar android.Path) {
-
+func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV, indexCSV android.WritablePath, classesJar android.Path) {
 	stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
 
 	ctx.Build(pctx, android.BuildParams{
@@ -112,6 +114,7 @@
 			"stubAPIFlags": stubFlagsCSV.String(),
 		},
 	})
+	h.flagsCSVPath = flagsCSV
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        hiddenAPIGenerateCSVRule,
@@ -124,18 +127,26 @@
 			"stubAPIFlags": stubFlagsCSV.String(),
 		},
 	})
+	h.metadataCSVPath = metadataCSV
 
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		BuiltTool(ctx, "merge_csv").
+		FlagWithInput("--zip_input=", classesJar).
+		FlagWithOutput("--output=", indexCSV)
+	rule.Build(pctx, ctx, "merged-hiddenapi-index", "Merged Hidden API index")
+	h.indexCSVPath = indexCSV
 }
 
 var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{
-	Command: `rm -rf $tmpDir && mkdir -p $tmpDir && mkdir $tmpDir/dex-input && mkdir $tmpDir/dex-output && ` +
-		`unzip -o -q $in 'classes*.dex' -d $tmpDir/dex-input && ` +
-		`for INPUT_DEX in $$(find $tmpDir/dex-input -maxdepth 1 -name 'classes*.dex' | sort); do ` +
-		`  echo "--input-dex=$${INPUT_DEX}"; ` +
-		`  echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})"; ` +
-		`done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags && ` +
-		`${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" && ` +
-		`${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" $out $tmpDir/dex.jar $in`,
+	Command: `rm -rf $tmpDir && mkdir -p $tmpDir && mkdir $tmpDir/dex-input && mkdir $tmpDir/dex-output &&
+		unzip -o -q $in 'classes*.dex' -d $tmpDir/dex-input &&
+		for INPUT_DEX in $$(find $tmpDir/dex-input -maxdepth 1 -name 'classes*.dex' | sort); do
+		  echo "--input-dex=$${INPUT_DEX}";
+		  echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})";
+		done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags &&
+		${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" &&
+		${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
 	CommandDeps: []string{
 		"${config.HiddenAPI}",
 		"${config.SoongZipCmd}",
@@ -159,9 +170,21 @@
 		tmpOutput = android.PathForModuleOut(ctx, "hiddenapi", "unaligned", "unaligned.jar")
 		tmpDir = android.PathForModuleOut(ctx, "hiddenapi", "unaligned")
 	}
+
+	enforceHiddenApiFlagsToAllMembers := true
 	// If frameworks/base doesn't exist we must be building with the 'master-art' manifest.
 	// Disable assertion that all methods/fields have hidden API flags assigned.
 	if !ctx.Config().FrameworksBaseDirExists(ctx) {
+		enforceHiddenApiFlagsToAllMembers = false
+	}
+	// b/149353192: when a module is instrumented, jacoco adds synthetic members
+	// $jacocoData and $jacocoInit. Since they don't exist when building the hidden API flags,
+	// don't complain when we don't find hidden API flags for the synthetic members.
+	if j, ok := ctx.Module().(*Library); ok && j.shouldInstrument(ctx) {
+		enforceHiddenApiFlagsToAllMembers = false
+	}
+
+	if !enforceHiddenApiFlagsToAllMembers {
 		hiddenapiFlags = "--no-force-assign-all"
 	}
 
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 7850193..7e7e955 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -22,13 +22,15 @@
 
 func init() {
 	android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	android.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory)
 	android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
 }
 
 type hiddenAPISingletonPathsStruct struct {
-	stubFlags android.OutputPath
 	flags     android.OutputPath
+	index     android.OutputPath
 	metadata  android.OutputPath
+	stubFlags android.OutputPath
 }
 
 var hiddenAPISingletonPathsKey = android.NewOnceKey("hiddenAPISingletonPathsKey")
@@ -39,9 +41,10 @@
 func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct {
 	return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} {
 		return hiddenAPISingletonPathsStruct{
-			stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
 			flags:     android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"),
+			index:     android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"),
 			metadata:  android.PathForOutput(ctx, "hiddenapi", "hiddenapi-greylist.csv"),
+			stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
 		}
 	}).(hiddenAPISingletonPathsStruct)
 }
@@ -364,3 +367,45 @@
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	return module
 }
+
+func hiddenAPIIndexSingletonFactory() android.Singleton {
+	return &hiddenAPIIndexSingleton{}
+}
+
+type hiddenAPIIndexSingleton struct {
+	index android.Path
+}
+
+func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
+	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+		return
+	}
+
+	indexes := android.Paths{}
+	ctx.VisitAllModules(func(module android.Module) {
+		if h, ok := module.(hiddenAPIIntf); ok {
+			if h.indexCSV() != nil {
+				indexes = append(indexes, h.indexCSV())
+			}
+		}
+	})
+
+	rule := android.NewRuleBuilder()
+	rule.Command().
+		BuiltTool(ctx, "merge_csv").
+		FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties").
+		FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index).
+		Inputs(indexes)
+	rule.Build(pctx, ctx, "singleton-merged-hiddenapi-index", "Singleton merged Hidden API index")
+
+	h.index = hiddenAPISingletonPaths(ctx).index
+}
+
+func (h *hiddenAPIIndexSingleton) MakeVars(ctx android.MakeVarsContext) {
+	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+		return
+	}
+
+	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_INDEX", h.index.String())
+}
diff --git a/java/java.go b/java/java.go
index 462dba8..b3aca49 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1519,6 +1519,14 @@
 		j.headerJarFile = j.implementationJarFile
 	}
 
+	// Force enable the instrumentation for java code that is built for APEXes ...
+	// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
+	// doesn't make sense)
+	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
+	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+		j.properties.Instrument = true
+	}
+
 	if j.shouldInstrument(ctx) {
 		outputFile = j.instrument(ctx, flags, outputFile, jarName)
 	}
diff --git a/scripts/jsonmodify.py b/scripts/jsonmodify.py
index 4b2c3c2..ba1109e 100755
--- a/scripts/jsonmodify.py
+++ b/scripts/jsonmodify.py
@@ -112,9 +112,10 @@
 
   if args.out:
     with open(args.out, "w") as f:
-      json.dump(obj, f, indent=2)
+      json.dump(obj, f, indent=2, separators=(',', ': '))
+      f.write('\n')
   else:
-    print(json.dumps(obj, indent=2))
+    print(json.dumps(obj, indent=2, separators=(',', ': ')))
 
 
 if __name__ == '__main__':
diff --git a/sdk/bp.go b/sdk/bp.go
index 6936daf..c2a75e4 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -48,8 +48,7 @@
 }
 
 func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
-	set := &bpPropertySet{}
-	set.init()
+	set := newPropertySet()
 	s.AddProperty(name, set)
 	return set
 }
@@ -62,7 +61,7 @@
 	return s.tags[name]
 }
 
-func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
+func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
 	var newOrder []string
 	for _, name := range s.order {
 		value := s.properties[name]
@@ -70,7 +69,13 @@
 		var newValue interface{}
 		var newTag android.BpPropertyTag
 		if propertySet, ok := value.(*bpPropertySet); ok {
-			newValue, newTag = transformer.transformPropertySet(name, propertySet, tag)
+			var newPropertySet *bpPropertySet
+			newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag)
+			if newPropertySet == nil {
+				newValue = nil
+			} else {
+				newValue = newPropertySet
+			}
 		} else {
 			newValue, newTag = transformer.transformProperty(name, value, tag)
 		}
@@ -88,6 +93,16 @@
 	s.order = newOrder
 }
 
+func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag)
+	if newPropertySet != nil {
+		newPropertySet.transformContents(transformer)
+
+		newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag)
+	}
+	return newPropertySet, newTag
+}
+
 func (s *bpPropertySet) setProperty(name string, value interface{}) {
 	if s.properties[name] == nil {
 		s.AddProperty(name, value)
@@ -136,7 +151,17 @@
 	// The name will be "" for the top level property set.
 	//
 	// Returning (nil, ...) will cause the property set to be removed.
-	transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
+	transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
+
+	// Transform the property set, returning the new property set/tag to insert back into the
+	// parent property set (or module if this is the top level property set).
+	//
+	// This will be called after transforming the properties in the supplied set.
+	//
+	// The name will be "" for the top level property set.
+	//
+	// Returning (nil, ...) will cause the property set to be removed.
+	transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
 
 	// Transform a property, return the new value/tag to insert back into the property set.
 	//
@@ -165,7 +190,11 @@
 	return module
 }
 
-func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+func (t identityTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	return propertySet, tag
+}
+
+func (t identityTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
 	return propertySet, tag
 }
 
@@ -180,12 +209,13 @@
 func (m *bpModule) transform(transformer bpTransformer) *bpModule {
 	transformedModule := transformer.transformModule(m)
 	// Copy the contents of the returned property set into the module and then transform that.
-	transformedModule.bpPropertySet, _ = transformer.transformPropertySet("", transformedModule.bpPropertySet, nil)
-	transformedModule.bpPropertySet.transform(transformer)
+	transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
 	return transformedModule
 }
 
-type deepCopyTransformation struct{}
+type deepCopyTransformation struct {
+	identityTransformation
+}
 
 func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
 	// Take a shallow copy of the module. Any mutable property values will be copied by the
@@ -194,7 +224,7 @@
 	return &moduleCopy
 }
 
-func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+func (t deepCopyTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
 	// Create a shallow copy of the properties map. Any mutable property values will be copied by the
 	// transformer.
 	propertiesCopy := make(map[string]interface{})
@@ -253,10 +283,19 @@
 }
 
 func (f *bpFile) newModule(moduleType string) *bpModule {
+	return newModule(moduleType)
+}
+
+func newModule(moduleType string) *bpModule {
 	module := &bpModule{
 		moduleType:    moduleType,
-		bpPropertySet: &bpPropertySet{},
+		bpPropertySet: newPropertySet(),
 	}
-	module.bpPropertySet.init()
 	return module
 }
+
+func newPropertySet() *bpPropertySet {
+	set := &bpPropertySet{}
+	set.init()
+	return set
+}
diff --git a/sdk/bp_test.go b/sdk/bp_test.go
new file mode 100644
index 0000000..f89f38c
--- /dev/null
+++ b/sdk/bp_test.go
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sdk
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+type removeFredTransformation struct {
+	identityTransformation
+}
+
+func (t removeFredTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
+	if name == "fred" {
+		return nil, nil
+	}
+	return value, tag
+}
+
+func (t removeFredTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	if name == "fred" {
+		return nil, nil
+	}
+	return propertySet, tag
+}
+
+func (t removeFredTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	if len(propertySet.properties) == 0 {
+		return nil, nil
+	}
+	return propertySet, tag
+}
+
+func TestTransformRemoveProperty(t *testing.T) {
+
+	helper := &TestHelper{t}
+
+	set := newPropertySet()
+	set.AddProperty("name", "name")
+	set.AddProperty("fred", "12")
+
+	set.transformContents(removeFredTransformation{})
+
+	contents := &generatedContents{}
+	outputPropertySet(contents, set)
+	helper.AssertTrimmedStringEquals("removing property failed", "name: \"name\",\\n", contents.content.String())
+}
+
+func TestTransformRemovePropertySet(t *testing.T) {
+
+	helper := &TestHelper{t}
+
+	set := newPropertySet()
+	set.AddProperty("name", "name")
+	set.AddPropertySet("fred")
+
+	set.transformContents(removeFredTransformation{})
+
+	contents := &generatedContents{}
+	outputPropertySet(contents, set)
+	helper.AssertTrimmedStringEquals("removing property set failed", "name: \"name\",\\n", contents.content.String())
+}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 9c8e292..ecb1da0 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -749,3 +749,199 @@
 `),
 	)
 }
+
+func TestHostSnapshotWithMultiLib64(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		module_exports {
+			name: "myexports",
+			device_supported: false,
+			host_supported: true,
+			target: {
+				host: {
+					compile_multilib: "64",
+				},
+			},
+			native_static_libs: ["mynativelib"],
+		}
+
+		cc_library_static {
+			name: "mynativelib",
+			device_supported: false,
+			host_supported: true,
+			srcs: [
+				"Test.cpp",
+				"aidl/foo/bar/Test.aidl",
+			],
+			export_include_dirs: ["include"],
+			aidl: {
+				export_aidl_headers: true,
+			},
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("myexports", "linux_glibc_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_static {
+    name: "myexports_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/mynativelib.a"],
+            export_include_dirs: ["x86_64/include_gen/mynativelib"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_static {
+    name: "mynativelib",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    arch: {
+        x86_64: {
+            srcs: ["x86_64/lib/mynativelib.a"],
+            export_include_dirs: ["x86_64/include_gen/mynativelib"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    device_supported: false,
+    host_supported: true,
+    target: {
+        host: {
+            compile_multilib: "64",
+        },
+    },
+    native_static_libs: ["myexports_mynativelib@current"],
+}`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/mynativelib.a -> x86_64/lib/mynativelib.a
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/Test.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/BnTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BnTest.h
+.intermediates/mynativelib/linux_glibc_x86_64_static/gen/aidl/aidl/foo/bar/BpTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BpTest.h
+`),
+	)
+}
+
+func TestSnapshotWithCcHeadersLibrary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_header_libs: ["mynativeheaders"],
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			export_include_dirs: ["include"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "android_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mysdk_mynativeheaders@current",
+    sdk_member_name: "mynativeheaders",
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+`),
+	)
+}
+
+func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			device_supported: false,
+			host_supported: true,
+			native_header_libs: ["mynativeheaders"],
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			device_supported: false,
+			host_supported: true,
+			export_include_dirs: ["include"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mysdk_mynativeheaders@current",
+    sdk_member_name: "mynativeheaders",
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    export_include_dirs: ["include/include"],
+    stl: "none",
+    system_shared_libs: [],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    device_supported: false,
+    host_supported: true,
+    native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+`),
+	)
+}
diff --git a/sdk/update.go b/sdk/update.go
index ff567be..d211e80 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -107,10 +107,15 @@
 // The members are first grouped by type and then grouped by name. The order of
 // the types is the order they are referenced in android.SdkMemberTypesRegistry.
 // The names are in the order in which the dependencies were added.
-func (s *sdk) collectMembers(ctx android.ModuleContext) []*sdkMember {
+//
+// Returns the members as well as the multilib setting to use.
+func (s *sdk) collectMembers(ctx android.ModuleContext) ([]*sdkMember, string) {
 	byType := make(map[android.SdkMemberType][]*sdkMember)
 	byName := make(map[string]*sdkMember)
 
+	lib32 := false // True if any of the members have 32 bit version.
+	lib64 := false // True if any of the members have 64 bit version.
+
 	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 		tag := ctx.OtherModuleDependencyTag(child)
 		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
@@ -122,7 +127,6 @@
 			}
 
 			name := ctx.OtherModuleName(child)
-
 			member := byName[name]
 			if member == nil {
 				member = &sdkMember{memberType: memberType, name: name}
@@ -130,6 +134,13 @@
 				byType[memberType] = append(byType[memberType], member)
 			}
 
+			multilib := child.Target().Arch.ArchType.Multilib
+			if multilib == "lib32" {
+				lib32 = true
+			} else if multilib == "lib64" {
+				lib64 = true
+			}
+
 			// Only append new variants to the list. This is needed because a member can be both
 			// exported by the sdk and also be a transitive sdk member.
 			member.variants = appendUniqueVariants(member.variants, child.(android.SdkAware))
@@ -148,7 +159,17 @@
 		members = append(members, membersOfType...)
 	}
 
-	return members
+	// Compute the setting of multilib.
+	var multilib string
+	if lib32 && lib64 {
+		multilib = "both"
+	} else if lib32 {
+		multilib = "32"
+	} else if lib64 {
+		multilib = "64"
+	}
+
+	return members, multilib
 }
 
 func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
@@ -207,7 +228,8 @@
 	}
 	s.builderForTests = builder
 
-	for _, member := range s.collectMembers(ctx) {
+	members, multilib := s.collectMembers(ctx)
+	for _, member := range members {
 		member.memberType.BuildSnapshot(ctx, builder, member)
 	}
 
@@ -219,6 +241,9 @@
 	unversionedTransformer := unversionedTransformation{builder: builder}
 
 	for _, unversioned := range builder.prebuiltOrder {
+		// Prune any empty property sets.
+		unversioned = unversioned.transform(pruneEmptySetTransformer{})
+
 		// Copy the unversioned module so it can be modified to make it versioned.
 		versioned := unversioned.deepCopy()
 
@@ -249,6 +274,16 @@
 	}
 
 	addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
+
+	// Compile_multilib defaults to both and must always be set to both on the
+	// device and so only needs to be set when targeted at the host and is neither
+	// unspecified or both.
+	if s.HostSupported() && multilib != "" && multilib != "both" {
+		targetSet := snapshotModule.AddPropertySet("target")
+		hostSet := targetSet.AddPropertySet("host")
+		hostSet.AddProperty("compile_multilib", multilib)
+	}
+
 	for _, memberListProperty := range s.memberListProperties() {
 		names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
 		if len(names) > 0 {
@@ -357,6 +392,20 @@
 	}
 }
 
+type pruneEmptySetTransformer struct {
+	identityTransformation
+}
+
+var _ bpTransformer = (*pruneEmptySetTransformer)(nil)
+
+func (t pruneEmptySetTransformer) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
+	if len(propertySet.properties) == 0 {
+		return nil, nil
+	} else {
+		return propertySet, tag
+	}
+}
+
 func generateBpContents(contents *generatedContents, bpFile *bpFile) {
 	contents.Printfln("// This is auto-generated. DO NOT EDIT.")
 	for _, bpModule := range bpFile.order {
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index ce404f8..65dbb22 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -144,6 +144,9 @@
 	// list of .sysprop files which defines the properties.
 	Srcs []string `android:"path"`
 
+	// If set to true, build a variant of the module for the host.  Defaults to false.
+	Host_supported *bool
+
 	// Whether public stub exists or not.
 	Public_stub *bool `blueprint:"mutated"`
 }
@@ -306,12 +309,20 @@
 	Sysprop          struct {
 		Platform *bool
 	}
-	Header_libs        []string
-	Shared_libs        []string
+	Target struct {
+		Android struct {
+			Header_libs []string
+			Shared_libs []string
+		}
+		Host struct {
+			Static_libs []string
+		}
+	}
 	Required           []string
 	Recovery           *bool
 	Recovery_available *bool
 	Vendor_available   *bool
+	Host_supported     *bool
 }
 
 type javaLibraryProperties struct {
@@ -394,10 +405,12 @@
 	ccProps.Device_specific = proptools.BoolPtr(ctx.DeviceSpecific())
 	ccProps.Product_specific = proptools.BoolPtr(ctx.ProductSpecific())
 	ccProps.Sysprop.Platform = proptools.BoolPtr(isOwnerPlatform)
-	ccProps.Header_libs = []string{"libbase_headers"}
-	ccProps.Shared_libs = []string{"liblog"}
+	ccProps.Target.Android.Header_libs = []string{"libbase_headers"}
+	ccProps.Target.Android.Shared_libs = []string{"liblog"}
+	ccProps.Target.Host.Static_libs = []string{"libbase", "liblog"}
 	ccProps.Recovery_available = m.properties.Recovery_available
 	ccProps.Vendor_available = m.properties.Vendor_available
+	ccProps.Host_supported = m.properties.Host_supported
 	ctx.CreateModule(cc.LibraryFactory, &ccProps)
 
 	scope := "internal"
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 7cad3da..51da222 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -161,6 +161,7 @@
 			api_packages: ["android.sysprop"],
 			property_owner: "Platform",
 			vendor_available: true,
+			host_supported: true,
 		}
 
 		sysprop_library {
@@ -244,6 +245,11 @@
 			static_libs: ["sysprop-platform", "sysprop-vendor"],
 		}
 
+		cc_library {
+			name: "libbase",
+			host_supported: true,
+		}
+
 		cc_library_headers {
 			name: "libbase_headers",
 			vendor_available: true,
@@ -256,6 +262,12 @@
 			nocrt: true,
 			system_shared_libs: [],
 			recovery_available: true,
+			host_supported: true,
+		}
+
+		cc_binary_host {
+			name: "hostbin",
+			static_libs: ["sysprop-platform"],
 		}
 
 		llndk_library {