Merge "DO NOT MERGE: Remove AppSearch from Android R."
diff --git a/android/arch.go b/android/arch.go
index 922548e..e440486 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -596,7 +596,7 @@
 }()
 
 var (
-	osTypeList      []OsType
+	OsTypeList      []OsType
 	commonTargetMap = make(map[string]Target)
 
 	NoOsType    OsType
@@ -672,7 +672,7 @@
 
 		DefaultDisabled: defDisabled,
 	}
-	osTypeList = append(osTypeList, os)
+	OsTypeList = append(OsTypeList, os)
 
 	if _, found := commonTargetMap[name]; found {
 		panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
@@ -684,7 +684,7 @@
 }
 
 func osByName(name string) OsType {
-	for _, os := range osTypeList {
+	for _, os := range OsTypeList {
 		if os.Name == name {
 			return os
 		}
@@ -750,7 +750,7 @@
 
 	var moduleOSList []OsType
 
-	for _, os := range osTypeList {
+	for _, os := range OsTypeList {
 		supportedClass := false
 		for _, osClass := range osClasses {
 			if os.Class == osClass {
@@ -1071,7 +1071,7 @@
 			"Arm_on_x86",
 			"Arm_on_x86_64",
 		}
-		for _, os := range osTypeList {
+		for _, os := range OsTypeList {
 			targets = append(targets, os.Field)
 
 			for _, archType := range osArchTypeMap[os] {
diff --git a/android/sdk.go b/android/sdk.go
index d13ad7d..969e21a 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -302,7 +302,46 @@
 	//
 	// The SdkMember is guaranteed to contain variants for which the
 	// IsInstance(Module) method returned true.
+	//
+	// deprecated Use AddPrebuiltModule() instead.
 	BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
+
+	// Add a prebuilt module that the sdk will populate.
+	//
+	// Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
+	// method to build the snapshot. That method is deprecated because it requires the SdkMemberType
+	// implementation to do all the word.
+	//
+	// Otherwise, returning a non-nil value from this will cause the sdk module type to do the
+	// majority of the work to generate the snapshot. The sdk module code generates the snapshot
+	// as follows:
+	//
+	// * A properties struct of type SdkMemberProperties is created for each variant and
+	//   populated with information from the variant by calling PopulateFromVariant(SdkAware)
+	//   on the struct.
+	//
+	// * An additional properties struct is created into which the common properties will be
+	//   added.
+	//
+	// * The variant property structs are analysed to find exported (capitalized) fields which
+	//   have common values. Those fields are cleared and the common value added to the common
+	//   properties.
+	//
+	// * The sdk module type populates the BpModule structure, creating the arch specific
+	//   structure and calls AddToPropertySet(...) on the properties struct to add the member
+	//   specific properties in the correct place in the structure.
+	//
+	// * Finally, the FinalizeModule(...) method is called to add any additional properties.
+	//   This was created to allow the property ordering in existing tests to be maintained so
+	//   as to avoid having to change tests while refactoring.
+	//
+	AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule
+
+	// Add any additional properties to the end of the module.
+	FinalizeModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember, bpModule BpModule)
+
+	// Create a structure into which variant specific properties can be added.
+	CreateVariantPropertiesStruct() SdkMemberProperties
 }
 
 // Base type for SdkMemberType implementations.
@@ -324,6 +363,23 @@
 	return b.TransitiveSdkMembers
 }
 
+func (b *SdkMemberTypeBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) {
+	panic("override AddPrebuiltModule")
+}
+
+func (b *SdkMemberTypeBase) AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule {
+	// Returning nil causes the legacy BuildSnapshot method to be used.
+	return nil
+}
+
+func (b *SdkMemberTypeBase) FinalizeModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember, module BpModule) {
+	// Do nothing by default
+}
+
+func (b *SdkMemberTypeBase) CreateVariantPropertiesStruct() SdkMemberProperties {
+	panic("override me")
+}
+
 // Encapsulates the information about registered SdkMemberTypes.
 type SdkMemberTypesRegistry struct {
 	// The list of types sorted by property name.
@@ -389,3 +445,50 @@
 		SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType)
 	}
 }
+
+// Base structure for all implementations of SdkMemberProperties.
+//
+// Contains common properties that apply across many different member types. These
+// are not affected by the optimization to extract common values.
+type SdkMemberPropertiesBase struct {
+	// The setting to use for the compile_multilib property.
+	Compile_multilib string
+
+	// The number of unique os types supported by the member variants.
+	Os_count int
+
+	// The os type for which these properties refer.
+	Os OsType
+}
+
+// The os prefix to use for any file paths in the sdk.
+//
+// Is an empty string if the member only provides variants for a single os type, otherwise
+// is the OsType.Name.
+func (b *SdkMemberPropertiesBase) OsPrefix() string {
+	if b.Os_count == 1 {
+		return ""
+	} else {
+		return b.Os.Name
+	}
+}
+
+func (b *SdkMemberPropertiesBase) Base() *SdkMemberPropertiesBase {
+	return b
+}
+
+// Interface to be implemented on top of a structure that contains variant specific
+// information.
+//
+// Struct fields that are capitalized are examined for common values to extract. Fields
+// that are not capitalized are assumed to be arch specific.
+type SdkMemberProperties interface {
+	// Access the base structure.
+	Base() *SdkMemberPropertiesBase
+
+	// Populate the structure with information from the variant.
+	PopulateFromVariant(variant SdkAware)
+
+	// Add the information from the structure to the property set.
+	AddToPropertySet(sdkModuleContext ModuleContext, builder SnapshotBuilder, propertySet BpPropertySet)
+}
diff --git a/apex/apex.go b/apex/apex.go
index 736ce85..cb1f263 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1993,7 +1993,7 @@
 		if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, to) {
 			return
 		}
-		ctx.ModuleErrorf("requires %q that is not available for the APEX.", to.Name())
+		ctx.ModuleErrorf("%q requires %q that is not available for the APEX.", from.Name(), to.Name())
 	})
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2b13197..7b842da 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -3345,7 +3345,7 @@
 
 func TestApexPropertiesShouldBeDefaultable(t *testing.T) {
 	// libfoo's apex_available comes from cc_defaults
-	testApexError(t, `"myapex" .*: requires "libfoo" that is not available for the APEX`, `
+	testApexError(t, `"myapex" .*: "myapex" requires "libfoo" that is not available for the APEX`, `
 	apex {
 		name: "myapex",
 		key: "myapex.key",
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 58d6ad0..fc9b89e 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -16,7 +16,6 @@
 
 import (
 	"path/filepath"
-	"strings"
 
 	"android/soong/android"
 	"github.com/google/blueprint"
@@ -64,65 +63,13 @@
 	return false
 }
 
-func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	info := mt.organizeVariants(member)
-	buildSharedNativeBinarySnapshot(info, builder, member)
-}
-
-// Organize the variants by architecture.
-func (mt *binarySdkMemberType) organizeVariants(member android.SdkMember) *nativeBinaryInfo {
-	memberName := member.Name()
-	info := &nativeBinaryInfo{
-		name:       memberName,
-		memberType: mt,
-	}
-
-	for _, variant := range member.Variants() {
-		ccModule := variant.(*Module)
-
-		info.archVariantProperties = append(info.archVariantProperties, nativeBinaryInfoProperties{
-			name:       memberName,
-			archType:   ccModule.Target().Arch.ArchType.String(),
-			outputFile: ccModule.OutputFile().Path(),
-		})
-	}
-
-	// Initialize the unexported properties that will not be set during the
-	// extraction process.
-	info.commonProperties.name = memberName
-
-	// Extract common properties from the arch specific properties.
-	extractCommonProperties(&info.commonProperties, info.archVariantProperties)
-
-	return info
-}
-
-func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
+func (mt *binarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
 	pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
-	archVariantCount := len(info.archVariantProperties)
+	return pbm
+}
 
-	// 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)
-		archTypeProperties.AddProperty("srcs", []string{nativeBinaryPathFor(av)})
-
-		builder.CopyToSnapshot(av.outputFile, nativeBinaryPathFor(av))
-	}
+func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &nativeBinaryInfoProperties{}
 }
 
 const (
@@ -131,7 +78,7 @@
 
 // path to the native binary. Relative to <sdk_root>/<api_dir>
 func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
-	return filepath.Join(lib.archType,
+	return filepath.Join(lib.OsPrefix(), lib.archType,
 		nativeBinaryDir, lib.outputFile.Base())
 }
 
@@ -140,8 +87,7 @@
 // The exported (capitalized) fields will be examined and may be changed during common value extraction.
 // The unexported fields will be left untouched.
 type nativeBinaryInfoProperties struct {
-	// The name of the library, is not exported as this must not be changed during optimization.
-	name string
+	android.SdkMemberPropertiesBase
 
 	// archType is not exported as if set (to a non default value) it is always arch specific.
 	// This is "" for common properties.
@@ -151,10 +97,21 @@
 	outputFile android.Path
 }
 
-// nativeBinaryInfo represents a collection of arch-specific modules having the same name
-type nativeBinaryInfo struct {
-	name                  string
-	memberType            *binarySdkMemberType
-	archVariantProperties []nativeBinaryInfoProperties
-	commonProperties      nativeBinaryInfoProperties
+func (p *nativeBinaryInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+	ccModule := variant.(*Module)
+
+	p.archType = ccModule.Target().Arch.ArchType.String()
+	p.outputFile = ccModule.OutputFile().Path()
+}
+
+func (p *nativeBinaryInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+	if p.Compile_multilib != "" {
+		propertySet.AddProperty("compile_multilib", p.Compile_multilib)
+	}
+
+	if p.outputFile != nil {
+		propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
+
+		builder.CopyToSnapshot(p.outputFile, nativeBinaryPathFor(*p))
+	}
 }
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index a36917e..656df69 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -16,7 +16,6 @@
 
 import (
 	"path/filepath"
-	"reflect"
 
 	"android/soong/android"
 	"github.com/google/blueprint"
@@ -96,48 +95,25 @@
 	return false
 }
 
-// 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)
-	info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
+func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
+	pbm := builder.AddPrebuiltModule(member, mt.prebuiltModuleType)
+
+	ccModule := member.Variants()[0].(*Module)
+
+	sdkVersion := ccModule.SdkVersion()
+	if sdkVersion != "" {
+		pbm.AddProperty("sdk_version", sdkVersion)
+	}
+	return pbm
 }
 
-// Organize the variants by architecture.
-func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
-	memberName := member.Name()
-	info := &nativeLibInfo{
-		name:       memberName,
-		memberType: mt,
-	}
+func (mt *librarySdkMemberType) FinalizeModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember, bpModule android.BpModule) {
+	bpModule.AddProperty("stl", "none")
+	bpModule.AddProperty("system_shared_libs", []string{})
+}
 
