Merge "Make source_stem required for Rust SourceProviders"
diff --git a/android/sdk.go b/android/sdk.go
index 28f5cd5..9ea7ff4 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -327,6 +327,12 @@
 	// SdkAware and be added with an SdkMemberTypeDependencyTag tag.
 	HasTransitiveSdkMembers() bool
 
+	// Return true if prebuilt host artifacts may be specific to the host OS. Only
+	// applicable to modules where HostSupported() is true. If this is true,
+	// snapshots will list each host OS variant explicitly and disable all other
+	// host OS'es.
+	IsHostOsDependent() bool
+
 	// Add dependencies from the SDK module to all the module variants the member
 	// type contributes to the SDK. `names` is the list of module names given in
 	// the member type property (as returned by SdkPropertyName()) in the SDK
@@ -389,6 +395,7 @@
 	PropertyName         string
 	SupportsSdk          bool
 	TransitiveSdkMembers bool
+	HostOsDependent      bool
 }
 
 func (b *SdkMemberTypeBase) SdkPropertyName() string {
@@ -403,6 +410,10 @@
 	return b.TransitiveSdkMembers
 }
 
+func (b *SdkMemberTypeBase) IsHostOsDependent() bool {
+	return b.HostOsDependent
+}
+
 // Encapsulates the information about registered SdkMemberTypes.
 type SdkMemberTypesRegistry struct {
 	// The list of types sorted by property name.
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 51d8b4e..337de55 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -29,7 +29,8 @@
 
 var ccBinarySdkMemberType = &binarySdkMemberType{
 	SdkMemberTypeBase: android.SdkMemberTypeBase{
-		PropertyName: "native_binaries",
+		PropertyName:    "native_binaries",
+		HostOsDependent: true,
 	},
 }
 
diff --git a/cc/library_headers.go b/cc/library_headers.go
index b7ab390..8b3dbeb 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -25,8 +25,9 @@
 
 var headersLibrarySdkMemberType = &librarySdkMemberType{
 	SdkMemberTypeBase: android.SdkMemberTypeBase{
-		PropertyName: "native_header_libs",
-		SupportsSdk:  true,
+		PropertyName:    "native_header_libs",
+		SupportsSdk:     true,
+		HostOsDependent: true,
 	},
 	prebuiltModuleType: "cc_prebuilt_library_headers",
 	noOutputFiles:      true,
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 4b9eb30..cff00b6 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -27,8 +27,9 @@
 
 var sharedLibrarySdkMemberType = &librarySdkMemberType{
 	SdkMemberTypeBase: android.SdkMemberTypeBase{
-		PropertyName: "native_shared_libs",
-		SupportsSdk:  true,
+		PropertyName:    "native_shared_libs",
+		SupportsSdk:     true,
+		HostOsDependent: true,
 	},
 	prebuiltModuleType: "cc_prebuilt_library_shared",
 	linkTypes:          []string{"shared"},
@@ -36,8 +37,9 @@
 
 var staticLibrarySdkMemberType = &librarySdkMemberType{
 	SdkMemberTypeBase: android.SdkMemberTypeBase{
-		PropertyName: "native_static_libs",
-		SupportsSdk:  true,
+		PropertyName:    "native_static_libs",
+		SupportsSdk:     true,
+		HostOsDependent: true,
 	},
 	prebuiltModuleType: "cc_prebuilt_library_static",
 	linkTypes:          []string{"static"},
@@ -45,8 +47,9 @@
 
 var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
 	SdkMemberTypeBase: android.SdkMemberTypeBase{
-		PropertyName: "native_libs",
-		SupportsSdk:  true,
+		PropertyName:    "native_libs",
+		SupportsSdk:     true,
+		HostOsDependent: true,
 	},
 	prebuiltModuleType: "cc_prebuilt_library",
 	linkTypes:          []string{"static", "shared"},
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 0af2258..6df940c 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -484,18 +484,22 @@
 
 var (
 	// Modules under following directories are ignored. They are OEM's and vendor's
-	// proprietary modules(device/, vendor/, and hardware/).
+	// proprietary modules(device/, kernel/, vendor/, and hardware/).
 	// TODO(b/65377115): Clean up these with more maintainable way
 	vendorProprietaryDirs = []string{
 		"device",
+		"kernel",
 		"vendor",
 		"hardware",
 	}
 
 	// Modules under following directories are included as they are in AOSP,
-	// although hardware/ is normally for vendor's own.
+	// although hardware/ and kernel/ are normally for vendor's own.
 	// TODO(b/65377115): Clean up these with more maintainable way
 	aospDirsUnderProprietary = []string{
+		"kernel/configs",
+		"kernel/prebuilts",
+		"kernel/tests",
 		"hardware/interfaces",
 		"hardware/libhardware",
 		"hardware/libhardware_legacy",
diff --git a/java/androidmk.go b/java/androidmk.go
index 081fcb2..650d126 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -127,8 +127,8 @@
 						entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
 					}
 
-					if library.proguardDictionary != nil {
-						entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.proguardDictionary)
+					if library.dexer.proguardDictionary.Valid() {
+						entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary.Path())
 					}
 					entries.SetString("LOCAL_MODULE_STEM", library.Stem())
 
@@ -332,8 +332,8 @@
 				if app.jacocoReportClassesFile != nil {
 					entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile)
 				}
-				if app.proguardDictionary != nil {
-					entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.proguardDictionary)
+				if app.dexer.proguardDictionary.Valid() {
+					entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary.Path())
 				}
 
 				if app.Name() == "framework-res" {
diff --git a/java/app.go b/java/app.go
index 1ede34e..fcb2e99 100755
--- a/java/app.go
+++ b/java/app.go
@@ -588,11 +588,11 @@
 
 func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
 	a.dexpreopter.installPath = a.installPath(ctx)
-	if a.deviceProperties.Uncompress_dex == nil {
+	if a.dexProperties.Uncompress_dex == nil {
 		// If the value was not force-set by the user, use reasonable default based on the module.
-		a.deviceProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
+		a.dexProperties.Uncompress_dex = proptools.BoolPtr(a.shouldUncompressDex(ctx))
 	}
-	a.dexpreopter.uncompressedDex = *a.deviceProperties.Uncompress_dex
+	a.dexpreopter.uncompressedDex = *a.dexProperties.Uncompress_dex
 	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
 	a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
 	a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
@@ -995,8 +995,8 @@
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
-	module.Module.deviceProperties.Optimize.EnabledByDefault = true
-	module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true)
+	module.Module.dexProperties.Optimize.EnabledByDefault = true
+	module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true)
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -1110,7 +1110,7 @@
 func AndroidTestFactory() android.Module {
 	module := &AndroidTest{}
 
-	module.Module.deviceProperties.Optimize.EnabledByDefault = true
+	module.Module.dexProperties.Optimize.EnabledByDefault = true
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
@@ -1161,7 +1161,7 @@
 func AndroidTestHelperAppFactory() android.Module {
 	module := &AndroidTestHelperApp{}
 
-	module.Module.deviceProperties.Optimize.EnabledByDefault = true
+	module.Module.dexProperties.Optimize.EnabledByDefault = true
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
diff --git a/java/dex.go b/java/dex.go
index 9e61e95..cd45a93 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -24,6 +24,60 @@
 	"android/soong/remoteexec"
 )
 
+type DexProperties struct {
+	// If set to true, compile dex regardless of installable.  Defaults to false.
+	Compile_dex *bool
+
+	// list of module-specific flags that will be used for dex compiles
+	Dxflags []string `android:"arch_variant"`
+
+	Optimize struct {
+		// If false, disable all optimization.  Defaults to true for android_app and android_test
+		// modules, false for java_library and java_test modules.
+		Enabled *bool
+		// True if the module containing this has it set by default.
+		EnabledByDefault bool `blueprint:"mutated"`
+
+		// If true, optimize for size by removing unused code.  Defaults to true for apps,
+		// false for libraries and tests.
+		Shrink *bool
+
+		// If true, optimize bytecode.  Defaults to false.
+		Optimize *bool
+
+		// If true, obfuscate bytecode.  Defaults to false.
+		Obfuscate *bool
+
+		// If true, do not use the flag files generated by aapt that automatically keep
+		// classes referenced by the app manifest.  Defaults to false.
+		No_aapt_flags *bool
+
+		// Flags to pass to proguard.
+		Proguard_flags []string
+
+		// Specifies the locations of files containing proguard flags.
+		Proguard_flags_files []string `android:"path"`
+	}
+
+	// Keep the data uncompressed. We always need uncompressed dex for execution,
+	// so this might actually save space by avoiding storing the same data twice.
+	// This defaults to reasonable value based on module and should not be set.
+	// It exists only to support ART tests.
+	Uncompress_dex *bool
+}
+
+type dexer struct {
+	dexProperties DexProperties
+
+	// list of extra proguard flag files
+	extraProguardFlagFiles android.Paths
+	proguardDictionary     android.OptionalPath
+}
+
+func (d *dexer) effectiveOptimizeEnabled() bool {
+	return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
+}
+
 var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
@@ -86,8 +140,8 @@
 		},
 	}, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"})
 
-func (j *Module) dexCommonFlags(ctx android.ModuleContext) []string {
-	flags := j.deviceProperties.Dxflags
+func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string {
+	flags := d.dexProperties.Dxflags
 	// Translate all the DX flags to D8 ones until all the build files have been migrated
 	// to D8 flags. See: b/69377755
 	flags = android.RemoveListFromList(flags,
@@ -103,30 +157,27 @@
 			"--verbose")
 	}
 
-	minSdkVersion, err := j.minSdkVersion().effectiveVersion(ctx)
+	effectiveVersion, err := minSdkVersion.effectiveVersion(ctx)
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
 	}
 
-	flags = append(flags, "--min-api "+minSdkVersion.asNumberString())
+	flags = append(flags, "--min-api "+effectiveVersion.asNumberString())
 	return flags
 }
 