-	for _, variant := range member.Variants() {
-		ccModule := variant.(*Module)
-
-		// Separate out the generated include dirs (which are arch specific) from the
-		// include dirs (which may not be).
-		exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
-			ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
-
-		info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
-			name:                         memberName,
-			archType:                     ccModule.Target().Arch.ArchType.String(),
-			ExportedIncludeDirs:          exportedIncludeDirs,
-			exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
-			ExportedSystemIncludeDirs:    ccModule.ExportedSystemIncludeDirs(),
-			ExportedFlags:                ccModule.ExportedFlags(),
-			exportedGeneratedHeaders:     ccModule.ExportedGeneratedHeaders(),
-			outputFile:                   ccModule.OutputFile().Path(),
-		})
-	}
-
-	// Initialize the unexported properties that will not be set during the
-	// extraction process.
-	info.commonProperties.name = memberName
-
-	// Extract common properties from the arch specific properties.
-	extractCommonProperties(&info.commonProperties, info.archVariantProperties)
-
-	return info
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &nativeLibInfoProperties{memberType: mt}
 }
 
 func isGeneratedHeaderDirectory(p android.Path) bool {
@@ -145,94 +121,9 @@
 	return gen
 }
 
-// Extract common properties from a slice of property structures of the same type.
-//
-// All the property structures must be of the same type.
-// commonProperties - must be a pointer to the structure into which common properties will be added.
-// inputPropertiesSlice - must be a slice of input properties structures.
-//
-// Iterates over each exported field (capitalized name) and checks to see whether they
-// have the same value (using DeepEquals) across all the input properties. If it does not then no
-// change is made. Otherwise, the common value is stored in the field in the commonProperties
-// and the field in each of the input properties structure is set to its default value.
-func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
-	commonStructValue := reflect.ValueOf(commonProperties).Elem()
-	propertiesStructType := commonStructValue.Type()
-
-	// Create an empty structure from which default values for the field can be copied.
-	emptyStructValue := reflect.New(propertiesStructType).Elem()
-
-	for f := 0; f < propertiesStructType.NumField(); f++ {
-		// Check to see if all the structures have the same value for the field. The commonValue
-		// is nil on entry to the loop and if it is nil on exit then there is no common value,
-		// otherwise it points to the common value.
-		var commonValue *reflect.Value
-		sliceValue := reflect.ValueOf(inputPropertiesSlice)
-
-		for i := 0; i < sliceValue.Len(); i++ {
-			structValue := sliceValue.Index(i)
-			fieldValue := structValue.Field(f)
-			if !fieldValue.CanInterface() {
-				// The field is not exported so ignore it.
-				continue
-			}
-
-			if commonValue == nil {
-				// Use the first value as the commonProperties value.
-				commonValue = &fieldValue
-			} else {
-				// If the value does not match the current common value then there is
-				// no value in common so break out.
-				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
-					commonValue = nil
-					break
-				}
-			}
-		}
-
-		// If the fields all have a common value then store it in the common struct field
-		// and set the input struct's field to the empty value.
-		if commonValue != nil {
-			emptyValue := emptyStructValue.Field(f)
-			commonStructValue.Field(f).Set(*commonValue)
-			for i := 0; i < sliceValue.Len(); i++ {
-				structValue := sliceValue.Index(i)
-				fieldValue := structValue.Field(f)
-				fieldValue.Set(emptyValue)
-			}
-		}
-	}
-}
-
-func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-
-	pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
-
-	addPossiblyArchSpecificProperties(sdkModuleContext, builder, info.commonProperties, pbm)
-
-	archProperties := pbm.AddPropertySet("arch")
-	for _, av := range info.archVariantProperties {
-		archTypeProperties := archProperties.AddPropertySet(av.archType)
-
-		// 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{})
-}
-
 type includeDirsProperty struct {
 	// Accessor to retrieve the paths
-	pathsGetter func(libInfo nativeLibInfoProperties) android.Paths
+	pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths
 
 	// The name of the property in the prebuilt library, "" means there is no property.
 	propertyName string
@@ -252,7 +143,7 @@
 		// 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 },
+		pathsGetter:  func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
 		propertyName: "export_include_dirs",
 		snapshotDir:  nativeIncludeDir,
 		copy:         true,
@@ -262,7 +153,7 @@
 		// 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 },
+		pathsGetter:  func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
 		propertyName: "export_system_include_dirs",
 		snapshotDir:  nativeIncludeDir,
 		copy:         true,
@@ -273,7 +164,7 @@
 		// 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 },
+		pathsGetter:  func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
 		propertyName: "export_include_dirs",
 		snapshotDir:  nativeGeneratedIncludeDir,
 		copy:         false,
@@ -284,7 +175,7 @@
 		// 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 },
+		pathsGetter:  func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
 		propertyName: "",
 		snapshotDir:  nativeGeneratedIncludeDir,
 		copy:         true,
@@ -293,7 +184,14 @@
 }
 
 // Add properties that may, or may not, be arch specific.
-func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+
+	// Copy the generated library to the snapshot and add a reference to it in the .bp module.
+	if libInfo.outputFile != nil {
+		nativeLibraryPath := nativeLibraryPathFor(libInfo)
+		builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath)
+		outputProperties.AddProperty("srcs", []string{nativeLibraryPath})
+	}
 
 	// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
 	includeDirs := make(map[string][]string)
@@ -355,8 +253,8 @@
 )
 
 // path to the native library. Relative to <sdk_root>/<api_dir>
-func nativeLibraryPathFor(lib nativeLibInfoProperties) string {
-	return filepath.Join(lib.archType,
+func nativeLibraryPathFor(lib *nativeLibInfoProperties) string {
+	return filepath.Join(lib.OsPrefix(), lib.archType,
 		nativeStubDir, lib.outputFile.Base())
 }
 
@@ -365,6 +263,10 @@
 // The exported (capitalized) fields will be examined and may be changed during common value extraction.
 // The unexported fields will be left untouched.
 type nativeLibInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	memberType *librarySdkMemberType
+
 	// The name of the library, is not exported as this must not be changed during optimization.
 	name string
 
@@ -401,10 +303,29 @@
 	outputFile android.Path
 }
 
-// nativeLibInfo represents a collection of arch-specific modules having the same name
-type nativeLibInfo struct {
-	name                  string
-	memberType            *librarySdkMemberType
-	archVariantProperties []nativeLibInfoProperties
-	commonProperties      nativeLibInfoProperties
+func (p *nativeLibInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+	ccModule := variant.(*Module)
+
+	// If the library has some link types then it produces an output binary file, otherwise it
+	// is header only.
+	if p.memberType.linkTypes != nil {
+		p.outputFile = ccModule.OutputFile().Path()
+	}
+
+	// Separate out the generated include dirs (which are arch specific) from the
+	// include dirs (which may not be).
+	exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
+		ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
+
+	p.name = variant.Name()
+	p.archType = ccModule.Target().Arch.ArchType.String()
+	p.ExportedIncludeDirs = exportedIncludeDirs
+	p.exportedGeneratedIncludeDirs = exportedGeneratedIncludeDirs
+	p.ExportedSystemIncludeDirs = ccModule.ExportedSystemIncludeDirs()
+	p.ExportedFlags = ccModule.ExportedFlags()
+	p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
+}
+
+func (p *nativeLibInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+	addPossiblyArchSpecificProperties(sdkModuleContext, builder, p, propertySet)
 }
diff --git a/cc/testing.go b/cc/testing.go
index a22763a..b8a7eab 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -34,7 +34,7 @@
 	ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
 }
 
-func GatherRequiredDepsForTest(os android.OsType) string {
+func GatherRequiredDepsForTest(oses ...android.OsType) string {
 	ret := `
 		toolchain_library {
 			name: "libatomic",
@@ -341,8 +341,9 @@
 		}
 	`
 
-	if os == android.Fuchsia {
-		ret += `
+	for _, os := range oses {
+		if os == android.Fuchsia {
+			ret += `
 		cc_library {
 			name: "libbioniccompat",
 			stl: "none",
@@ -352,6 +353,22 @@
 			stl: "none",
 		}
 		`
+		}
+		if os == android.Windows {
+			ret += `
+		toolchain_library {
+			name: "libwinpthread",
+			host_supported: true,
+			enabled: false,
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+			src: "",
+		}
+		`
+		}
 	}
 	return ret
 }
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index d7adb40..6ec919c 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -379,6 +379,7 @@
 		FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
 		FlagWithArg("--android-root=", global.EmptyDirectory).
 		FlagWithArg("--no-inline-from=", "core-oj.jar").
+		Flag("--force-determinism").
 		Flag("--abort-on-hard-verifier-error")
 
 	if global.BootFlags != "" {
diff --git a/java/java.go b/java/java.go
index 135ae51..d0b5adf 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1879,12 +1879,12 @@
 )
 
 // path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
-func sdkSnapshotFilePathForJar(member android.SdkMember) string {
-	return sdkSnapshotFilePathForMember(member, jarFileSuffix)
+func sdkSnapshotFilePathForJar(osPrefix, name string) string {
+	return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
 }
 
-func sdkSnapshotFilePathForMember(member android.SdkMember, suffix string) string {
-	return filepath.Join(javaDir, member.Name()+suffix)
+func sdkSnapshotFilePathForMember(osPrefix, name string, suffix string) string {
+	return filepath.Join(javaDir, osPrefix, name+suffix)
 }
 
 type librarySdkMemberType struct {
@@ -1904,32 +1904,46 @@
 	return ok
 }
 
-func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
+	return builder.AddPrebuiltModule(member, "java_import")
+}
 
-	variants := member.Variants()
-	if len(variants) != 1 {
-		sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
-		for _, variant := range variants {
-			sdkModuleContext.ModuleErrorf("    %q", variant)
-		}
-	}
-	variant := variants[0]
+func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &librarySdkMemberProperties{memberType: mt}
+}
+
+type librarySdkMemberProperties struct {
+	android.SdkMemberPropertiesBase
+
+	memberType *librarySdkMemberType
+
+	library     *Library
+	jarToExport android.Path
+}
+
+func (p *librarySdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
 	j := variant.(*Library)
 
-	exportedJar := mt.jarToExportGetter(j)
-	snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
-	builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+	p.library = j
+	p.jarToExport = p.memberType.jarToExportGetter(j)
+}
 
-	for _, dir := range j.AidlIncludeDirs() {
-		// TODO(jiyong): copy parcelable declarations only
-		aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
-		for _, file := range aidlFiles {
-			builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
+func (p *librarySdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+	if p.jarToExport != nil {
+		exportedJar := p.jarToExport
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.library.Name())
+		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
+
+		for _, dir := range p.library.AidlIncludeDirs() {
+			// TODO(jiyong): copy parcelable declarations only
+			aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
+			for _, file := range aidlFiles {
+				builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
+			}
 		}
-	}
 
-	module := builder.AddPrebuiltModule(member, "java_import")
-	module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+	}
 }
 
 var javaHeaderLibsSdkMemberType android.SdkMemberType = &librarySdkMemberType{
@@ -2094,31 +2108,44 @@
 	return ok
 }
 
-func (mt *testSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	variants := member.Variants()
-	if len(variants) != 1 {
-		sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
-		for _, variant := range variants {
-			sdkModuleContext.ModuleErrorf("    %q", variant)
-		}
-	}
-	variant := variants[0]
-	j := variant.(*Test)
+func (mt *testSdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
+	return builder.AddPrebuiltModule(member, "java_test_import")
+}
 
-	implementationJars := j.ImplementationJars()
+func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &testSdkMemberProperties{}
+}
+
+type testSdkMemberProperties struct {
+	android.SdkMemberPropertiesBase
+
+	test        *Test
+	jarToExport android.Path
+}
+
+func (p *testSdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
+	test := variant.(*Test)
+
+	implementationJars := test.ImplementationJars()
 	if len(implementationJars) != 1 {
-		panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+		panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
 	}
 
-	snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
-	builder.CopyToSnapshot(implementationJars[0], snapshotRelativeJavaLibPath)
+	p.test = test
+	p.jarToExport = implementationJars[0]
+}
 
-	snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(member, testConfigSuffix)
-	builder.CopyToSnapshot(j.testConfig, snapshotRelativeTestConfigPath)
+func (p *testSdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+	if p.jarToExport != nil {
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.test.Name())
+		builder.CopyToSnapshot(p.jarToExport, snapshotRelativeJavaLibPath)
 
-	module := builder.AddPrebuiltModule(member, "java_test_import")
-	module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
-	module.AddProperty("test_config", snapshotRelativeTestConfigPath)
+		snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), p.test.Name(), testConfigSuffix)
+		builder.CopyToSnapshot(p.test.testConfig, snapshotRelativeTestConfigPath)
+
+		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+		propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
+	}
 }
 
 // java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
@@ -2321,7 +2348,7 @@
 //
 
 type ImportProperties struct {
-	Jars []string `android:"path"`
+	Jars []string `android:"path,arch_variant"`
 
 	Sdk_version *string
 
diff --git a/java/sdk.go b/java/sdk.go
index 1e60d67..d230ccd 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -283,6 +283,28 @@
 	}
 }
 
+func (s sdkSpec) validateSystemSdk(ctx android.EarlyModuleContext) bool {
+	// Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
+	// Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
+	// sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
+	if s.kind != sdkSystem || !s.version.isNumbered() {
+		return true
+	}
+	allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
+	if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+		systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions()
+		if len(systemSdkVersions) > 0 {
+			allowedVersions = systemSdkVersions
+		}
+	}
+	if len(allowedVersions) > 0 && !android.InList(s.version.String(), allowedVersions) {
+		ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
+			s.raw, allowedVersions)
+		return false
+	}
+	return true
+}
+
 func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep {
 	sdkVersion := sdkContext.sdkVersion()
 	if !sdkVersion.valid() {
@@ -293,6 +315,9 @@
 	if ctx.Config().IsPdkBuild() {
 		sdkVersion = sdkVersion.forPdkBuild(ctx)
 	}
+	if !sdkVersion.validateSystemSdk(ctx) {
+		return sdkDep{}
+	}
 
 	if sdkVersion.usePrebuilt(ctx) {
 		dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), sdkVersion.kind.String())
@@ -340,21 +365,6 @@
 		}
 	}
 
-	// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
-	// or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
-	if sdkVersion.kind == sdkSystem && sdkVersion.version.isNumbered() {
-		allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
-		if ctx.DeviceSpecific() || ctx.SocSpecific() {
-			if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
-				allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
-			}
-		}
-		if len(allowed_versions) > 0 && !android.InList(sdkVersion.version.String(), allowed_versions) {
-			ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
-				sdkVersion.raw, allowed_versions)
-		}
-	}
-
 	switch sdkVersion.kind {
 	case sdkPrivate:
 		return sdkDep{
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 076b3f5..9e97a60 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1 +1,2 @@
 per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
+per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
new file mode 100755
index 0000000..79e40dd
--- /dev/null
+++ b/scripts/build-mainline-modules.sh
@@ -0,0 +1,63 @@
+#!/bin/bash -ex
+
+# Non exhaustive list of modules where we want prebuilts. More can be added as
+# needed.
+MAINLINE_MODULES=(
+  com.android.art.debug
+  com.android.art.release
+  com.android.art.testing
+  com.android.conscrypt
+  com.android.runtime
+  com.android.tzdata
+  com.android.i18n
+)
+
+# List of SDKs and module exports we know of.
+MODULES_SDK_AND_EXPORTS=(
+  art-module-sdk
+  art-module-test-exports
+  conscrypt-module-sdk
+  conscrypt-module-test-exports
+)
+
+# We want to create apex modules for all supported architectures.
+PRODUCTS=(
+    aosp_arm
+    aosp_arm64
+    aosp_x86
+    aosp_x86_64
+)
+
+if [ ! -e "build/make/core/Makefile" ]; then
+    echo "$0 must be run from the top of the tree"
+    exit 1
+fi
+
+OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR)
+DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR)
+
+for product in "${PRODUCTS[@]}"; do
+    build/soong/soong_ui.bash --make-mode $@ \
+        TARGET_PRODUCT=${product} \
+        ${MAINLINE_MODULES[@]}
+
+    PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
+    TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
+    rm -rf ${DIST_DIR}/${TARGET_ARCH}/
+    mkdir -p ${DIST_DIR}/${TARGET_ARCH}/
+    for module in "${MAINLINE_MODULES[@]}"; do
+      cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
+    done
+done
+
+
+# Create multi-archs SDKs in a different out directory. The multi-arch script
+# uses soong directly and therefore needs its own directory that doesn't clash
+# with make.
+export OUT_DIR=${OUT_DIR}/aml/
+for sdk in "${MODULES_SDK_AND_EXPORTS[@]}"; do
+    build/soong/scripts/build-aml-prebuilts.sh ${sdk}
+done
+
+rm -rf ${DIST_DIR}/mainline-sdks
+cp -R ${OUT_DIR}/soong/mainline-sdks ${DIST_DIR}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index a14890e..11bc902 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -25,11 +25,13 @@
 	t.Helper()
 
 	fs := map[string][]byte{
-		"Test.cpp":                  nil,
-		"include/Test.h":            nil,
-		"arm64/include/Arm64Test.h": nil,
-		"libfoo.so":                 nil,
-		"aidl/foo/bar/Test.aidl":    nil,
+		"Test.cpp":                      nil,
+		"include/Test.h":                nil,
+		"include-android/AndroidTest.h": nil,
+		"include-host/HostTest.h":       nil,
+		"arm64/include/Arm64Test.h":     nil,
+		"libfoo.so":                     nil,
+		"aidl/foo/bar/Test.aidl":        nil,
 	}
 	return testSdkWithFs(t, bp, fs)
 }
@@ -401,6 +403,108 @@
 	)
 }
 
+func TestMultipleHostOsTypesSnapshotWithCcBinary(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,
+			native_binaries: ["mynativebinary"],
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+
+		cc_binary {
+			name: "mynativebinary",
+			device_supported: false,
+			host_supported: true,
+			srcs: [
+				"Test.cpp",
+			],
+			compile_multilib: "both",
+			system_shared_libs: [],
+			stl: "none",
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("myexports", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+    name: "myexports_mynativebinary@current",
+    sdk_member_name: "mynativebinary",
+    device_supported: false,
+    host_supported: true,
+    target: {
+        linux_glibc: {
+            compile_multilib: "both",
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/bin/mynativebinary"],
+        },
+        windows: {
+            compile_multilib: "64",
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+        },
+    },
+}
+
+cc_prebuilt_binary {
+    name: "mynativebinary",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    target: {
+        linux_glibc: {
+            compile_multilib: "both",
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/bin/mynativebinary"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/bin/mynativebinary"],
+        },
+        windows: {
+            compile_multilib: "64",
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/bin/mynativebinary.exe"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    device_supported: false,
+    host_supported: true,
+    native_binaries: ["myexports_mynativebinary@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativebinary/linux_glibc_x86_64/mynativebinary -> linux_glibc/x86_64/bin/mynativebinary
+.intermediates/mynativebinary/linux_glibc_x86/mynativebinary -> linux_glibc/x86/bin/mynativebinary
+.intermediates/mynativebinary/windows_x86_64/mynativebinary.exe -> windows/x86_64/bin/mynativebinary.exe
+`),
+	)
+}
+
 func TestSnapshotWithCcSharedLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
@@ -517,6 +621,7 @@
 			},
 			system_shared_libs: [],
 			stl: "none",