-func (j *Module) d8Flags(ctx android.ModuleContext, flags javaBuilderFlags) ([]string, android.Paths) {
-	d8Flags := j.dexCommonFlags(ctx)
-
+func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) {
 	d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...)
 	d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...)
 
-	var d8Deps android.Paths
 	d8Deps = append(d8Deps, flags.bootClasspath...)
 	d8Deps = append(d8Deps, flags.classpath...)
 
 	return d8Flags, d8Deps
 }
 
-func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) {
-	opt := j.deviceProperties.Optimize
+func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) {
+	opt := d.dexProperties.Optimize
 
 	// When an app contains references to APIs that are not in the SDK specified by
 	// its LOCAL_SDK_VERSION for example added by support library or by runtime
@@ -140,8 +191,6 @@
 		proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...)
 	})
 
-	r8Flags = append(r8Flags, j.dexCommonFlags(ctx)...)
-
 	r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
 	r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars"))
 	r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars"))
@@ -154,15 +203,10 @@
 		android.PathForSource(ctx, "build/make/core/proguard.flags"),
 	}
 
-	if j.shouldInstrumentStatic(ctx) {
-		flagFiles = append(flagFiles,
-			android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags"))
-	}
-
-	flagFiles = append(flagFiles, j.extraProguardFlagFiles...)
+	flagFiles = append(flagFiles, d.extraProguardFlagFiles...)
 	// TODO(ccross): static android library proguard files
 
-	flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, j.deviceProperties.Optimize.Proguard_flags_files)...)
+	flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...)
 
 	r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include "))
 	r8Deps = append(r8Deps, flagFiles...)
@@ -171,7 +215,7 @@
 	r8Deps = append(r8Deps, android.PathForSource(ctx,
 		"build/make/core/proguard_basic_keeps.flags"))
 
-	r8Flags = append(r8Flags, j.deviceProperties.Optimize.Proguard_flags...)
+	r8Flags = append(r8Flags, opt.Proguard_flags...)
 
 	// TODO(ccross): Don't shrink app instrumentation tests by default.
 	if !Bool(opt.Shrink) {
@@ -197,29 +241,30 @@
 	return r8Flags, r8Deps
 }
 
-func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
+func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion sdkSpec,
 	classesJar android.Path, jarName string) android.ModuleOutPath {
 
-	useR8 := j.deviceProperties.EffectiveOptimizeEnabled()
-
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
 	outDir := android.PathForModuleOut(ctx, "dex")
 
 	zipFlags := "--ignore_missing_files"
-	if proptools.Bool(j.deviceProperties.Uncompress_dex) {
+	if proptools.Bool(d.dexProperties.Uncompress_dex) {
 		zipFlags += " -L 0"
 	}
 
+	commonFlags := d.dexCommonFlags(ctx, minSdkVersion)
+
+	useR8 := d.effectiveOptimizeEnabled()
 	if useR8 {
 		proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary")
-		j.proguardDictionary = proguardDictionary
-		r8Flags, r8Deps := j.r8Flags(ctx, flags)
+		d.proguardDictionary = android.OptionalPathForPath(proguardDictionary)
+		r8Flags, r8Deps := d.r8Flags(ctx, flags)
 		rule := r8
 		args := map[string]string{
-			"r8Flags":  strings.Join(r8Flags, " "),
+			"r8Flags":  strings.Join(append(commonFlags, r8Flags...), " "),
 			"zipFlags": zipFlags,
-			"outDict":  j.proguardDictionary.String(),
+			"outDict":  proguardDictionary.String(),
 			"outDir":   outDir.String(),
 		}
 		if ctx.Config().IsEnvTrue("RBE_R8") {
@@ -236,7 +281,7 @@
 			Args:           args,
 		})
 	} else {
-		d8Flags, d8Deps := j.d8Flags(ctx, flags)
+		d8Flags, d8Deps := d8Flags(flags)
 		rule := d8
 		if ctx.Config().IsEnvTrue("RBE_D8") {
 			rule = d8RE
@@ -248,13 +293,13 @@
 			Input:       classesJar,
 			Implicits:   d8Deps,
 			Args: map[string]string{
-				"d8Flags":  strings.Join(d8Flags, " "),
+				"d8Flags":  strings.Join(append(commonFlags, d8Flags...), " "),
 				"zipFlags": zipFlags,
 				"outDir":   outDir.String(),
 			},
 		})
 	}