+			sdk_version: "minimum",
 		}
 	`)
 
@@ -529,6 +634,7 @@
     sdk_member_name: "mynativelib",
     device_supported: false,
     host_supported: true,
+    sdk_version: "minimum",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -549,6 +655,7 @@
     prefer: false,
     device_supported: false,
     host_supported: true,
+    sdk_version: "minimum",
     export_include_dirs: ["include/include"],
     arch: {
         x86_64: {
@@ -585,6 +692,99 @@
 	)
 }
 
+func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(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_shared_libs: ["mynativelib"],
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+
+		cc_library_shared {
+			name: "mynativelib",
+			device_supported: false,
+			host_supported: true,
+			srcs: [
+				"Test.cpp",
+			],
+			system_shared_libs: [],
+			stl: "none",
+			target: {
+				windows: {
+					enabled: true,
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    device_supported: false,
+    host_supported: true,
+    target: {
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/lib/mynativelib.dll"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_shared {
+    name: "mynativelib",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    target: {
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/mynativelib.so"],
+        },
+        windows_x86_64: {
+            srcs: ["windows/x86_64/lib/mynativelib.dll"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    device_supported: false,
+    host_supported: true,
+    native_shared_libs: ["mysdk_mynativelib@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> linux_glibc/x86_64/lib/mynativelib.so
+.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> linux_glibc/x86/lib/mynativelib.so
+.intermediates/mynativelib/windows_x86_64_shared/mynativelib.dll -> windows/x86_64/lib/mynativelib.dll
+`),
+	)
+}
+
 func TestSnapshotWithCcStaticLibrary(t *testing.T) {
 	result := testSdkWithCc(t, `
 		module_exports {
@@ -955,3 +1155,83 @@
 `),
 	)
 }