-	if proptools.Bool(j.deviceProperties.Uncompress_dex) {
+	if proptools.Bool(d.dexProperties.Uncompress_dex) {
 		alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", jarName)
 		TransformZipAlign(ctx, alignedJavalibJar, javalibJar)
 		javalibJar = alignedJavalibJar
diff --git a/java/droiddoc.go b/java/droiddoc.go
index d2f8d83..0840d50 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -294,6 +294,9 @@
 	// the dirs which Metalava extracts API levels annotations from.
 	Api_levels_annotations_dirs []string
 
+	// the filename which Metalava extracts API levels annotations from. Defaults to android.jar.
+	Api_levels_jar_filename *string
+
 	// if set to true, collect the values used by the Dev tools and
 	// write them in files packaged with the SDK. Defaults to false.
 	Write_sdk_values *bool
@@ -1407,34 +1410,37 @@
 }
 
 func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
-	if Bool(d.properties.Api_levels_annotations_enabled) {
-		d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml")
-
-		if len(d.properties.Api_levels_annotations_dirs) == 0 {
-			ctx.PropertyErrorf("api_levels_annotations_dirs",
-				"has to be non-empty if api levels annotations was enabled!")
-		}
-
-		cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
-		cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml)
-		cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion())
-		cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
-
-		ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
-			if t, ok := m.(*ExportedDroiddocDir); ok {
-				for _, dep := range t.deps {
-					if strings.HasSuffix(dep.String(), "android.jar") {
-						cmd.Implicit(dep)
-					}
-				}
-				cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/android.jar")
-			} else {
-				ctx.PropertyErrorf("api_levels_annotations_dirs",
-					"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
-			}
-		})
-
+	if !Bool(d.properties.Api_levels_annotations_enabled) {
+		return
 	}
+
+	d.apiVersionsXml = android.PathForModuleOut(ctx, "api-versions.xml")
+
+	if len(d.properties.Api_levels_annotations_dirs) == 0 {
+		ctx.PropertyErrorf("api_levels_annotations_dirs",
+			"has to be non-empty if api levels annotations was enabled!")
+	}
+
+	cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
+	cmd.FlagWithInput("--apply-api-levels ", d.apiVersionsXml)
+	cmd.FlagWithArg("--current-version ", ctx.Config().PlatformSdkVersion())
+	cmd.FlagWithArg("--current-codename ", ctx.Config().PlatformSdkCodename())
+
+	filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
+
+	ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
+		if t, ok := m.(*ExportedDroiddocDir); ok {
+			for _, dep := range t.deps {
+				if strings.HasSuffix(dep.String(), filename) {
+					cmd.Implicit(dep)
+				}
+			}
+			cmd.FlagWithArg("--android-jar-pattern ", t.dir.String()+"/%/public/"+filename)
+		} else {
+			ctx.PropertyErrorf("api_levels_annotations_dirs",
+				"module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m))
+		}
+	})
 }
 
 func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
diff --git a/java/java.go b/java/java.go
index bd476bc..d5375a5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -264,9 +264,6 @@
 }
 
 type CompilerDeviceProperties struct {
-	// list of module-specific flags that will be used for dex compiles
-	Dxflags []string `android:"arch_variant"`
-
 	// if not blank, set to the version of the sdk to compile against.
 	// Defaults to compiling against the current platform.
 	Sdk_version *string
@@ -312,37 +309,6 @@
 		}
 	}
 
-	// If set to true, compile dex regardless of installable.  Defaults to false.
-	Compile_dex *bool
-
-	Optimize struct {
-		// If false, disable all optimization.  Defaults to true for android_app and android_test
-		// modules, false for java_library and java_test modules.
-		Enabled *bool
-		// True if the module containing this has it set by default.
-		EnabledByDefault bool `blueprint:"mutated"`
-
-		// If true, optimize for size by removing unused code.  Defaults to true for apps,
-		// false for libraries and tests.
-		Shrink *bool
-
-		// If true, optimize bytecode.  Defaults to false.
-		Optimize *bool
-
-		// If true, obfuscate bytecode.  Defaults to false.
-		Obfuscate *bool
-
-		// If true, do not use the flag files generated by aapt that automatically keep
-		// classes referenced by the app manifest.  Defaults to false.
-		No_aapt_flags *bool
-
-		// Flags to pass to proguard.
-		Proguard_flags []string
-
-		// Specifies the locations of files containing proguard flags.
-		Proguard_flags_files []string `android:"path"`
-	}
-
 	// When targeting 1.9 and above, override the modules to use with --system,
 	// otherwise provides defaults libraries to add to the bootclasspath.
 	System_modules *string
@@ -356,19 +322,9 @@
 	// set the name of the output
 	Stem *string
 
-	// Keep the data uncompressed. We always need uncompressed dex for execution,
-	// so this might actually save space by avoiding storing the same data twice.
-	// This defaults to reasonable value based on module and should not be set.
-	// It exists only to support ART tests.
-	Uncompress_dex *bool
-
 	IsSDKLibrary bool `blueprint:"mutated"`
 }
 
-func (me *CompilerDeviceProperties) EffectiveOptimizeEnabled() bool {
-	return BoolDefault(me.Optimize.Enabled, me.Optimize.EnabledByDefault)
-}
-
 // Functionality common to Module and Import
 //
 // It is embedded in Module so its functionality can be used by methods in Module
@@ -437,9 +393,6 @@
 	// output file containing uninstrumented classes that will be instrumented by jacoco
 	jacocoReportClassesFile android.Path
 
-	// output file containing mapping of obfuscated names
-	proguardDictionary android.Path
-
 	// output file of the module, which may be a classes jar or a dex jar
 	outputFile       android.Path
 	extraOutputFiles android.Paths
@@ -455,9 +408,6 @@
 	compiledJavaSrcs android.Paths
 	compiledSrcJars  android.Paths
 
-	// list of extra progurad flag files
-	extraProguardFlagFiles android.Paths
-
 	// manifest file to use instead of properties.Manifest
 	overrideManifest android.OptionalPath
 
@@ -484,6 +434,7 @@
 	extraResources android.Paths
 
 	hiddenAPI
+	dexer
 	dexpreopter
 	linter
 
@@ -507,6 +458,7 @@
 	j.addHostProperties()
 	j.AddProperties(
 		&j.deviceProperties,
+		&j.dexer.dexProperties,
 		&j.dexpreoptProperties,
 		&j.linter.properties,
 	)
@@ -519,7 +471,10 @@
 	case ".jar":
 		return android.Paths{j.implementationAndResourcesJar}, nil
 	case ".proguard_map":
-		return android.Paths{j.proguardDictionary}, nil
+		if j.dexer.proguardDictionary.Valid() {
+			return android.Paths{j.dexer.proguardDictionary.Path()}, nil
+		}
+		return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -728,10 +683,10 @@
 			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
 			ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
-			if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
+			if j.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
 				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
 			}
-			if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
+			if j.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
 				ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
 			}
 		}
@@ -1647,8 +1602,8 @@
 
 	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
 	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !j.IsForPlatform() {
-		if j.deviceProperties.Compile_dex == nil {
-			j.deviceProperties.Compile_dex = proptools.BoolPtr(true)
+		if j.dexProperties.Compile_dex == nil {
+			j.dexProperties.Compile_dex = proptools.BoolPtr(true)
 		}
 		if j.deviceProperties.Hostdex == nil {
 			j.deviceProperties.Hostdex = proptools.BoolPtr(true)
@@ -1656,10 +1611,14 @@
 	}
 
 	if ctx.Device() && j.hasCode(ctx) &&
-		(Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
+		(Bool(j.properties.Installable) || Bool(j.dexProperties.Compile_dex)) {
+		if j.shouldInstrumentStatic(ctx) {
+			j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles,
+				android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags"))
+		}
 		// Dex compilation
 		var dexOutputFile android.ModuleOutPath
-		dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName)
+		dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName)
 		if ctx.Failed() {
 			return
 		}
@@ -1669,7 +1628,7 @@
 
 		// Hidden API CSV generation and dex encoding
 		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
-			proptools.Bool(j.deviceProperties.Uncompress_dex))
+			proptools.Bool(j.dexProperties.Uncompress_dex))
 
 		// merge dex jar with resources if necessary
 		if j.resourceJar != nil {
@@ -1677,7 +1636,7 @@
 			combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName)
 			TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
 				false, nil, nil)