+
+func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			host_supported: true,
+			native_header_libs: ["mynativeheaders"],
+		}
+
+		cc_library_headers {
+			name: "mynativeheaders",
+			host_supported: true,
+			system_shared_libs: [],
+			stl: "none",
+			export_system_include_dirs: ["include"],
+			target: {
+				android: {
+					export_include_dirs: ["include-android"],
+				},
+				host: {
+					export_include_dirs: ["include-host"],
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_headers {
+    name: "mysdk_mynativeheaders@current",
+    sdk_member_name: "mynativeheaders",
+    host_supported: true,
+    export_system_include_dirs: ["include/include"],
+    target: {
+        android: {
+            export_include_dirs: ["include/include-android"],
+        },
+        linux_glibc: {
+            export_include_dirs: ["include/include-host"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+cc_prebuilt_library_headers {
+    name: "mynativeheaders",
+    prefer: false,
+    host_supported: true,
+    export_system_include_dirs: ["include/include"],
+    target: {
+        android: {
+            export_include_dirs: ["include/include-android"],
+        },
+        linux_glibc: {
+            export_include_dirs: ["include/include-host"],
+        },
+    },
+    stl: "none",
+    system_shared_libs: [],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    host_supported: true,
+    native_header_libs: ["mysdk_mynativeheaders@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+include-android/AndroidTest.h -> include/include-android/AndroidTest.h
+include-host/HostTest.h -> include/include-host/HostTest.h
+`),
+	)
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 9046eec..45da1f9 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -230,6 +230,72 @@
 	)
 }
 
+func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithJava(t, `
+		sdk {
+			name: "mysdk",
+			host_supported: true,
+			java_header_libs: ["myjavalib"],
+		}
+
+		java_library {
+			name: "myjavalib",
+			host_supported: true,
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    host_supported: true,
+    target: {
+        android: {
+            jars: ["java/android/myjavalib.jar"],
+        },
+        linux_glibc: {
+            jars: ["java/linux_glibc/myjavalib.jar"],
+        },
+    },
+}
+
+java_import {
+    name: "myjavalib",
+    prefer: false,
+    host_supported: true,
+    target: {
+        android: {
+            jars: ["java/android/myjavalib.jar"],
+        },
+        linux_glibc: {
+            jars: ["java/linux_glibc/myjavalib.jar"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    host_supported: true,
+    java_header_libs: ["mysdk_myjavalib@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+`),
+	)
+}
+
 func TestSnapshotWithJavaImplLibrary(t *testing.T) {
 	result := testSdkWithJava(t, `
 		module_exports {
diff --git a/sdk/testing.go b/sdk/testing.go
index 41333cd..464c3ca 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -40,7 +40,7 @@
 			name: "myapex.cert",
 			certificate: "myapex",
 		}
-	` + cc.GatherRequiredDepsForTest(android.Android)
+	` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
 
 	mockFS := map[string][]byte{
 		"build/make/target/product/security":         nil,
diff --git a/sdk/update.go b/sdk/update.go
index b335777..282a7a4 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"reflect"
+	"sort"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -251,7 +252,14 @@
 
 	members, multilib := s.organizeMembers(ctx, memberRefs)
 	for _, member := range members {
-		member.memberType.BuildSnapshot(ctx, builder, member)
+		memberType := member.memberType
+		prebuiltModule := memberType.AddPrebuiltModule(ctx, builder, member)
+		if prebuiltModule == nil {
+			// Fall back to legacy method of building a snapshot
+			memberType.BuildSnapshot(ctx, builder, member)
+		} else {
+			s.createMemberSnapshot(ctx, builder, member, prebuiltModule)
+		}
 	}
 
 	// Create a transformer that will transform an unversioned module into a versioned module.
@@ -643,3 +651,285 @@
 func (m *sdkMember) Variants() []android.SdkAware {
 	return m.variants
 }
+
+type baseInfo struct {
+	Properties android.SdkMemberProperties
+}
+
+type osTypeSpecificInfo struct {
+	baseInfo
+
+	// The list of arch type specific info for this os type.
+	archTypes []*archTypeSpecificInfo
+
+	// True if the member has common arch variants for this os type.
+	commonArch bool
+}
+
+type archTypeSpecificInfo struct {
+	baseInfo
+
+	archType android.ArchType
+}
+
+func (s *sdk) createMemberSnapshot(sdkModuleContext android.ModuleContext, builder *snapshotBuilder, member *sdkMember, bpModule android.BpModule) {
+
+	memberType := member.memberType
+
+	// Group the variants by os type.
+	variantsByOsType := make(map[android.OsType][]android.SdkAware)
+	variants := member.Variants()
+	for _, variant := range variants {
+		osType := variant.Target().Os
+		variantsByOsType[osType] = append(variantsByOsType[osType], variant)
+	}
+
+	osCount := len(variantsByOsType)
+	createVariantPropertiesStruct := func(os android.OsType) android.SdkMemberProperties {
+		properties := memberType.CreateVariantPropertiesStruct()
+		base := properties.Base()
+		base.Os_count = osCount
+		base.Os = os
+		return properties
+	}
+
+	osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
+
+	// The set of properties that are common across all architectures and os types.
+	commonProperties := createVariantPropertiesStruct(android.CommonOS)
+
+	// The list of property structures which are os type specific but common across
+	// architectures within that os type.
+	var osSpecificPropertiesList []android.SdkMemberProperties
+
+	for osType, osTypeVariants := range variantsByOsType {
+		// Group the properties for each variant by arch type within the os.
+		osInfo := &osTypeSpecificInfo{}
+		osTypeToInfo[osType] = osInfo
+
+		// Create a structure into which properties common across the architectures in
+		// this os type will be stored. Add it to the list of os type specific yet
+		// architecture independent properties structs.
+		osInfo.Properties = createVariantPropertiesStruct(osType)
+		osSpecificPropertiesList = append(osSpecificPropertiesList, osInfo.Properties)
+
+		commonArch := false
+		for _, variant := range osTypeVariants {
+			var properties android.SdkMemberProperties
+
+			// Get the info associated with the arch type inside the os info.
+			archType := variant.Target().Arch.ArchType
+
+			if archType.Name == "common" {
+				// The arch type is common so populate the common properties directly.
+				properties = osInfo.Properties
+
+				commonArch = true
+			} else {
+				archInfo := &archTypeSpecificInfo{archType: archType}
+				properties = createVariantPropertiesStruct(osType)
+				archInfo.Properties = properties
+
+				osInfo.archTypes = append(osInfo.archTypes, archInfo)
+			}
+
+			properties.PopulateFromVariant(variant)
+		}
+
+		if commonArch {
+			if len(osTypeVariants) != 1 {
+				panic("Expected to only have 1 variant when arch type is common but found " + string(len(variants)))
+			}
+		} else {
+			var archPropertiesList []android.SdkMemberProperties
+			for _, archInfo := range osInfo.archTypes {
+				archPropertiesList = append(archPropertiesList, archInfo.Properties)
+			}
+
+			extractCommonProperties(osInfo.Properties, archPropertiesList)
+
+			// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+			var multilib string
+			archVariantCount := len(osInfo.archTypes)
+			if archVariantCount == 2 {
+				multilib = "both"
+			} else if archVariantCount == 1 {
+				if strings.HasSuffix(osInfo.archTypes[0].archType.Name, "64") {
+					multilib = "64"
+				} else {
+					multilib = "32"
+				}
+			}
+
+			osInfo.commonArch = commonArch
+			osInfo.Properties.Base().Compile_multilib = multilib
+		}
+	}
+
+	// Extract properties which are common across all architectures and os types.
+	extractCommonProperties(commonProperties, osSpecificPropertiesList)
+
+	// Add the common properties to the module.
+	commonProperties.AddToPropertySet(sdkModuleContext, builder, bpModule)
+
+	// Create a target property set into which target specific properties can be
+	// added.
+	targetPropertySet := bpModule.AddPropertySet("target")
+
+	// Iterate over the os types in a fixed order.
+	for _, osType := range s.getPossibleOsTypes() {
+		osInfo := osTypeToInfo[osType]
+		if osInfo == nil {
+			continue
+		}
+
+		var osPropertySet android.BpPropertySet
+		var archOsPrefix string
+		if len(osTypeToInfo) == 1 {
+			// There is only one os type present in the variants sp don't bother
+			// with adding target specific properties.
+
+			// Create a structure that looks like:
+			// module_type {
+			//   name: "...",
+			//   ...
+			//   <common properties>
+			//   ...
+			//   <single os type specific properties>
+			//
+			//   arch: {
+			//     <arch specific sections>
+			//   }
+			//
+			osPropertySet = bpModule
+
+			// Arch specific properties need to be added to an arch specific section
+			// within arch.
+			archOsPrefix = ""
+		} else {
+			// Create a structure that looks like:
+			// module_type {
+			//   name: "...",
+			//   ...
+			//   <common properties>
+			//   ...
+			//   target: {
+			//     <arch independent os specific sections, e.g. android>
+			//     ...
+			//     <arch and os specific sections, e.g. android_x86>
+			//   }
+			//
+			osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
+
+			// Arch specific properties need to be added to an os and arch specific
+			// section prefixed with <os>_.
+			archOsPrefix = osType.Name + "_"
+		}
+
+		osInfo.Properties.AddToPropertySet(sdkModuleContext, builder, osPropertySet)
+		if !osInfo.commonArch {
+			// Either add the arch specific sections into the target or arch sections
+			// depending on whether they will also be os specific.
+			var archPropertySet android.BpPropertySet
+			if archOsPrefix == "" {
+				archPropertySet = osPropertySet.AddPropertySet("arch")
+			} else {
+				archPropertySet = targetPropertySet
+			}
+
+			// Add arch (and possibly os) specific sections for each set of
+			// arch (and possibly os) specific properties.
+			for _, av := range osInfo.archTypes {
+				archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + av.archType.Name)
+
+				av.Properties.AddToPropertySet(sdkModuleContext, builder, archTypePropertySet)
+			}
+		}
+	}
+
+	memberType.FinalizeModule(sdkModuleContext, builder, member, bpModule)
+}
+
+// Compute the list of possible os types that this sdk could support.
+func (s *sdk) getPossibleOsTypes() []android.OsType {
+	var osTypes []android.OsType
+	for _, osType := range android.OsTypeList {
+		if s.DeviceSupported() {
+			if osType.Class == android.Device && osType != android.Fuchsia {
+				osTypes = append(osTypes, osType)
+			}
+		}
+		if s.HostSupported() {
+			if osType.Class == android.Host || osType.Class == android.HostCross {
+				osTypes = append(osTypes, osType)
+			}
+		}
+	}
+	sort.SliceStable(osTypes, func(i, j int) bool { return osTypes[i].Name < osTypes[j].Name })
+	return osTypes
+}
+
+// Extract common properties from a slice of property structures of the same type.
+//
+// All the property structures must be of the same type.
+// commonProperties - must be a pointer to the structure into which common properties will be added.
+// inputPropertiesSlice - must be a slice of input properties structures.
+//
+// Iterates over each exported field (capitalized name) and checks to see whether they
+// have the same value (using DeepEquals) across all the input properties. If it does not then no
+// change is made. Otherwise, the common value is stored in the field in the commonProperties
+// and the field in each of the input properties structure is set to its default value.
+func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
+	commonPropertiesValue := reflect.ValueOf(commonProperties)
+	commonStructValue := commonPropertiesValue.Elem()
+	propertiesStructType := commonStructValue.Type()
+
+	// Create an empty structure from which default values for the field can be copied.
+	emptyStructValue := reflect.New(propertiesStructType).Elem()
+
+	for f := 0; f < propertiesStructType.NumField(); f++ {
+		// Check to see if all the structures have the same value for the field. The commonValue
+		// is nil on entry to the loop and if it is nil on exit then there is no common value,
+		// otherwise it points to the common value.
+		var commonValue *reflect.Value
+		sliceValue := reflect.ValueOf(inputPropertiesSlice)
+
+		field := propertiesStructType.Field(f)
+		if field.Name == "SdkMemberPropertiesBase" {
+			continue
+		}
+
+		for i := 0; i < sliceValue.Len(); i++ {
+			structValue := sliceValue.Index(i).Elem().Elem()
+			fieldValue := structValue.Field(f)
+			if !fieldValue.CanInterface() {
+				// The field is not exported so ignore it.
+				continue
+			}
+
+			if commonValue == nil {
+				// Use the first value as the commonProperties value.
+				commonValue = &fieldValue
+			} else {
+				// If the value does not match the current common value then there is
+				// no value in common so break out.
+				if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
+					commonValue = nil
+					break
+				}
+			}
+		}
+
+		// If the fields all have a common value then store it in the common struct field
+		// and set the input struct's field to the empty value.
+		if commonValue != nil {
+			emptyValue := emptyStructValue.Field(f)
+			commonStructValue.Field(f).Set(*commonValue)
+			for i := 0; i < sliceValue.Len(); i++ {
+				structValue := sliceValue.Index(i).Elem().Elem()
+				fieldValue := structValue.Field(f)
+				fieldValue.Set(emptyValue)
+			}
+		}
+	}
+}