-			if *j.deviceProperties.Uncompress_dex {
+			if *j.dexProperties.Uncompress_dex {
 				combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName)
 				TransformZipAlign(ctx, combinedAlignedJar, combinedJar)
 				dexOutputFile = combinedAlignedJar
@@ -2008,11 +1967,11 @@
 	j.checkSdkVersions(ctx)
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
-	if j.deviceProperties.Uncompress_dex == nil {
+	if j.dexProperties.Uncompress_dex == nil {
 		// If the value was not force-set by the user, use reasonable default based on the module.
-		j.deviceProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
+		j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
 	}
-	j.dexpreopter.uncompressedDex = *j.deviceProperties.Uncompress_dex
+	j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
 	j.compile(ctx, nil)
 
 	// Collect the module directory for IDE info in java/jdeps.go.
@@ -2970,6 +2929,7 @@
 	module.AddProperties(
 		&CompilerProperties{},
 		&CompilerDeviceProperties{},
+		&DexProperties{},
 		&DexpreoptProperties{},
 		&android.ProtoProperties{},
 		&aaptProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index a3c7854..50c40c3 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1170,6 +1170,62 @@
 		`)
 }
 
+func TestDroidstubs(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		droiddoc_exported_dir {
+		    name: "droiddoc-templates-sdk",
+		    path: ".",
+		}
+
+		droidstubs {
+		    name: "bar-stubs",
+		    srcs: [
+		        "bar-doc/a.java",
+				],
+				api_levels_annotations_dirs: [
+					"droiddoc-templates-sdk",
+				],
+				api_levels_annotations_enabled: true,
+		}
+
+		droidstubs {
+		    name: "bar-stubs-other",
+		    srcs: [
+		        "bar-doc/a.java",
+				],
+				api_levels_annotations_dirs: [
+					"droiddoc-templates-sdk",
+				],
+				api_levels_annotations_enabled: true,
+				api_levels_jar_filename: "android.other.jar",
+		}
+		`,
+		map[string][]byte{
+			"bar-doc/a.java": nil,
+		})
+	testcases := []struct {
+		moduleName          string
+		expectedJarFilename string
+	}{
+		{
+			moduleName:          "bar-stubs",
+			expectedJarFilename: "android.jar",
+		},
+		{
+			moduleName:          "bar-stubs-other",
+			expectedJarFilename: "android.other.jar",
+		},
+	}
+	for _, c := range testcases {
+		m := ctx.ModuleForTests(c.moduleName, "android_common")
+		metalava := m.Rule("metalava")
+		expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename
+		if actual := metalava.RuleParams.Command; !strings.Contains(actual, expected) {
+			t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, actual)
+		}
+	}
+}
+
 func TestDroidstubsWithSystemModules(t *testing.T) {
 	ctx, _ := testJava(t, `
 		droidstubs {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 8a8d0c9..0379a31 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1112,6 +1112,7 @@
 		&module.properties,
 		&module.protoProperties,
 		&module.deviceProperties,
+		&module.dexProperties,
 		&module.dexpreoptProperties,
 		&module.linter.properties,
 		&props,
@@ -1171,8 +1172,8 @@
 	// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
 	// interop with older developer tools that don't support 1.9.
 	props.Java_version = proptools.StringPtr("1.8")
-	if module.deviceProperties.Compile_dex != nil {
-		props.Compile_dex = module.deviceProperties.Compile_dex
+	if module.dexProperties.Compile_dex != nil {
+		props.Compile_dex = module.dexProperties.Compile_dex
 	}
 
 	// Dist the class jar artifact for sdk builds.
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 403f466..2224a9c 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -41,12 +41,12 @@
 	bindgen = pctx.AndroidStaticRule("bindgen",
 		blueprint.RuleParams{
 			Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
-				"$bindgenCmd $flags $in -o $out -- -MD -MF $out.d $cflags",
-			CommandDeps: []string{"$bindgenCmd"},
+				"$cmd $flags $in -o $out -- -MD -MF $out.d $cflags",
+			CommandDeps: []string{"$cmd"},
 			Deps:        blueprint.DepsGCC,
 			Depfile:     "$out.d",
 		},
-		"flags", "cflags")
+		"cmd", "flags", "cflags")
 )
 
 func init() {
@@ -76,6 +76,12 @@
 	// list of shared libraries that provide headers for this binding.
 	Shared_libs []string `android:"arch_variant"`
 
+	// module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
+	// binary must expect arguments in a similar fashion to bindgen, e.g.
+	//
+	// "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]"
+	Custom_bindgen string `android:"path"`
+
 	//TODO(b/161141999) Add support for headers from cc_library_header modules.
 }
 
@@ -130,17 +136,28 @@
 
 	outputFile := android.PathForModuleOut(ctx, b.baseSourceProvider.getStem(ctx)+".rs")
 
+	var cmd, cmdDesc string
+	if b.Properties.Custom_bindgen != "" {
+		cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(*Module).HostToolPath().String()
+		cmdDesc = b.Properties.Custom_bindgen
+	} else {
+		cmd = "$bindgenCmd"
+		cmdDesc = "bindgen"
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        bindgen,
-		Description: "bindgen " + wrapperFile.Path().Rel(),
+		Description: strings.Join([]string{cmdDesc, wrapperFile.Path().Rel()}, " "),
 		Output:      outputFile,
 		Input:       wrapperFile.Path(),
 		Implicits:   implicits,
 		Args: map[string]string{
+			"cmd":    cmd,
 			"flags":  strings.Join(bindgenFlags, " "),
 			"cflags": strings.Join(cflags, " "),
 		},
 	})
+
 	b.baseSourceProvider.outputFile = outputFile
 	return outputFile
 }
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index c428348..0b529ca 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -55,3 +55,29 @@
 		t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
 	}
 }
+
+func TestRustBindgenCustomBindgen(t *testing.T) {
+	ctx := testRust(t, `
+		rust_bindgen {
+			name: "libbindgen",
+			wrapper_src: "src/any.h",
+			crate_name: "bindgen",
+			stem: "libbindgen",
+			source_stem: "bindings",
+			custom_bindgen: "my_bindgen"
+		}
+		rust_binary_host {
+			name: "my_bindgen",
+			srcs: ["foo.rs"],
+		}
+	`)
+
+	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs")
+
+	// The rule description should contain the custom binary name rather than bindgen, so checking the description
+	// should be sufficient.
+	if !strings.Contains(libbindgen.Description, "my_bindgen") {
+		t.Errorf("Custom bindgen binary %s not used for libbindgen: rule description %#v", "my_bindgen",
+			libbindgen.Description)
+	}
+}
diff --git a/rust/project_json.go b/rust/project_json.go
index 41dd194..8310479 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -75,17 +75,16 @@
 	knownCrates map[string]crateInfo, module android.Module,
 	crate *rustProjectCrate, deps map[string]int) {
 
-	//TODO(tweek): The stdlib dependencies do not appear here. We need to manually add them.
 	ctx.VisitDirectDeps(module, func(child android.Module) {
-		childId, childName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child)
+		childId, childCrateName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child)
 		if !ok {
 			return
 		}
-		if _, ok = deps[childName]; ok {
+		if _, ok = deps[ctx.ModuleName(child)]; ok {
 			return
 		}
-		crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childName})
-		deps[childName] = childId
+		crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childCrateName})
+		deps[ctx.ModuleName(child)] = childId
 	})
 }
 
@@ -106,8 +105,9 @@
 	if !ok {
 		return 0, "", false
 	}
+	moduleName := ctx.ModuleName(module)
 	crateName := rModule.CrateName()
-	if cInfo, ok := knownCrates[crateName]; ok {
+	if cInfo, ok := knownCrates[moduleName]; ok {
 		// We have seen this crate already; merge any new dependencies.
 		crate := project.Crates[cInfo.ID]
 		mergeDependencies(ctx, project, knownCrates, module, &crate, cInfo.Deps)
@@ -115,15 +115,18 @@
 		return cInfo.ID, crateName, true
 	}
 	crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)}
-	src := rustLib.baseCompiler.Properties.Srcs[0]
-	crate.RootModule = path.Join(ctx.ModuleDir(rModule), src)
+	srcs := rustLib.baseCompiler.Properties.Srcs
+	if len(srcs) == 0 {
+		return 0, "", false
+	}
+	crate.RootModule = path.Join(ctx.ModuleDir(rModule), srcs[0])
 	crate.Edition = rustLib.baseCompiler.edition()
 
 	deps := make(map[string]int)
 	mergeDependencies(ctx, project, knownCrates, module, &crate, deps)
 
 	id := len(project.Crates)
-	knownCrates[crateName] = crateInfo{ID: id, Deps: deps}
+	knownCrates[moduleName] = crateInfo{ID: id, Deps: deps}
 	project.Crates = append(project.Crates, crate)
 	// rust-analyzer requires that all crates belong to at least one root:
 	// https://github.com/rust-analyzer/rust-analyzer/issues/4735.
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index 6786e72..8521940 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -15,6 +15,7 @@
 package rust
 
 import (
+	"encoding/json"
 	"io/ioutil"
 	"path/filepath"
 	"testing"
@@ -23,20 +24,12 @@
 	"android/soong/cc"
 )
 
-func TestProjectJson(t *testing.T) {
-	bp := `rust_library {
-		  name: "liba",
-		  srcs: ["src/lib.rs"],
-		  crate_name: "a"
-		}` + GatherRequiredDepsForTest()
-	env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
-	fs := map[string][]byte{
-		"foo.rs":     nil,
-		"src/lib.rs": nil,
-	}
-
+// testProjectJson run the generation of rust-project.json. It returns the raw
+// content of the generated file.
+func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte {
 	cc.GatherRequiredFilesForTest(fs)
 
+	env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
 	config := android.TestArchConfig(buildDir, env, bp, fs)
 	ctx := CreateTestContext()
 	ctx.Register(config)
@@ -48,8 +41,131 @@
 	// The JSON file is generated via WriteFileToOutputDir. Therefore, it
 	// won't appear in the Output of the TestingSingleton. Manually verify
 	// it exists.
-	_, err := ioutil.ReadFile(filepath.Join(buildDir, "rust-project.json"))
+	content, err := ioutil.ReadFile(filepath.Join(buildDir, rustProjectJsonFileName))
 	if err != nil {
 		t.Errorf("rust-project.json has not been generated")
 	}
+	return content
+}
+
+// validateJsonCrates validates that content follows the basic structure of
+// rust-project.json. It returns the crates attribute if the validation
+// succeeded.
+// It uses an empty interface instead of relying on a defined structure to
+// avoid a strong dependency on our implementation.
+func validateJsonCrates(t *testing.T, rawContent []byte) []interface{} {
+	var content interface{}
+	err := json.Unmarshal(rawContent, &content)
+	if err != nil {
+		t.Errorf("Unable to parse the rust-project.json as JSON: %v", err)
+	}
+	root, ok := content.(map[string]interface{})
+	if !ok {
+		t.Errorf("Unexpected JSON format: %v", content)
+	}
+	if _, ok = root["crates"]; !ok {
+		t.Errorf("No crates attribute in rust-project.json: %v", root)
+	}
+	crates, ok := root["crates"].([]interface{})
+	if !ok {
+		t.Errorf("Unexpected crates format: %v", root["crates"])
+	}
+	return crates
+}
+
+func TestProjectJsonDep(t *testing.T) {
+	bp := `
+	rust_library {
+		name: "liba",
+		srcs: ["a/src/lib.rs"],
+		crate_name: "a"
+	}
+	rust_library {
+		name: "libb",
+		srcs: ["b/src/lib.rs"],
+		crate_name: "b",
+		rlibs: ["liba"],
+	}
+	` + GatherRequiredDepsForTest()
+	fs := map[string][]byte{
+		"a/src/lib.rs": nil,
+		"b/src/lib.rs": nil,
+	}
+	jsonContent := testProjectJson(t, bp, fs)
+	validateJsonCrates(t, jsonContent)
+}
+
+func TestProjectJsonBindGen(t *testing.T) {
+	bp := `
+	rust_library {
+		name: "liba",
+		srcs: ["src/lib.rs"],
+		rlibs: ["libbindings"],
+		crate_name: "a"
+	}
+	rust_bindgen {
+		name: "libbindings",
+		crate_name: "bindings",
+		source_stem: "bindings",
+		host_supported: true,
+		wrapper_src: "src/any.h",
+	}
+	` + GatherRequiredDepsForTest()
+	fs := map[string][]byte{
+		"src/lib.rs": nil,
+	}
+	jsonContent := testProjectJson(t, bp, fs)
+	validateJsonCrates(t, jsonContent)
+}
+
+func TestProjectJsonMultiVersion(t *testing.T) {
+	bp := `
+	rust_library {
+		name: "liba1",
+		srcs: ["a1/src/lib.rs"],
+		crate_name: "a"
+	}
+	rust_library {
+		name: "liba2",
+		srcs: ["a2/src/lib.rs"],
+		crate_name: "a",
+	}
+	rust_library {
+		name: "libb",
+		srcs: ["b/src/lib.rs"],
+		crate_name: "b",
+		rustlibs: ["liba1", "liba2"],
+	}
+	` + GatherRequiredDepsForTest()
+	fs := map[string][]byte{
+		"a1/src/lib.rs": nil,
+		"a2/src/lib.rs": nil,
+		"b/src/lib.rs":  nil,
+	}
+	jsonContent := testProjectJson(t, bp, fs)
+	crates := validateJsonCrates(t, jsonContent)
+	for _, crate := range crates {
+		c := crate.(map[string]interface{})
+		if c["root_module"] == "b/src/lib.rs" {
+			deps, ok := c["deps"].([]interface{})
+			if !ok {
+				t.Errorf("Unexpected format for deps: %v", c["deps"])
+			}
+			aCount := 0
+			for _, dep := range deps {
+				d, ok := dep.(map[string]interface{})
+				if !ok {
+					t.Errorf("Unexpected format for dep: %v", dep)
+				}
+				if d["name"] == "a" {
+					aCount++
+				}
+			}
+			if aCount != 2 {
+				t.Errorf("Unexpected number of liba dependencies want %v, got %v: %v", 2, aCount, deps)
+			}
+			return
+		}
+	}
+	t.Errorf("libb crate has not been found: %v", crates)
 }
diff --git a/rust/rust.go b/rust/rust.go
index 0195247..7ec2d73 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -722,10 +722,11 @@
 }
 
 var (
-	rlibDepTag       = dependencyTag{name: "rlibTag", library: true}
-	dylibDepTag      = dependencyTag{name: "dylib", library: true}
-	procMacroDepTag  = dependencyTag{name: "procMacro", proc_macro: true}
-	testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
+	customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
+	rlibDepTag          = dependencyTag{name: "rlibTag", library: true}
+	dylibDepTag         = dependencyTag{name: "dylib", library: true}
+	procMacroDepTag     = dependencyTag{name: "procMacro", proc_macro: true}
+	testPerSrcDepTag    = dependencyTag{name: "rust_unit_tests"}
 )
 
 type autoDep struct {
@@ -1009,6 +1010,13 @@
 		actx.AddVariationDependencies(commonDepVariations, cc.CrtEndDepTag, deps.CrtEnd)
 	}
 
+	if mod.sourceProvider != nil {
+		if bindgen, ok := mod.sourceProvider.(*bindgenDecorator); ok &&
+			bindgen.Properties.Custom_bindgen != "" {
+			actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), customBindgenDepTag,
+				bindgen.Properties.Custom_bindgen)
+		}
+	}
 	// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
 	actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
 }
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 17afdb8..9501d88 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -39,6 +39,20 @@
 
 // Contains tests for SDK members provided by the cc package.
 
+func TestSingleDeviceOsAssumption(t *testing.T) {
+	// Mock a module with DeviceSupported() == true.
+	s := &sdk{}
+	android.InitAndroidArchModule(s, android.DeviceSupported, android.MultilibCommon)
+
+	osTypes := s.getPossibleOsTypes()
+	if len(osTypes) != 1 {
+		// The snapshot generation assumes there is a single device OS. If more are
+		// added it might need to disable them by default, like it does for host
+		// OS'es.
+		t.Errorf("expected a single device OS, got %v", osTypes)
+	}
+}
+
 func TestSdkIsCompileMultilibBoth(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
@@ -99,9 +113,15 @@
     stl: "none",
     compile_multilib: "64",
     target: {
+        host: {
+            enabled: false,
+        },
         android_arm64: {
             srcs: ["android/arm64/lib/sdkmember.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/sdkmember.so"],
         },
@@ -115,9 +135,15 @@
     stl: "none",
     compile_multilib: "64",
     target: {
+        host: {
+            enabled: false,
+        },
         android_arm64: {
             srcs: ["android/arm64/lib/sdkmember.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/sdkmember.so"],
         },
@@ -129,6 +155,14 @@
     host_supported: true,
     native_shared_libs: ["mysdk_sdkmember@current"],
     compile_multilib: "64",
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -573,7 +607,11 @@
     installable: false,
     stl: "none",
     target: {
+        host: {
+            enabled: false,
+        },
         linux_glibc: {
+            enabled: true,
             compile_multilib: "both",
         },
         linux_glibc_x86_64: {
@@ -583,6 +621,7 @@
             srcs: ["linux_glibc/x86/bin/mynativebinary"],
         },
         windows: {
+            enabled: true,
             compile_multilib: "64",
         },
         windows_x86_64: {
@@ -598,7 +637,11 @@
     host_supported: true,
     stl: "none",
     target: {
+        host: {
+            enabled: false,
+        },
         linux_glibc: {
+            enabled: true,
             compile_multilib: "both",
         },
         linux_glibc_x86_64: {
@@ -608,6 +651,7 @@
             srcs: ["linux_glibc/x86/bin/mynativebinary"],
         },
         windows: {
+            enabled: true,
             compile_multilib: "64",
         },
         windows_x86_64: {
@@ -622,7 +666,14 @@
     host_supported: true,
     native_binaries: ["myexports_mynativebinary@current"],
     target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
         windows: {
+            enabled: true,
             compile_multilib: "64",
         },
     },
@@ -636,6 +687,162 @@
 	)
 }
 
+func TestSnapshotWithSingleHostOsType(t *testing.T) {
+	ctx, config := testSdkContext(`
+		cc_defaults {
+			name: "mydefaults",
+			device_supported: false,
+			host_supported: true,
+			compile_multilib: "64",
+			target: {
+				host: {
+					enabled: false,
+				},
+				linux_bionic: {
+					enabled: true,
+				},
+			},
+		}
+
+		module_exports {
+			name: "myexports",
+			defaults: ["mydefaults"],
+			native_shared_libs: ["mynativelib"],
+			native_binaries: ["mynativebinary"],
+			compile_multilib: "64",  // The built-in default in sdk.go overrides mydefaults.
+		}
+
+		cc_library {
+			name: "mynativelib",
+			defaults: ["mydefaults"],
+			srcs: [
+				"Test.cpp",
+			],
+			stl: "none",
+		}
+
+		cc_binary {
+			name: "mynativebinary",
+			defaults: ["mydefaults"],
+			srcs: [
+				"Test.cpp",
+			],
+			stl: "none",
+		}
+	`, ccTestFs, []android.OsType{android.LinuxBionic})
+
+	result := runTests(t, ctx, config)
+
+	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,
+    installable: false,
+    stl: "none",
+    compile_multilib: "64",
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+        linux_bionic_x86_64: {
+            srcs: ["x86_64/bin/mynativebinary"],
+        },
+    },
+}
+
+cc_prebuilt_binary {
+    name: "mynativebinary",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    stl: "none",
+    compile_multilib: "64",
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+        linux_bionic_x86_64: {
+            srcs: ["x86_64/bin/mynativebinary"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "myexports_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    device_supported: false,
+    host_supported: true,
+    installable: false,
+    stl: "none",
+    compile_multilib: "64",
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+        linux_bionic_x86_64: {
+            srcs: ["x86_64/lib/mynativelib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mynativelib",
+    prefer: false,
+    device_supported: false,
+    host_supported: true,
+    stl: "none",
+    compile_multilib: "64",
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+        linux_bionic_x86_64: {
+            srcs: ["x86_64/lib/mynativelib.so"],
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    device_supported: false,
+    host_supported: true,
+    native_binaries: ["myexports_mynativebinary@current"],
+    native_shared_libs: ["myexports_mynativelib@current"],
+    compile_multilib: "64",
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_bionic: {
+            enabled: true,
+        },
+    },
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mynativebinary/linux_bionic_x86_64/mynativebinary -> x86_64/bin/mynativebinary
+.intermediates/mynativelib/linux_bionic_x86_64_shared/mynativelib.so -> x86_64/lib/mynativelib.so
+`),
+	)
+}
+
 // Test that we support the necessary flags for the linker binary, which is
 // special in several ways.
 func TestSnapshotWithCcStaticNocrtBinary(t *testing.T) {
@@ -674,11 +881,17 @@
     compile_multilib: "both",
     static_executable: true,
     nocrt: true,
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/bin/linker"],
         },
-        x86: {
+        linux_glibc_x86: {
             srcs: ["x86/bin/linker"],
         },
     },
@@ -693,11 +906,17 @@
     compile_multilib: "both",
     static_executable: true,
     nocrt: true,
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/bin/linker"],
         },
-        x86: {
+        linux_glibc_x86: {
             srcs: ["x86/bin/linker"],
         },
     },
@@ -708,6 +927,14 @@
     device_supported: false,
     host_supported: true,
     native_binaries: ["mymodule_exports_linker@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -1034,12 +1261,18 @@
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/lib/mynativelib.so"],
             export_include_dirs: ["x86_64/include_gen/mynativelib"],
         },
-        x86: {
+        linux_glibc_x86: {
             srcs: ["x86/lib/mynativelib.so"],
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
@@ -1055,12 +1288,18 @@
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/lib/mynativelib.so"],
             export_include_dirs: ["x86_64/include_gen/mynativelib"],
         },
-        x86: {
+        linux_glibc_x86: {
             srcs: ["x86/lib/mynativelib.so"],
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
@@ -1072,6 +1311,14 @@
     device_supported: false,
     host_supported: true,
     native_shared_libs: ["mysdk_mynativelib@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -1130,7 +1377,11 @@
     installable: false,
     stl: "none",
     target: {
+        host: {
+            enabled: false,
+        },
         linux_glibc: {
+            enabled: true,
             compile_multilib: "both",
         },
         linux_glibc_x86_64: {
@@ -1140,6 +1391,7 @@
             srcs: ["linux_glibc/x86/lib/mynativelib.so"],
         },
         windows: {
+            enabled: true,
             compile_multilib: "64",
         },
         windows_x86_64: {
@@ -1155,7 +1407,11 @@
     host_supported: true,
     stl: "none",
     target: {
+        host: {
+            enabled: false,
+        },
         linux_glibc: {
+            enabled: true,
             compile_multilib: "both",
         },
         linux_glibc_x86_64: {
@@ -1165,6 +1421,7 @@
             srcs: ["linux_glibc/x86/lib/mynativelib.so"],
         },
         windows: {
+            enabled: true,
             compile_multilib: "64",
         },
         windows_x86_64: {
@@ -1179,7 +1436,14 @@
     host_supported: true,
     native_shared_libs: ["mysdk_mynativelib@current"],
     target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
         windows: {
+            enabled: true,
             compile_multilib: "64",
         },
     },
@@ -1312,12 +1576,18 @@
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/lib/mynativelib.a"],
             export_include_dirs: ["x86_64/include_gen/mynativelib"],
         },
-        x86: {
+        linux_glibc_x86: {
             srcs: ["x86/lib/mynativelib.a"],
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
@@ -1332,12 +1602,18 @@
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/lib/mynativelib.a"],
             export_include_dirs: ["x86_64/include_gen/mynativelib"],
         },
-        x86: {
+        linux_glibc_x86: {
             srcs: ["x86/lib/mynativelib.a"],
             export_include_dirs: ["x86/include_gen/mynativelib"],
         },
@@ -1349,6 +1625,14 @@
     device_supported: false,
     host_supported: true,
     native_static_libs: ["myexports_mynativelib@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -1496,8 +1780,14 @@
     stl: "none",
     compile_multilib: "64",
     export_include_dirs: ["include/include"],
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/lib/mynativelib.a"],
             export_include_dirs: ["x86_64/include_gen/mynativelib"],
         },
@@ -1512,8 +1802,14 @@
     stl: "none",
     compile_multilib: "64",
     export_include_dirs: ["include/include"],
-    arch: {
-        x86_64: {
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+        linux_glibc_x86_64: {
             srcs: ["x86_64/lib/mynativelib.a"],
             export_include_dirs: ["x86_64/include_gen/mynativelib"],
         },
@@ -1526,6 +1822,14 @@
     host_supported: true,
     native_static_libs: ["myexports_mynativelib@current"],
     compile_multilib: "64",
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }`),
 		checkAllCopyRules(`
 include/Test.h -> include/include/Test.h
@@ -1612,6 +1916,14 @@
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 
 cc_prebuilt_library_headers {
@@ -1622,6 +1934,14 @@
     stl: "none",
     compile_multilib: "both",
     export_include_dirs: ["include/include"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 
 sdk_snapshot {
@@ -1629,6 +1949,14 @@
     device_supported: false,
     host_supported: true,
     native_header_libs: ["mysdk_mynativeheaders@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -1673,10 +2001,14 @@
     compile_multilib: "both",
     export_system_include_dirs: ["common_os/include/include"],
     target: {
+        host: {
+            enabled: false,
+        },
         android: {
             export_include_dirs: ["android/include/include-android"],
         },
         linux_glibc: {
+            enabled: true,
             export_include_dirs: ["linux_glibc/include/include-host"],
         },
     },
@@ -1690,10 +2022,14 @@
     compile_multilib: "both",
     export_system_include_dirs: ["common_os/include/include"],
     target: {
+        host: {
+            enabled: false,
+        },
         android: {
             export_include_dirs: ["android/include/include-android"],
         },
         linux_glibc: {
+            enabled: true,
             export_include_dirs: ["linux_glibc/include/include-host"],
         },
     },
@@ -1703,6 +2039,14 @@
     name: "mysdk@current",
     host_supported: true,
     native_header_libs: ["mysdk_mynativeheaders@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -1870,6 +2214,9 @@
     installable: false,
     compile_multilib: "both",
     target: {
+        host: {
+            enabled: false,
+        },
         android: {
             system_shared_libs: [],
         },
@@ -1879,6 +2226,9 @@
         android_arm: {
             srcs: ["android/arm/lib/sslvariants.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
         },
@@ -1894,6 +2244,9 @@
     host_supported: true,
     compile_multilib: "both",
     target: {
+        host: {
+            enabled: false,
+        },
         android: {
             system_shared_libs: [],
         },
@@ -1903,6 +2256,9 @@
         android_arm: {
             srcs: ["android/arm/lib/sslvariants.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
         },
@@ -1916,6 +2272,14 @@
     name: "mysdk@current",
     host_supported: true,
     native_shared_libs: ["mysdk_sslvariants@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `))
 }
@@ -2025,12 +2389,18 @@
         versions: ["3"],
     },
     target: {
+        host: {
+            enabled: false,
+        },
         android_arm64: {
             srcs: ["android/arm64/lib/stubslib.so"],
         },
         android_arm: {
             srcs: ["android/arm/lib/stubslib.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/stubslib.so"],
         },
@@ -2049,12 +2419,18 @@
         versions: ["3"],
     },
     target: {
+        host: {
+            enabled: false,
+        },
         android_arm64: {
             srcs: ["android/arm64/lib/stubslib.so"],
         },
         android_arm: {
             srcs: ["android/arm/lib/stubslib.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/stubslib.so"],
         },
@@ -2068,6 +2444,14 @@
     name: "mysdk@current",
     host_supported: true,
     native_shared_libs: ["mysdk_stubslib@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `))
 }
@@ -2099,12 +2483,18 @@
     unique_host_soname: true,
     compile_multilib: "both",
     target: {
+        host: {
+            enabled: false,
+        },
         android_arm64: {
             srcs: ["android/arm64/lib/mylib.so"],
         },
         android_arm: {
             srcs: ["android/arm/lib/mylib.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
         },
@@ -2121,12 +2511,18 @@
     unique_host_soname: true,
     compile_multilib: "both",
     target: {
+        host: {
+            enabled: false,
+        },
         android_arm64: {
             srcs: ["android/arm64/lib/mylib.so"],
         },
         android_arm: {
             srcs: ["android/arm/lib/mylib.so"],
         },
+        linux_glibc: {
+            enabled: true,
+        },
         linux_glibc_x86_64: {
             srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
         },
@@ -2140,6 +2536,14 @@
     name: "mysdk@current",
     host_supported: true,
     native_shared_libs: ["mysdk_mylib@current"],
+    target: {
+        host: {
+            enabled: false,
+        },
+        linux_glibc: {
+            enabled: true,
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
diff --git a/sdk/update.go b/sdk/update.go
index 25d50d2..936696a 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -262,7 +262,7 @@
 		memberCtx := &memberContext{ctx, builder, memberType, member.name}
 
 		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
-		s.createMemberSnapshot(memberCtx, member, prebuiltModule)
+		s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule))
 	}
 
 	// Create a transformer that will transform an unversioned module into a versioned module.
@@ -345,12 +345,37 @@
 		snapshotModule.AddProperty("compile_multilib", commonVariantProperties.Compile_multilib)
 	}
 
-	// Iterate over the os types in a fixed order.
 	targetPropertySet := snapshotModule.AddPropertySet("target")
+
+	// If host is supported and any member is host OS dependent then disable host
+	// by default, so that we can enable each host OS variant explicitly. This
+	// avoids problems with implicitly enabled OS variants when the snapshot is
+	// used, which might be different from this run (e.g. different build OS).
+	hasHostOsDependentMember := false
+	if s.HostSupported() {
+		for _, memberRef := range memberRefs {
+			if memberRef.memberType.IsHostOsDependent() {
+				hasHostOsDependentMember = true
+				break
+			}
+		}
+		if hasHostOsDependentMember {
+			hostPropertySet := targetPropertySet.AddPropertySet("host")
+			hostPropertySet.AddProperty("enabled", false)
+		}
+	}
+
+	// Iterate over the os types in a fixed order.
 	for _, osType := range s.getPossibleOsTypes() {
 		if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
 			osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
 
+			// Enable the variant explicitly when we've disabled it by default on host.
+			if hasHostOsDependentMember &&
+				(osType.Class == android.Host || osType.Class == android.HostCross) {
+				osPropertySet.AddProperty("enabled", true)
+			}
+
 			variantProps := variantToProperties[sdkVariant]
 			if variantProps.Compile_multilib != "" && variantProps.Compile_multilib != "both" {
 				osPropertySet.AddProperty("compile_multilib", variantProps.Compile_multilib)
@@ -993,9 +1018,12 @@
 	var osPropertySet android.BpPropertySet
 	var archPropertySet android.BpPropertySet
 	var archOsPrefix string
-	if osInfo.Properties.Base().Os_count == 1 {
-		// There is only one os type present in the variants so don't bother
-		// with adding target specific properties.
+	if osInfo.Properties.Base().Os_count == 1 &&
+		(osInfo.osType.Class == android.Device || !ctx.memberType.IsHostOsDependent()) {
+		// There is only one OS type present in the variants and it shouldn't have a
+		// variant-specific target. The latter is the case if it's either for device
+		// where there is only one OS (android), or for host and the member type
+		// isn't host OS dependent.
 
 		// Create a structure that looks like:
 		// module_type {
@@ -1032,6 +1060,12 @@
 		osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
 		archPropertySet = targetPropertySet
 
+		// Enable the variant explicitly when we've disabled it by default on host.
+		if ctx.memberType.IsHostOsDependent() &&
+			(osType.Class == android.Host || osType.Class == android.HostCross) {
+			osPropertySet.AddProperty("enabled", true)
+		}
+
 		// Arch specific properties need to be added to an os and arch specific
 		// section prefixed with <os>_.
 		archOsPrefix = osType.Name + "_"
@@ -1202,7 +1236,7 @@
 	return m.name
 }
 
-func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
+func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
 
 	memberType := member.memberType
 
@@ -1256,6 +1290,18 @@
 	// added.
 	targetPropertySet := bpModule.AddPropertySet("target")
 
+	// If the member is host OS dependent and has host_supported then disable by
+	// default and enable each host OS variant explicitly. This avoids problems
+	// with implicitly enabled OS variants when the snapshot is used, which might
+	// be different from this run (e.g. different build OS).
+	if ctx.memberType.IsHostOsDependent() {
+		hostSupported := bpModule.getValue("host_supported") == true // Missing means false.
+		if hostSupported {
+			hostPropertySet := targetPropertySet.AddPropertySet("host")
+			hostPropertySet.AddProperty("enabled", false)
+		}
+	}
+
 	// Iterate over the os types in a fixed order.
 	for _, osType := range s.getPossibleOsTypes() {
 		osInfo := osTypeToInfo[osType]