Merge "Remove most of the remaining references to gccCmd."
diff --git a/android/arch.go b/android/arch.go
index 74fef3d..c1b2c33 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1014,35 +1014,19 @@
 	base.customizableProperties = m.GetProperties()
 }
 
-// appendProperties squashes properties from the given field of the given src property struct
-// into the dst property struct.  Returns the reflect.Value of the field in the src property
-// struct to be used for further appendProperties calls on fields of that property struct.
-func (m *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
-	dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
-
-	// Step into non-nil pointers to structs in the src value.
-	if src.Kind() == reflect.Ptr {
-		if src.IsNil() {
-			return src
-		}
-		src = src.Elem()
-	}
-
-	// Find the requested field in the src struct.
-	src = src.FieldByName(field)
-	if !src.IsValid() {
-		ctx.ModuleErrorf("field %q does not exist", srcPrefix)
-		return src
-	}
-
-	// Save the value of the field in the src struct to return.
-	ret := src
-
+func maybeBlueprintEmbed(src reflect.Value) reflect.Value {
 	// If the value of the field is a struct (as opposed to a pointer to a struct) then step
 	// into the BlueprintEmbed field.
 	if src.Kind() == reflect.Struct {
-		src = src.FieldByName("BlueprintEmbed")
+		return src.FieldByName("BlueprintEmbed")
+	} else {
+		return src
 	}
+}
+
+// Merges the property struct in srcValue into dst.
+func mergePropertyStruct(ctx BaseMutatorContext, dst interface{}, srcValue reflect.Value) {
+	src := maybeBlueprintEmbed(srcValue).Interface()
 
 	// order checks the `android:"variant_prepend"` tag to handle properties where the
 	// arch-specific value needs to come before the generic value, for example for lists of
@@ -1058,7 +1042,7 @@
 	}
 
 	// Squash the located property struct into the destination property struct.
-	err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, order)
+	err := proptools.ExtendMatchingProperties([]interface{}{dst}, src, nil, order)
 	if err != nil {
 		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
 			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
@@ -1066,8 +1050,29 @@
 			panic(err)
 		}
 	}
+}
 
-	return ret
+// Returns the immediate child of the input property struct that corresponds to
+// the sub-property "field".
+func getChildPropertyStruct(ctx BaseMutatorContext,
+	src reflect.Value, field, userFriendlyField string) reflect.Value {
+
+	// Step into non-nil pointers to structs in the src value.
+	if src.Kind() == reflect.Ptr {
+		if src.IsNil() {
+			return src
+		}
+		src = src.Elem()
+	}
+
+	// Find the requested field in the src struct.
+	src = src.FieldByName(proptools.FieldNameForProperty(field))
+	if !src.IsValid() {
+		ctx.ModuleErrorf("field %q does not exist", userFriendlyField)
+		return src
+	}
+
+	return src
 }
 
 // Squash the appropriate OS-specific property structs into the matching top level property structs
@@ -1094,7 +1099,8 @@
 			if os.Class == Host {
 				field := "Host"
 				prefix := "target.host"
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				hostProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
+				mergePropertyStruct(ctx, genProps, hostProperties)
 			}
 
 			// Handle target OS generalities of the form:
@@ -1106,13 +1112,15 @@
 			if os.Linux() {
 				field := "Linux"
 				prefix := "target.linux"
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				linuxProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
+				mergePropertyStruct(ctx, genProps, linuxProperties)
 			}
 
 			if os.Bionic() {
 				field := "Bionic"
 				prefix := "target.bionic"
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				bionicProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
+				mergePropertyStruct(ctx, genProps, bionicProperties)
 			}
 
 			// Handle target OS properties in the form:
@@ -1129,12 +1137,14 @@
 			// },
 			field := os.Field
 			prefix := "target." + os.Name
-			m.appendProperties(ctx, genProps, targetProp, field, prefix)
+			osProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
+			mergePropertyStruct(ctx, genProps, osProperties)
 
 			if os.Class == Host && os != Windows {
 				field := "Not_windows"
 				prefix := "target.not_windows"
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				notWindowsProperties := getChildPropertyStruct(ctx, targetProp, field, prefix)
+				mergePropertyStruct(ctx, genProps, notWindowsProperties)
 			}
 
 			// Handle 64-bit device properties in the form:
@@ -1154,17 +1164,189 @@
 				if ctx.Config().Android64() {
 					field := "Android64"
 					prefix := "target.android64"
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
+					android64Properties := getChildPropertyStruct(ctx, targetProp, field, prefix)
+					mergePropertyStruct(ctx, genProps, android64Properties)
 				} else {
 					field := "Android32"
 					prefix := "target.android32"
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
+					android32Properties := getChildPropertyStruct(ctx, targetProp, field, prefix)
+					mergePropertyStruct(ctx, genProps, android32Properties)
 				}
 			}
 		}
 	}
 }
 
+// Returns the struct containing the properties specific to the given
+// architecture type. These look like this in Blueprint files:
+// arch: {
+//     arm64: {
+//         key: value,
+//     },
+// },
+// This struct will also contain sub-structs containing to the architecture/CPU
+// variants and features that themselves contain properties specific to those.
+func getArchTypeStruct(ctx BaseMutatorContext, archProperties interface{}, archType ArchType) reflect.Value {
+	archPropValues := reflect.ValueOf(archProperties).Elem()
+	archProp := archPropValues.FieldByName("Arch").Elem()
+	prefix := "arch." + archType.Name
+	archStruct := getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
+	return archStruct
+}
+
+// Returns the struct containing the properties specific to a given multilib
+// value. These look like this in the Blueprint file:
+// multilib: {
+//     lib32: {
+//         key: value,
+//     },
+// },
+func getMultilibStruct(ctx BaseMutatorContext, archProperties interface{}, archType ArchType) reflect.Value {
+	archPropValues := reflect.ValueOf(archProperties).Elem()
+	multilibProp := archPropValues.FieldByName("Multilib").Elem()
+	multilibProperties := getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
+	return multilibProperties
+}
+
+// Returns the structs corresponding to the properties specific to the given
+// architecture and OS in archProperties.
+func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value {
+	result := make([]reflect.Value, 0)
+	archPropValues := reflect.ValueOf(archProperties).Elem()
+
+	targetProp := archPropValues.FieldByName("Target").Elem()
+
+	archType := arch.ArchType
+
+	if arch.ArchType != Common {
+		archStruct := getArchTypeStruct(ctx, archProperties, arch.ArchType)
+		result = append(result, archStruct)
+
+		// Handle arch-variant-specific properties in the form:
+		// arch: {
+		//     arm: {
+		//         variant: {
+		//             key: value,
+		//         },
+		//     },
+		// },
+		v := variantReplacer.Replace(arch.ArchVariant)
+		if v != "" {
+			prefix := "arch." + archType.Name + "." + v
+			variantProperties := getChildPropertyStruct(ctx, archStruct, v, prefix)
+			result = append(result, variantProperties)
+		}
+
+		// Handle cpu-variant-specific properties in the form:
+		// arch: {
+		//     arm: {
+		//         variant: {
+		//             key: value,
+		//         },
+		//     },
+		// },
+		if arch.CpuVariant != arch.ArchVariant {
+			c := variantReplacer.Replace(arch.CpuVariant)
+			if c != "" {
+				prefix := "arch." + archType.Name + "." + c
+				cpuVariantProperties := getChildPropertyStruct(ctx, archStruct, c, prefix)
+				result = append(result, cpuVariantProperties)
+			}
+		}
+
+		// Handle arch-feature-specific properties in the form:
+		// arch: {
+		//     arm: {
+		//         feature: {
+		//             key: value,
+		//         },
+		//     },
+		// },
+		for _, feature := range arch.ArchFeatures {
+			prefix := "arch." + archType.Name + "." + feature
+			featureProperties := getChildPropertyStruct(ctx, archStruct, feature, prefix)
+			result = append(result, featureProperties)
+		}
+
+		multilibProperties := getMultilibStruct(ctx, archProperties, archType)
+		result = append(result, multilibProperties)
+
+		// Handle combined OS-feature and arch specific properties in the form:
+		// target: {
+		//     bionic_x86: {
+		//         key: value,
+		//     },
+		// }
+		if os.Linux() {
+			field := "Linux_" + arch.ArchType.Name
+			userFriendlyField := "target.linux_" + arch.ArchType.Name
+			linuxProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
+			result = append(result, linuxProperties)
+		}
+
+		if os.Bionic() {
+			field := "Bionic_" + archType.Name
+			userFriendlyField := "target.bionic_" + archType.Name
+			bionicProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
+			result = append(result, bionicProperties)
+		}
+
+		// Handle combined OS and arch specific properties in the form:
+		// target: {
+		//     linux_glibc_x86: {
+		//         key: value,
+		//     },
+		//     linux_glibc_arm: {
+		//         key: value,
+		//     },
+		//     android_arm {
+		//         key: value,
+		//     },
+		//     android_x86 {
+		//         key: value,
+		//     },
+		// },
+		field := os.Field + "_" + archType.Name
+		userFriendlyField := "target." + os.Name + "_" + archType.Name
+		osArchProperties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
+		result = append(result, osArchProperties)
+	}
+
+	// Handle arm on x86 properties in the form:
+	// target {
+	//     arm_on_x86 {
+	//         key: value,
+	//     },
+	//     arm_on_x86_64 {
+	//         key: value,
+	//     },
+	// },
+	if os.Class == Device {
+		if arch.ArchType == X86 && (hasArmAbi(arch) ||
+			hasArmAndroidArch(ctx.Config().Targets[Android])) {
+			field := "Arm_on_x86"
+			userFriendlyField := "target.arm_on_x86"
+			armOnX86Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
+			result = append(result, armOnX86Properties)
+		}
+		if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
+			hasArmAndroidArch(ctx.Config().Targets[Android])) {
+			field := "Arm_on_x86_64"
+			userFriendlyField := "target.arm_on_x86_64"
+			armOnX8664Properties := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField)
+			result = append(result, armOnX8664Properties)
+		}
+		if os == Android && nativeBridgeEnabled {
+			userFriendlyField := "Native_bridge"
+			prefix := "target.native_bridge"
+			nativeBridgeProperties := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix)
+			result = append(result, nativeBridgeProperties)
+		}
+	}
+
+	return result
+}
+
 // Squash the appropriate arch-specific property structs into the matching top level property
 // structs based on the CompileTarget value that was annotated on the variant.
 func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
@@ -1176,144 +1358,15 @@
 		if m.archProperties[i] == nil {
 			continue
 		}
-		for _, archProperties := range m.archProperties[i] {
-			archPropValues := reflect.ValueOf(archProperties).Elem()
 
-			archProp := archPropValues.FieldByName("Arch").Elem()
-			multilibProp := archPropValues.FieldByName("Multilib").Elem()
-			targetProp := archPropValues.FieldByName("Target").Elem()
+		propStructs := make([]reflect.Value, 0)
+		for _, archProperty := range m.archProperties[i] {
+			propStructShard := getArchProperties(ctx, archProperty, arch, os, m.Target().NativeBridge == NativeBridgeEnabled)
+			propStructs = append(propStructs, propStructShard...)
+		}
 
-			// Handle arch-specific properties in the form:
-			// arch: {
-			//     arm64: {
-			//         key: value,
-			//     },
-			// },
-			t := arch.ArchType
-
-			if arch.ArchType != Common {
-				field := proptools.FieldNameForProperty(t.Name)
-				prefix := "arch." + t.Name
-				archStruct := m.appendProperties(ctx, genProps, archProp, field, prefix)
-
-				// Handle arch-variant-specific properties in the form:
-				// arch: {
-				//     variant: {
-				//         key: value,
-				//     },
-				// },
-				v := variantReplacer.Replace(arch.ArchVariant)
-				if v != "" {
-					field := proptools.FieldNameForProperty(v)
-					prefix := "arch." + t.Name + "." + v
-					m.appendProperties(ctx, genProps, archStruct, field, prefix)
-				}
-
-				// Handle cpu-variant-specific properties in the form:
-				// arch: {
-				//     variant: {
-				//         key: value,
-				//     },
-				// },
-				if arch.CpuVariant != arch.ArchVariant {
-					c := variantReplacer.Replace(arch.CpuVariant)
-					if c != "" {
-						field := proptools.FieldNameForProperty(c)
-						prefix := "arch." + t.Name + "." + c
-						m.appendProperties(ctx, genProps, archStruct, field, prefix)
-					}
-				}
-
-				// Handle arch-feature-specific properties in the form:
-				// arch: {
-				//     feature: {
-				//         key: value,
-				//     },
-				// },
-				for _, feature := range arch.ArchFeatures {
-					field := proptools.FieldNameForProperty(feature)
-					prefix := "arch." + t.Name + "." + feature
-					m.appendProperties(ctx, genProps, archStruct, field, prefix)
-				}
-
-				// Handle multilib-specific properties in the form:
-				// multilib: {
-				//     lib32: {
-				//         key: value,
-				//     },
-				// },
-				field = proptools.FieldNameForProperty(t.Multilib)
-				prefix = "multilib." + t.Multilib
-				m.appendProperties(ctx, genProps, multilibProp, field, prefix)
-			}
-
-			// Handle combined OS-feature and arch specific properties in the form:
-			// target: {
-			//     bionic_x86: {
-			//         key: value,
-			//     },
-			// }
-			if os.Linux() && arch.ArchType != Common {
-				field := "Linux_" + arch.ArchType.Name
-				prefix := "target.linux_" + arch.ArchType.Name
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
-			}
-
-			if os.Bionic() && arch.ArchType != Common {
-				field := "Bionic_" + t.Name
-				prefix := "target.bionic_" + t.Name
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
-			}
-
-			// Handle combined OS and arch specific properties in the form:
-			// target: {
-			//     linux_glibc_x86: {
-			//         key: value,
-			//     },
-			//     linux_glibc_arm: {
-			//         key: value,
-			//     },
-			//     android_arm {
-			//         key: value,
-			//     },
-			//     android_x86 {
-			//         key: value,
-			//     },
-			// },
-			if arch.ArchType != Common {
-				field := os.Field + "_" + t.Name
-				prefix := "target." + os.Name + "_" + t.Name
-				m.appendProperties(ctx, genProps, targetProp, field, prefix)
-			}
-
-			// Handle arm on x86 properties in the form:
-			// target {
-			//     arm_on_x86 {
-			//         key: value,
-			//     },
-			//     arm_on_x86_64 {
-			//         key: value,
-			//     },
-			// },
-			if os.Class == Device {
-				if arch.ArchType == X86 && (hasArmAbi(arch) ||
-					hasArmAndroidArch(ctx.Config().Targets[Android])) {
-					field := "Arm_on_x86"
-					prefix := "target.arm_on_x86"
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
-				}
-				if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
-					hasArmAndroidArch(ctx.Config().Targets[Android])) {
-					field := "Arm_on_x86_64"
-					prefix := "target.arm_on_x86_64"
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
-				}
-				if os == Android && m.Target().NativeBridge == NativeBridgeEnabled {
-					field := "Native_bridge"
-					prefix := "target.native_bridge"
-					m.appendProperties(ctx, genProps, targetProp, field, prefix)
-				}
-			}
+		for _, propStruct := range propStructs {
+			mergePropertyStruct(ctx, genProps, propStruct)
 		}
 	}
 }
@@ -1810,7 +1863,7 @@
 // For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }`
 // will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given
 // propertyset contains `Foo []string`.
-func (m *ModuleBase) GetArchProperties(propertySet interface{}) map[ArchType]interface{} {
+func (m *ModuleBase) GetArchProperties(ctx BaseMutatorContext, propertySet interface{}) map[ArchType]interface{} {
 	// Return value of the arch types to the prop values for that arch.
 	archToProp := map[ArchType]interface{}{}
 
@@ -1819,27 +1872,47 @@
 		return archToProp
 	}
 
-	// For each arch (x86, arm64, etc.),
+	dstType := reflect.ValueOf(propertySet).Type()
+	var archProperties []interface{}
+
+	// First find the property set in the module that corresponds to the requested
+	// one. m.archProperties[i] corresponds to m.generalProperties[i].
+	for i, generalProp := range m.generalProperties {
+		srcType := reflect.ValueOf(generalProp).Type()
+		if srcType == dstType {
+			archProperties = m.archProperties[i]
+			break
+		}
+	}
+
+	if archProperties == nil {
+		// This module does not have the property set requested
+		return archToProp
+	}
+
+	// For each arch type (x86, arm64, etc.)
 	for _, arch := range ArchTypeList() {
-		// Find arch-specific properties matching that property set type. For example, any
-		// matching properties under `arch { x86 { ... } }`.
-		archPropertySet := m.getArchPropertySet(propertySet, arch)
-
-		// Find multilib-specific properties matching that property set type. For example, any
-		// matching properties under `multilib { lib32 { ... } }` for x86, as x86 is 32-bit.
-		multilibPropertySet := m.getMultilibPropertySet(propertySet, arch)
-
-		// Append the multilibPropertySet to archPropertySet. This combines the
-		// arch and multilib properties into a single property struct.
-		err := proptools.ExtendMatchingProperties([]interface{}{archPropertySet}, multilibPropertySet, nil, proptools.OrderAppend)
-		if err != nil {
-			// archPropertySet and multilibPropertySet must be of the same type, or
-			// something horrible went wrong.
-			panic(err)
+		// Arch properties are sometimes sharded (see createArchPropTypeDesc() ).
+		// Iterate over ever shard and extract a struct with the same type as the
+		// input one that contains the data specific to that arch.
+		propertyStructs := make([]reflect.Value, 0)
+		for _, archProperty := range archProperties {
+			archTypeStruct := getArchTypeStruct(ctx, archProperty, arch)
+			multilibStruct := getMultilibStruct(ctx, archProperty, arch)
+			propertyStructs = append(propertyStructs, archTypeStruct, multilibStruct)
 		}
 
-		archToProp[arch] = archPropertySet
+		// Create a new instance of the requested property set
+		value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
+
+		// Merge all the structs together
+		for _, propertyStruct := range propertyStructs {
+			mergePropertyStruct(ctx, value, propertyStruct)
+		}
+
+		archToProp[arch] = value
 	}
+
 	return archToProp
 }
 
diff --git a/android/bazel.go b/android/bazel.go
index 71884a7..6c476a7 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -210,7 +210,6 @@
 		"libc_tzcode",           // http://b/186822591, cc_library_static, localtime.c:84:46: error: expected expression
 		"libc_bionic_ndk",       // http://b/186822256, cc_library_static, signal.cpp:186:52: error: ISO C++ requires field designators to be specified in declaration order
 		"libc_malloc_hooks",     // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
-		"libstdc++",             // http://b/186822597, cc_library, ld.lld: error: undefined symbol: __errno
 		"libm",                  // http://b/183064661, cc_library, math.h:25:16: error: unexpected token in argument list
 
 		// http://b/186823769: Needs C++ STL support, includes from unconverted standard libraries in //external/libcxx
@@ -237,6 +236,12 @@
 		"libjemalloc5_unittest",
 	}
 
+	// Per-module denylist of cc_library modules to only generate the static
+	// variant if their shared variant isn't ready or buildable by Bazel.
+	bp2buildCcLibraryStaticOnlyList = []string{
+		"libstdc++", // http://b/186822597, cc_library, ld.lld: error: undefined symbol: __errno
+	}
+
 	// Per-module denylist to opt modules out of mixed builds. Such modules will
 	// still be generated via bp2build.
 	mixedBuildsDisabledList = []string{
@@ -251,6 +256,7 @@
 	// Used for quicker lookups
 	bp2buildDoNotWriteBuildFile = map[string]bool{}
 	bp2buildModuleDoNotConvert  = map[string]bool{}
+	bp2buildCcLibraryStaticOnly = map[string]bool{}
 	mixedBuildsDisabled         = map[string]bool{}
 )
 
@@ -263,11 +269,19 @@
 		bp2buildModuleDoNotConvert[moduleName] = true
 	}
 
+	for _, moduleName := range bp2buildCcLibraryStaticOnlyList {
+		bp2buildCcLibraryStaticOnly[moduleName] = true
+	}
+
 	for _, moduleName := range mixedBuildsDisabledList {
 		mixedBuildsDisabled[moduleName] = true
 	}
 }
 
+func GenerateCcLibraryStaticOnly(ctx BazelConversionPathContext) bool {
+	return bp2buildCcLibraryStaticOnly[ctx.Module().Name()]
+}
+
 func ShouldWriteBuildFileForDir(dir string) bool {
 	if _, ok := bp2buildDoNotWriteBuildFile[dir]; ok {
 		return false
@@ -285,6 +299,12 @@
 	if len(b.GetBazelLabel(ctx, ctx.Module())) == 0 {
 		return false
 	}
+	if GenerateCcLibraryStaticOnly(ctx) {
+		// Don't use partially-converted cc_library targets in mixed builds,
+		// since mixed builds would generally rely on both static and shared
+		// variants of a cc_library.
+		return false
+	}
 	return !mixedBuildsDisabled[ctx.Module().Name()]
 }
 
diff --git a/android/license.go b/android/license.go
index 3bc6199..cb375a2 100644
--- a/android/license.go
+++ b/android/license.go
@@ -51,6 +51,7 @@
 type licenseModule struct {
 	ModuleBase
 	DefaultableModuleBase
+	SdkBase
 
 	properties licenseProperties
 }
@@ -75,6 +76,7 @@
 	// The visibility property needs to be checked and parsed by the visibility module.
 	setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
 
+	InitSdkAwareModule(module)
 	initAndroidModuleBase(module)
 	InitDefaultableModule(module)
 
diff --git a/android/paths.go b/android/paths.go
index b934687..5d458cb 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -24,6 +24,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/pathtools"
 )
 
@@ -449,6 +450,12 @@
 		return outputFiles, nil
 	} else if tag != "" {
 		return nil, fmt.Errorf("path dependency %q is not an output file producing module", path)
+	} else if goBinary, ok := module.(bootstrap.GoBinaryTool); ok {
+		if rel, err := filepath.Rel(PathForOutput(ctx).String(), goBinary.InstallPath()); err == nil {
+			return Paths{PathForOutput(ctx, rel).WithoutRel()}, nil
+		} else {
+			return nil, fmt.Errorf("cannot find output path for %q: %w", goBinary.InstallPath(), err)
+		}
 	} else if srcProducer, ok := module.(SourceFileProducer); ok {
 		return srcProducer.Srcs(), nil
 	} else {
diff --git a/android/sdk.go b/android/sdk.go
index 6fc1910..0adfd89 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -41,6 +41,11 @@
 	sdkBase() *SdkBase
 	MakeMemberOf(sdk SdkRef)
 	IsInAnySdk() bool
+
+	// IsVersioned determines whether the module is versioned, i.e. has a name of the form
+	// <name>@<version>
+	IsVersioned() bool
+
 	ContainingSdk() SdkRef
 	MemberName() string
 	BuildWithSdks(sdks SdkRefs)
@@ -82,7 +87,7 @@
 func ParseSdkRef(ctx BaseModuleContext, str string, property string) SdkRef {
 	tokens := strings.Split(str, string(SdkVersionSeparator))
 	if len(tokens) < 1 || len(tokens) > 2 {
-		ctx.PropertyErrorf(property, "%q does not follow name#version syntax", str)
+		ctx.PropertyErrorf(property, "%q does not follow name@version syntax", str)
 		return SdkRef{Name: "invalid sdk name", Version: "invalid sdk version"}
 	}
 
@@ -140,6 +145,11 @@
 	return s.properties.ContainingSdk != nil
 }
 
+// IsVersioned returns true if this module is versioned.
+func (s *SdkBase) IsVersioned() bool {
+	return strings.Contains(s.module.Name(), "@")
+}
+
 // ContainingSdk returns the SDK that this module is a member of
 func (s *SdkBase) ContainingSdk() SdkRef {
 	if s.properties.ContainingSdk != nil {
@@ -292,9 +302,7 @@
 }
 
 // SdkMemberTypeDependencyTag is the interface that a tag must implement in order to allow the
-// dependent module to be automatically added to the sdk. In order for this to work the
-// SdkMemberType of the depending module must return true from
-// SdkMemberType.HasTransitiveSdkMembers.
+// dependent module to be automatically added to the sdk.
 type SdkMemberTypeDependencyTag interface {
 	blueprint.DependencyTag
 
@@ -375,13 +383,6 @@
 	// True if the member type supports the sdk/sdk_snapshot, false otherwise.
 	UsableWithSdkAndSdkSnapshot() bool
 
-	// Return true if modules of this type can have dependencies which should be
-	// treated as if they are sdk members.
-	//
-	// Any dependency that is to be treated as a member of the sdk needs to implement
-	// 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
@@ -447,10 +448,9 @@
 
 // Base type for SdkMemberType implementations.
 type SdkMemberTypeBase struct {
-	PropertyName         string
-	SupportsSdk          bool
-	TransitiveSdkMembers bool
-	HostOsDependent      bool
+	PropertyName    string
+	SupportsSdk     bool
+	HostOsDependent bool
 }
 
 func (b *SdkMemberTypeBase) SdkPropertyName() string {
@@ -461,10 +461,6 @@
 	return b.SupportsSdk
 }
 
-func (b *SdkMemberTypeBase) HasTransitiveSdkMembers() bool {
-	return b.TransitiveSdkMembers
-}
-
 func (b *SdkMemberTypeBase) IsHostOsDependent() bool {
 	return b.HostOsDependent
 }
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 7830f95..8996352 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -110,6 +110,13 @@
 	}
 }
 
+// Implements android.DepInInSameApex
+func (p *prebuiltCommon) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+	tag := ctx.OtherModuleDependencyTag(dep)
+	_, ok := tag.(exportedDependencyTag)
+	return ok
+}
+
 // apexInfoMutator marks any modules for which this apex exports a file as requiring an apex
 // specific variant and checks that they are supported.
 //
@@ -142,34 +149,43 @@
 
 	// Collect the list of dependencies.
 	var dependencies []android.ApexModule
-	mctx.VisitDirectDeps(func(m android.Module) {
-		tag := mctx.OtherModuleDependencyTag(m)
+	mctx.WalkDeps(func(child, parent android.Module) bool {
+		// If the child is not in the same apex as the parent then exit immediately and do not visit
+		// any of the child's dependencies.
+		if !android.IsDepInSameApex(mctx, parent, child) {
+			return false
+		}
+
+		tag := mctx.OtherModuleDependencyTag(child)
+		depName := mctx.OtherModuleName(child)
 		if exportedTag, ok := tag.(exportedDependencyTag); ok {
 			propertyName := exportedTag.name
-			depName := mctx.OtherModuleName(m)
 
 			// It is an error if the other module is not a prebuilt.
-			if _, ok := m.(android.PrebuiltInterface); !ok {
+			if !android.IsModulePrebuilt(child) {
 				mctx.PropertyErrorf(propertyName, "%q is not a prebuilt module", depName)
-				return
+				return false
 			}
 
 			// It is an error if the other module is not an ApexModule.
-			if _, ok := m.(android.ApexModule); !ok {
+			if _, ok := child.(android.ApexModule); !ok {
 				mctx.PropertyErrorf(propertyName, "%q is not usable within an apex", depName)
-				return
+				return false
 			}
-
-			// Strip off the prebuilt_ prefix if present before storing content to ensure consistent
-			// behavior whether there is a corresponding source module present or not.
-			depName = android.RemoveOptionalPrebuiltPrefix(depName)
-
-			// Remember that this module was added as a direct dependency.
-			contents[depName] = contents[depName].Add(true)
-
-			// Add the module to the list of dependencies that need to have an APEX variant.
-			dependencies = append(dependencies, m.(android.ApexModule))
 		}
+
+		// Strip off the prebuilt_ prefix if present before storing content to ensure consistent
+		// behavior whether there is a corresponding source module present or not.
+		depName = android.RemoveOptionalPrebuiltPrefix(depName)
+
+		// Remember if this module was added as a direct dependency.
+		direct := parent == mctx.Module()
+		contents[depName] = contents[depName].Add(direct)
+
+		// Add the module to the list of dependencies that need to have an APEX variant.
+		dependencies = append(dependencies, child.(android.ApexModule))
+
+		return true
 	})
 
 	// Create contents for the prebuilt_apex and store it away for later use.
diff --git a/bazel/properties.go b/bazel/properties.go
index 12dfcaf..a71b12b 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -229,11 +229,47 @@
 
 // Represents an attribute whose value is a single label
 type LabelAttribute struct {
-	Value Label
+	Value  Label
+	X86    Label
+	X86_64 Label
+	Arm    Label
+	Arm64  Label
 }
 
-func (LabelAttribute) HasConfigurableValues() bool {
-	return false
+func (attr *LabelAttribute) GetValueForArch(arch string) Label {
+	switch arch {
+	case ARCH_ARM:
+		return attr.Arm
+	case ARCH_ARM64:
+		return attr.Arm64
+	case ARCH_X86:
+		return attr.X86
+	case ARCH_X86_64:
+		return attr.X86_64
+	case CONDITIONS_DEFAULT:
+		return attr.Value
+	default:
+		panic("Invalid arch type")
+	}
+}
+
+func (attr *LabelAttribute) SetValueForArch(arch string, value Label) {
+	switch arch {
+	case ARCH_ARM:
+		attr.Arm = value
+	case ARCH_ARM64:
+		attr.Arm64 = value
+	case ARCH_X86:
+		attr.X86 = value
+	case ARCH_X86_64:
+		attr.X86_64 = value
+	default:
+		panic("Invalid arch type")
+	}
+}
+
+func (attr LabelAttribute) HasConfigurableValues() bool {
+	return attr.Arm.Label != "" || attr.Arm64.Label != "" || attr.X86.Label != "" || attr.X86_64.Label != ""
 }
 
 // Arch-specific label_list typed Bazel attribute values. This should correspond
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 050679b..95a2747 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -59,22 +59,30 @@
 func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
 	var value reflect.Value
 	var archSelects, osSelects selects
+	var defaultSelectValue string
 	switch list := v.(type) {
 	case bazel.StringListAttribute:
 		value, archSelects, osSelects = getStringListValues(list)
+		defaultSelectValue = "[]"
 	case bazel.LabelListAttribute:
 		value, archSelects, osSelects = getLabelListValues(list)
+		defaultSelectValue = "[]"
 	case bazel.LabelAttribute:
 		value, archSelects, osSelects = getLabelValue(list)
+		defaultSelectValue = "None"
 	default:
 		return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
 	}
 
-	ret, err := prettyPrint(value, indent)
-	if err != nil {
-		return ret, err
-	}
+	ret := ""
+	if value.Kind() != reflect.Invalid {
+		s, err := prettyPrint(value, indent)
+		if err != nil {
+			return ret, err
+		}
 
+		ret += s
+	}
 	// Convenience function to append selects components to an attribute value.
 	appendSelects := func(selectsData selects, defaultValue, s string) (string, error) {
 		selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent)
@@ -89,12 +97,12 @@
 		return s, nil
 	}
 
-	ret, err = appendSelects(archSelects, "[]", ret)
+	ret, err := appendSelects(archSelects, defaultSelectValue, ret)
 	if err != nil {
 		return "", err
 	}
 
-	ret, err = appendSelects(osSelects, "[]", ret)
+	ret, err = appendSelects(osSelects, defaultSelectValue, ret)
 	return ret, err
 }
 
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 452f6ed..b925682 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -142,7 +142,7 @@
 
 		paths := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.props.Arch_paths))
 
-		for arch, props := range m.GetArchProperties(&customProps{}) {
+		for arch, props := range m.GetArchProperties(ctx, &customProps{}) {
 			if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
 				paths.SetValueForArch(arch.Name, android.BazelLabelForModuleSrc(ctx, archProps.Arch_paths))
 			}
diff --git a/build_kzip.bash b/build_kzip.bash
index a4659d4..a09335e 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -5,6 +5,7 @@
 # It is assumed that the current directory is the top of the source tree.
 # The following environment variables affect the result:
 #   BUILD_NUMBER          build number, used to generate unique ID (will use UUID if not set)
+#   SUPERPROJECT_SHA      superproject sha, used to generate unique id (will use BUILD_NUMBER if not set)
 #   DIST_DIR              where the resulting all.kzip will be placed
 #   KYTHE_KZIP_ENCODING   proto or json (proto is default)
 #   KYTHE_JAVA_SOURCE_BATCH_SIZE maximum number of the Java source files in a compilation unit
@@ -14,6 +15,7 @@
 #   XREF_CORPUS           source code repository URI, e.g., 'android.googlesource.com/platform/superproject'
 
 : ${BUILD_NUMBER:=$(uuidgen)}
+: ${SUPERPROJECT_SHA:=$BUILD_NUMBER}
 : ${KYTHE_JAVA_SOURCE_BATCH_SIZE:=500}
 : ${KYTHE_KZIP_ENCODING:=proto}
 : ${XREF_CORPUS:?should be set}
@@ -48,6 +50,6 @@
 
 # Pack
 # TODO(asmundak): this should be done by soong.
-declare -r allkzip="$BUILD_NUMBER.kzip"
+declare -r allkzip="$SUPERPROJECT_SHA.kzip"
 "$out/soong/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
 
diff --git a/cc/bp2build.go b/cc/bp2build.go
index d52b817..1433f6f 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -58,7 +58,7 @@
 		}
 	}
 
-	for _, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
+	for _, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
 		// arch specific linker props
 		if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
 			allDeps = append(allDeps, baseLinkerProps.Header_libs...)
@@ -198,7 +198,7 @@
 		copts.Value = append(copts.Value, includeFlag("."))
 	}
 
-	for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
+	for arch, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
 			// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
 			// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
@@ -215,7 +215,7 @@
 
 	// After going through all archs, delete the duplicate files in the arch
 	// values that are already in the base srcs.Value.
-	for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
+	for arch, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) {
 		if _, ok := props.(*BaseCompilerProperties); ok {
 			srcs.SetValueForArch(arch.Name, bazel.SubtractBazelLabelList(srcs.GetValueForArch(arch.Name), srcs.Value))
 		}
@@ -269,15 +269,13 @@
 			linkopts.Value = baseLinkerProps.Ldflags
 
 			if baseLinkerProps.Version_script != nil {
-				versionScript = bazel.LabelAttribute{
-					Value: android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script),
-				}
+				versionScript.Value = android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)
 			}
 			break
 		}
 	}
 
-	for arch, p := range module.GetArchProperties(&BaseLinkerProperties{}) {
+	for arch, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) {
 		if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok {
 			libs := baseLinkerProps.Header_libs
 			libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
@@ -286,6 +284,10 @@
 			libs = android.SortedUniqueStrings(libs)
 			deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
 			linkopts.SetValueForArch(arch.Name, baseLinkerProps.Ldflags)
+			if baseLinkerProps.Version_script != nil {
+				versionScript.SetValueForArch(arch.Name,
+					android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
+			}
 		}
 	}
 
@@ -343,7 +345,7 @@
 	includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...)
 	includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs)
 
-	for arch, props := range module.GetArchProperties(&FlagExporterProperties{}) {
+	for arch, props := range module.GetArchProperties(ctx, &FlagExporterProperties{}) {
 		if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
 			archIncludeDirs := flagExporterProperties.Export_system_include_dirs
 			archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...)
diff --git a/cc/builder.go b/cc/builder.go
index 0542015..29cde9d 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -143,7 +143,7 @@
 			}(),
 			Pool: darwinStripPool,
 		},
-		"args", "crossCompile")
+		"args")
 
 	// Rule to invoke `strip` (to discard symbols and data from object files) on darwin architecture.
 	darwinStrip = pctx.AndroidStaticRule("darwinStrip",
@@ -993,7 +993,6 @@
 func transformStrip(ctx android.ModuleContext, inputFile android.Path,
 	outputFile android.WritablePath, flags StripFlags) {
 
-	crossCompile := gccCmd(flags.Toolchain, "")
 	args := ""
 	if flags.StripAddGnuDebuglink {
 		args += " --add-gnu-debuglink"
@@ -1010,9 +1009,6 @@
 	if flags.StripKeepSymbolsAndDebugFrame {
 		args += " --keep-symbols-and-debug-frame"
 	}
-	if flags.StripUseGnuStrip {
-		args += " --use-gnu-strip"
-	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        strip,
@@ -1020,8 +1016,7 @@
 		Output:      outputFile,
 		Input:       inputFile,
 		Args: map[string]string{
-			"crossCompile": crossCompile,
-			"args":         args,
+			"args": args,
 		},
 	})
 }
diff --git a/cc/library.go b/cc/library.go
index 50d3f67..7b631fa 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -259,6 +259,14 @@
 		return
 	}
 
+	// For some cc_library modules, their static variants are ready to be
+	// converted, but not their shared variants. For these modules, delegate to
+	// the cc_library_static bp2build converter temporarily instead.
+	if android.GenerateCcLibraryStaticOnly(ctx) {
+		ccLibraryStaticBp2BuildInternal(ctx, m)
+		return
+	}
+
 	sharedAttrs := bp2BuildParseSharedProps(ctx, m)
 	staticAttrs := bp2BuildParseStaticProps(ctx, m)
 	compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
@@ -2205,6 +2213,28 @@
 	return module
 }
 
+func ccLibraryStaticBp2BuildInternal(ctx android.TopDownMutatorContext, module *Module) {
+	compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
+	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
+
+	attrs := &bazelCcLibraryStaticAttributes{
+		Copts:      compilerAttrs.copts,
+		Srcs:       compilerAttrs.srcs,
+		Deps:       linkerAttrs.deps,
+		Linkopts:   linkerAttrs.linkopts,
+		Linkstatic: true,
+		Includes:   exportedIncludes,
+	}
+
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_library_static",
+		Bzl_load_location: "//build/bazel/rules:cc_library_static.bzl",
+	}
+
+	ctx.CreateBazelTargetModule(BazelCcLibraryStaticFactory, module.Name(), props, attrs)
+}
+
 func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) {
 	module, ok := ctx.Module().(*Module)
 	if !ok {
@@ -2218,24 +2248,7 @@
 		return
 	}
 
-	compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
-	linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
-	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
-
-	attrs := &bazelCcLibraryStaticAttributes{
-		Copts:      compilerAttrs.copts,
-		Srcs:       compilerAttrs.srcs,
-		Deps:       linkerAttrs.deps,
-		Linkstatic: true,
-		Includes:   exportedIncludes,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_library_static",
-		Bzl_load_location: "//build/bazel/rules:cc_library_static.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(BazelCcLibraryStaticFactory, module.Name(), props, attrs)
+	ccLibraryStaticBp2BuildInternal(ctx, module)
 }
 
 func (m *bazelCcLibraryStatic) Name() string {
diff --git a/cc/test.go b/cc/test.go
index 9b77e45..d4c23d7 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -46,6 +46,14 @@
 
 	// If the test is a hostside(no device required) unittest that shall be run during presubmit check.
 	Unit_test *bool
+
+	// Add ShippingApiLevelModuleController to auto generated test config. If the device properties
+	// for the shipping api level is less than the test_min_api_level, skip this module.
+	Test_min_api_level *int64
+
+	// Add MinApiLevelModuleController with ro.vndk.version property. If ro.vndk.version has an
+	// integer value and the value is less than the test_min_vndk_version, skip this module.
+	Test_min_vndk_version *int64
 }
 
 type TestBinaryProperties struct {
@@ -89,6 +97,7 @@
 
 	// Add ShippingApiLevelModuleController to auto generated test config. If the device properties
 	// for the shipping api level is less than the test_min_api_level, skip this module.
+	// Deprecated (b/187258404). Use test_options.test_min_api_level instead.
 	Test_min_api_level *int64
 
 	// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
@@ -395,11 +404,22 @@
 	for _, tag := range test.Properties.Test_options.Test_suite_tag {
 		configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag})
 	}
-	if test.Properties.Test_min_api_level != nil {
+	if test.Properties.Test_options.Test_min_api_level != nil {
+		var options []tradefed.Option
+		options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Test_min_api_level), 10)})
+		configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
+	} else if test.Properties.Test_min_api_level != nil {
+		// TODO: (b/187258404) Remove test.Properties.Test_min_api_level
 		var options []tradefed.Option
 		options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10)})
 		configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
 	}
+	if test.Properties.Test_options.Test_min_vndk_version != nil {
+		var options []tradefed.Option
+		options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Test_min_vndk_version), 10)})
+		options = append(options, tradefed.Option{Name: "api-level-prop", Value: "ro.vndk.version"})
+		configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options})
+	}
 
 	test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
 		test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config, testInstallBase)
diff --git a/cmd/run_with_timeout/Android.bp b/cmd/run_with_timeout/Android.bp
new file mode 100644
index 0000000..76262cc
--- /dev/null
+++ b/cmd/run_with_timeout/Android.bp
@@ -0,0 +1,27 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+    name: "run_with_timeout",
+    srcs: [
+        "run_with_timeout.go",
+    ],
+    testSrcs: [
+        "run_with_timeout_test.go",
+    ],
+}
diff --git a/cmd/run_with_timeout/run_with_timeout.go b/cmd/run_with_timeout/run_with_timeout.go
new file mode 100644
index 0000000..f2caaab
--- /dev/null
+++ b/cmd/run_with_timeout/run_with_timeout.go
@@ -0,0 +1,143 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// run_with_timeout is a utility that can kill a wrapped command after a configurable timeout,
+// optionally running a command to collect debugging information first.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"sync"
+	"syscall"
+	"time"
+)
+
+var (
+	timeout      = flag.Duration("timeout", 0, "time after which to kill command (example: 60s)")
+	onTimeoutCmd = flag.String("on_timeout", "", "command to run with `PID=<pid> sh -c` after timeout.")
+)
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: %s [--timeout N] [--on_timeout CMD] -- command [args...]\n", os.Args[0])
+	flag.PrintDefaults()
+	fmt.Fprintln(os.Stderr, "run_with_timeout is a utility that can kill a wrapped command after a configurable timeout,")
+	fmt.Fprintln(os.Stderr, "optionally running a command to collect debugging information first.")
+
+	os.Exit(2)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	if flag.NArg() < 1 {
+		fmt.Fprintln(os.Stderr, "command is required")
+		usage()
+	}
+
+	err := runWithTimeout(flag.Arg(0), flag.Args()[1:], *timeout, *onTimeoutCmd,
+		os.Stdin, os.Stdout, os.Stderr)
+	if err != nil {
+		if exitErr, ok := err.(*exec.ExitError); ok {
+			fmt.Fprintln(os.Stderr, "process exited with error:", exitErr.Error())
+		} else {
+			fmt.Fprintln(os.Stderr, "error:", err.Error())
+		}
+		os.Exit(1)
+	}
+}
+
+// concurrentWriter wraps a writer to make it thread-safe to call Write.
+type concurrentWriter struct {
+	w io.Writer
+	sync.Mutex
+}
+
+// Write writes the data to the wrapped writer with a lock to allow for concurrent calls.
+func (c *concurrentWriter) Write(data []byte) (n int, err error) {
+	c.Lock()
+	defer c.Unlock()
+	if c.w == nil {
+		return 0, nil
+	}
+	return c.w.Write(data)
+}
+
+// Close ends the concurrentWriter, causing future calls to Write to be no-ops.  It does not close
+// the underlying writer.
+func (c *concurrentWriter) Close() {
+	c.Lock()
+	defer c.Unlock()
+	c.w = nil
+}
+
+func runWithTimeout(command string, args []string, timeout time.Duration, onTimeoutCmdStr string,
+	stdin io.Reader, stdout, stderr io.Writer) error {
+	cmd := exec.Command(command, args...)
+
+	// Wrap the writers in a locking writer so that cmd and onTimeoutCmd don't try to write to
+	// stdout or stderr concurrently.
+	concurrentStdout := &concurrentWriter{w: stdout}
+	concurrentStderr := &concurrentWriter{w: stderr}
+	defer concurrentStdout.Close()
+	defer concurrentStderr.Close()
+
+	cmd.Stdin, cmd.Stdout, cmd.Stderr = stdin, concurrentStdout, concurrentStderr
+	err := cmd.Start()
+	if err != nil {
+		return err
+	}
+
+	// waitCh will signal the subprocess exited.
+	waitCh := make(chan error)
+	go func() {
+		waitCh <- cmd.Wait()
+	}()
+
+	// timeoutCh will signal the subprocess timed out if timeout was set.
+	var timeoutCh <-chan time.Time = make(chan time.Time)
+	if timeout > 0 {
+		timeoutCh = time.After(timeout)
+	}
+
+	select {
+	case err := <-waitCh:
+		if exitErr, ok := err.(*exec.ExitError); ok {
+			return fmt.Errorf("process exited with error: %w", exitErr)
+		}
+		return err
+	case <-timeoutCh:
+		// Continue below.
+	}
+
+	// Process timed out before exiting.
+	defer cmd.Process.Signal(syscall.SIGKILL)
+
+	if onTimeoutCmdStr != "" {
+		onTimeoutCmd := exec.Command("sh", "-c", onTimeoutCmdStr)
+		onTimeoutCmd.Stdin, onTimeoutCmd.Stdout, onTimeoutCmd.Stderr = stdin, concurrentStdout, concurrentStderr
+		onTimeoutCmd.Env = append(os.Environ(), fmt.Sprintf("PID=%d", cmd.Process.Pid))
+		err := onTimeoutCmd.Run()
+		if err != nil {
+			return fmt.Errorf("on_timeout command %q exited with error: %w", onTimeoutCmdStr, err)
+		}
+	}
+
+	return fmt.Errorf("timed out after %s", timeout.String())
+}
diff --git a/cmd/run_with_timeout/run_with_timeout_test.go b/cmd/run_with_timeout/run_with_timeout_test.go
new file mode 100644
index 0000000..aebd336
--- /dev/null
+++ b/cmd/run_with_timeout/run_with_timeout_test.go
@@ -0,0 +1,94 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"bytes"
+	"io"
+	"testing"
+	"time"
+)
+
+func Test_runWithTimeout(t *testing.T) {
+	type args struct {
+		command      string
+		args         []string
+		timeout      time.Duration
+		onTimeoutCmd string
+		stdin        io.Reader
+	}
+	tests := []struct {
+		name       string
+		args       args
+		wantStdout string
+		wantStderr string
+		wantErr    bool
+	}{
+		{
+			name: "no timeout",
+			args: args{
+				command: "echo",
+				args:    []string{"foo"},
+			},
+			wantStdout: "foo\n",
+		},
+		{
+			name: "timeout not reached",
+			args: args{
+				command: "echo",
+				args:    []string{"foo"},
+				timeout: 1 * time.Second,
+			},
+			wantStdout: "foo\n",
+		},
+		{
+			name: "timed out",
+			args: args{
+				command: "sh",
+				args:    []string{"-c", "sleep 1 && echo foo"},
+				timeout: 1 * time.Millisecond,
+			},
+			wantErr: true,
+		},
+		{
+			name: "on_timeout command",
+			args: args{
+				command:      "sh",
+				args:         []string{"-c", "sleep 1 && echo foo"},
+				timeout:      1 * time.Millisecond,
+				onTimeoutCmd: "echo bar",
+			},
+			wantStdout: "bar\n",
+			wantErr:    true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			stdout := &bytes.Buffer{}
+			stderr := &bytes.Buffer{}
+			err := runWithTimeout(tt.args.command, tt.args.args, tt.args.timeout, tt.args.onTimeoutCmd, tt.args.stdin, stdout, stderr)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("runWithTimeout() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if gotStdout := stdout.String(); gotStdout != tt.wantStdout {
+				t.Errorf("runWithTimeout() gotStdout = %v, want %v", gotStdout, tt.wantStdout)
+			}
+			if gotStderr := stderr.String(); gotStderr != tt.wantStderr {
+				t.Errorf("runWithTimeout() gotStderr = %v, want %v", gotStderr, tt.wantStderr)
+			}
+		})
+	}
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 7397919..24492d4 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -49,7 +49,7 @@
 
 	ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX
 
-	SystemServerJars          []string                  // jars that form the system server
+	SystemServerJars          android.ConfiguredJarList // jars that form the system server
 	SystemServerApps          []string                  // apps that are loaded into system server
 	UpdatableSystemServerJars android.ConfiguredJarList // jars within apex that are loaded into system server
 	SpeedApps                 []string                  // apps that should be speed optimized
@@ -604,7 +604,7 @@
 		BootJars:                           android.EmptyConfiguredJarList(),
 		UpdatableBootJars:                  android.EmptyConfiguredJarList(),
 		ArtApexJars:                        android.EmptyConfiguredJarList(),
-		SystemServerJars:                   nil,
+		SystemServerJars:                   android.EmptyConfiguredJarList(),
 		SystemServerApps:                   nil,
 		UpdatableSystemServerJars:          android.EmptyConfiguredJarList(),
 		SpeedApps:                          nil,
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 628197c..c9a80f8 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -120,7 +120,7 @@
 	// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
 	// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
 	if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
-		!contains(global.SystemServerJars, module.Name) && !module.PreoptExtractedApk {
+		!global.SystemServerJars.ContainsJar(module.Name) && !module.PreoptExtractedApk {
 		return true
 	}
 
@@ -362,7 +362,7 @@
 
 	if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
 		var compilerFilter string
-		if contains(global.SystemServerJars, module.Name) {
+		if global.SystemServerJars.ContainsJar(module.Name) {
 			// Jars of system server, use the product option if it is set, speed otherwise.
 			if global.SystemServerCompilerFilter != "" {
 				compilerFilter = global.SystemServerCompilerFilter
@@ -416,7 +416,7 @@
 
 	// PRODUCT_SYSTEM_SERVER_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
 	// PRODUCT_OTHER_JAVA_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
-	if contains(global.SystemServerJars, module.Name) {
+	if global.SystemServerJars.ContainsJar(module.Name) {
 		if global.AlwaysSystemServerDebugInfo {
 			debugInfo = true
 		} else if global.NeverSystemServerDebugInfo {
@@ -524,7 +524,7 @@
 // from java subpackage to dexpreopt.
 func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string {
 	return ctx.Config().Once(nonUpdatableSystemServerJarsKey, func() interface{} {
-		return android.RemoveListFromList(global.SystemServerJars, global.UpdatableSystemServerJars.CopyOfJars())
+		return android.RemoveListFromList(global.SystemServerJars.CopyOfJars(), global.UpdatableSystemServerJars.CopyOfJars())
 	}).([]string)
 }
 
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index de9dc45..4dd383d 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -55,6 +55,8 @@
 	ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
 	ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
 	ctx.RegisterModuleType("prebuilt_rfsa", PrebuiltRFSAFactory)
+
+	ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
 }
 
 var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterPrebuiltEtcBuildComponents)
@@ -124,6 +126,7 @@
 
 type PrebuiltEtc struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 
 	properties       prebuiltEtcProperties
 	subdirProperties prebuiltSubdirProperties
@@ -139,6 +142,11 @@
 	additionalDependencies *android.Paths
 }
 
+type Defaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
 func (p *PrebuiltEtc) inRamdisk() bool {
 	return p.ModuleBase.InRamdisk() || p.ModuleBase.InstallInRamdisk()
 }
@@ -378,6 +386,25 @@
 	InitPrebuiltEtcModule(module, "etc")
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	android.InitDefaultableModule(module)
+	return module
+}
+
+func defaultsFactory() android.Module {
+	return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+	module := &Defaults{}
+
+	module.AddProperties(props...)
+	module.AddProperties(
+		&prebuiltEtcProperties{},
+		&prebuiltSubdirProperties{},
+	)
+
+	android.InitDefaultsModule(module)
+
 	return module
 }
 
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 8fe362a..6270b5b 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -32,9 +32,8 @@
 
 	android.RegisterSdkMemberType(&bootclasspathFragmentMemberType{
 		SdkMemberTypeBase: android.SdkMemberTypeBase{
-			PropertyName:         "bootclasspath_fragments",
-			SupportsSdk:          true,
-			TransitiveSdkMembers: true,
+			PropertyName: "bootclasspath_fragments",
+			SupportsSdk:  true,
 		},
 	})
 }
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index d497460..460cc3e 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -81,7 +81,7 @@
 	maxSdkVersion int32
 }
 
-func (c *ClasspathFragmentBase) generateAndroidBuildActions(ctx android.ModuleContext) {
+func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
 	outputFilename := ctx.ModuleName() + ".pb"
 	c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
 	c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
@@ -137,7 +137,7 @@
 	return
 }
 
-func (c *ClasspathFragmentBase) getAndroidMkEntries() []android.AndroidMkEntries {
+func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "ETC",
 		OutputFile: android.OptionalPathForPath(c.outputFilepath),
diff --git a/java/config/config.go b/java/config/config.go
index 30c6f91..273084c 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -69,6 +69,8 @@
 	pctx.StaticVariable("JavacHeapSize", "2048M")
 	pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
 	pctx.StaticVariable("DexFlags", "-JXX:OnError='cat hs_err_pid%p.log' -JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads")
+	// TODO(b/181095653): remove duplicated flags.
+	pctx.StaticVariable("DexJavaFlags", "-XX:OnError='cat hs_err_pid%p.log' -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads -Xmx2G")
 
 	pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
 		`-Xmaxerrs 9999999`,
diff --git a/java/dex.go b/java/dex.go
index 7898e9d..6bf0143 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -84,6 +84,11 @@
 	return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
 }
 
+func init() {
+	pctx.HostBinToolVariable("runWithTimeoutCmd", "run_with_timeout")
+	pctx.SourcePathVariable("jstackCmd", "${config.JavaToolchain}/jstack")
+}
+
 var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
@@ -117,7 +122,10 @@
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
 			`rm -f "$outDict" && rm -rf "${outUsageDir}" && ` +
 			`mkdir -p $$(dirname ${outUsage}) && ` +
-			`$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
+			// TODO(b/181095653): remove R8 timeout and go back to config.R8Cmd.
+			`${runWithTimeoutCmd} -timeout 30m -on_timeout '${jstackCmd} $$PID' -- ` +
+			`$r8Template${config.JavaCmd} ${config.DexJavaFlags} -cp ${config.R8Jar} ` +
+			`com.android.tools.r8.compatproguard.CompatProguard -injars $in --output $outDir ` +
 			`--no-data-resources ` +
 			`-printmapping ${outDict} ` +
 			`-printusage ${outUsage} ` +
@@ -128,9 +136,10 @@
 			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
 			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
 		CommandDeps: []string{
-			"${config.R8Cmd}",
+			"${config.R8Jar}",
 			"${config.SoongZipCmd}",
 			"${config.MergeZipsCmd}",
+			"${runWithTimeoutCmd}",
 		},
 	}, map[string]*remoteexec.REParams{
 		"$r8Template": &remoteexec.REParams{
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 0020a2d..3113eb3 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -150,7 +150,7 @@
 
 	global := dexpreopt.GetGlobalConfig(ctx)
 
-	isSystemServerJar := inList(ctx.ModuleName(), global.SystemServerJars)
+	isSystemServerJar := global.SystemServerJars.ContainsJar(ctx.ModuleName())
 
 	bootImage := defaultBootImageConfig(ctx)
 	if global.UseArtImage {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ce5155f..06326ac 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -790,7 +790,7 @@
 
 	rule.Build("bootJarsProfile", "profile boot jars")
 
-	image.profileInstalls = rule.Installs()
+	image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
 
 	return profile
 }
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 0ab6502..72b61e3 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -39,10 +39,9 @@
 		// 2) The jars that are from an updatable apex.
 		systemServerClasspathLocations = append(systemServerClasspathLocations,
 			global.UpdatableSystemServerJars.DevicePaths(ctx.Config(), android.Android)...)
-		if len(systemServerClasspathLocations) != len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len() {
-			panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
-				len(systemServerClasspathLocations),
-				len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len()))
+
+		if expectedLen := global.SystemServerJars.Len() + global.UpdatableSystemServerJars.Len(); expectedLen != len(systemServerClasspathLocations) {
+			panic(fmt.Errorf("wrong number of system server jars, got %d, expected %d", len(systemServerClasspathLocations), expectedLen))
 		}
 		return systemServerClasspathLocations
 	})
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 01c0f16..56e6247 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -193,23 +193,6 @@
 	return false
 }
 
-// Used by xsd_config
-type ApiFilePath interface {
-	ApiFilePath() android.Path
-}
-
-type ApiStubsSrcProvider interface {
-	StubsSrcJar() android.Path
-}
-
-// Provider of information about API stubs, used by java_sdk_library.
-type ApiStubsProvider interface {
-	ApiFilePath
-	RemovedApiFilePath() android.Path
-
-	ApiStubsSrcProvider
-}
-
 //
 // Javadoc
 //
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 90d9896..566f7e3 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -146,6 +146,23 @@
 	Write_sdk_values *bool
 }
 
+// Used by xsd_config
+type ApiFilePath interface {
+	ApiFilePath() android.Path
+}
+
+type ApiStubsSrcProvider interface {
+	StubsSrcJar() android.Path
+}
+
+// Provider of information about API stubs, used by java_sdk_library.
+type ApiStubsProvider interface {
+	ApiFilePath
+	RemovedApiFilePath() android.Path
+
+	ApiStubsSrcProvider
+}
+
 // droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
 // documented, filtering out hidden classes and methods.  The resulting .java files are intended to be passed to
 // a droiddoc module to generate documentation.
diff --git a/java/java.go b/java/java.go
index 7258dce..d74bf68 100644
--- a/java/java.go
+++ b/java/java.go
@@ -669,6 +669,7 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	android.InitApexModule(module)
+	android.InitSdkAwareModule(module)
 	InitJavaModule(module, android.HostSupported)
 	return module
 }
@@ -923,6 +924,7 @@
 	module.Module.dexpreopter.isTest = true
 	module.Module.linter.test = true
 
+	android.InitSdkAwareModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
@@ -1296,9 +1298,10 @@
 		if ai.ForPrebuiltApex {
 			if deapexerModule == nil {
 				// This should never happen as a variant for a prebuilt_apex is only created if the
-				// deapxer module has been configured to export the dex implementation jar for this module.
+				// deapexer module has been configured to export the dex implementation jar for this module.
 				ctx.ModuleErrorf("internal error: module %q does not depend on a `deapexer` module for prebuilt_apex %q",
 					j.Name(), ai.ApexVariationName)
+				return
 			}
 
 			// Get the path of the dex implementation jar from the `deapexer` module.
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 4cb02e3..1acb9f4 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -87,7 +87,7 @@
 		OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV),
 		Include:    "$(BUILD_PHONY_PACKAGE)",
 	})
-	entries = append(entries, b.classpathFragmentBase().getAndroidMkEntries()...)
+	entries = append(entries, b.classpathFragmentBase().androidMkEntries()...)
 	return
 }
 
@@ -167,7 +167,7 @@
 }
 
 func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	b.classpathFragmentBase().generateAndroidBuildActions(ctx)
+	b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx)
 
 	// Gather all the dependencies from the art, updatable and non-updatable boot jars.
 	artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag)
@@ -321,6 +321,8 @@
 			}
 
 			hiddenAPISupportingModules = append(hiddenAPISupportingModules, hiddenAPISupportingModule)
+		} else if _, ok := module.(*DexImport); ok {
+			// Ignore this for the purposes of hidden API processing
 		} else {
 			ctx.ModuleErrorf("module %s of type %s does not support hidden API processing", module, ctx.OtherModuleType(module))
 		}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index 2216b11..98d4614 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -133,6 +133,23 @@
 			"platform:bar",
 		})
 	})
+
+	t.Run("dex import", func(t *testing.T) {
+		result := android.GroupFixturePreparers(
+			preparer,
+			android.FixtureAddTextFile("deximport/Android.bp", `
+				dex_import {
+					name: "foo",
+					jars: ["a.jar"],
+				}
+			`),
+		).RunTest(t)
+
+		CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
+			"platform:prebuilt_foo",
+			"platform:bar",
+		})
+	})
 }
 
 func TestPlatformBootclasspath_Fragments(t *testing.T) {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index fcc105d..aff4539 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1756,6 +1756,7 @@
 
 	module.InitSdkLibraryProperties()
 	android.InitApexModule(module)
+	android.InitSdkAwareModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 
 	// Initialize the map from scope to scope specific properties.
@@ -2385,9 +2386,6 @@
 	// Scope to per scope properties.
 	Scopes map[*apiScope]scopeProperties
 
-	// Additional libraries that the exported stubs libraries depend upon.
-	Libs []string
-
 	// The Java stubs source files.
 	Stub_srcs []string
 
@@ -2439,7 +2437,6 @@
 		}
 	}
 
-	s.Libs = sdk.properties.Libs
 	s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
 	s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary())
 	s.Compile_dex = sdk.dexProperties.Compile_dex
@@ -2504,8 +2501,4 @@
 		}
 		propertySet.AddProperty("doctag_files", dests)
 	}
-
-	if len(s.Libs) > 0 {
-		propertySet.AddPropertyWithTag("libs", s.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(false))
-	}
 }
diff --git a/java/system_modules.go b/java/system_modules.go
index a09778c..d0dc74a 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -35,9 +35,8 @@
 	// Register sdk member types.
 	android.RegisterSdkMemberType(&systemModulesSdkMemberType{
 		android.SdkMemberTypeBase{
-			PropertyName:         "java_system_modules",
-			SupportsSdk:          true,
-			TransitiveSdkMembers: true,
+			PropertyName: "java_system_modules",
+			SupportsSdk:  true,
 		},
 	})
 }
@@ -115,6 +114,7 @@
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
+	android.InitSdkAwareModule(module)
 	return module
 }
 
diff --git a/python/python.go b/python/python.go
index 4444a70..0f5b788 100644
--- a/python/python.go
+++ b/python/python.go
@@ -444,11 +444,10 @@
 		var sharedLibs []string
 		// if embedded launcher is enabled, we need to collect the shared library depenendencies of the
 		// launcher
-		ctx.VisitDirectDeps(func(dep android.Module) {
-			if ctx.OtherModuleDependencyTag(dep) == launcherSharedLibTag {
-				sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
-			}
-		})
+		for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) {
+			sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep))
+		}
+
 		p.installer.setAndroidMkSharedLibs(sharedLibs)
 
 		// Install the par file from installSource
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index a4f985b..31555c0 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -191,12 +191,12 @@
 
 		sdk_snapshot {
 			name: "mysdk@1",
-			native_shared_libs: ["sdkmember_mysdk_1"],
+			native_shared_libs: ["sdkmember_mysdk@1"],
 		}
 
 		sdk_snapshot {
 			name: "mysdk@2",
-			native_shared_libs: ["sdkmember_mysdk_2"],
+			native_shared_libs: ["sdkmember_mysdk@2"],
 		}
 
 		cc_prebuilt_library_shared {
@@ -208,7 +208,7 @@
 		}
 
 		cc_prebuilt_library_shared {
-			name: "sdkmember_mysdk_1",
+			name: "sdkmember_mysdk@1",
 			sdk_member_name: "sdkmember",
 			srcs: ["libfoo.so"],
 			system_shared_libs: [],
@@ -221,7 +221,7 @@
 		}
 
 		cc_prebuilt_library_shared {
-			name: "sdkmember_mysdk_2",
+			name: "sdkmember_mysdk@2",
 			sdk_member_name: "sdkmember",
 			srcs: ["libfoo.so"],
 			system_shared_libs: [],
@@ -272,8 +272,8 @@
 		}
 	`)
 
-	sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_apex10000_mysdk_1").Rule("toc").Output
-	sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_apex10000_mysdk_2").Rule("toc").Output
+	sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk@1", "android_arm64_armv8-a_shared_apex10000_mysdk_1").Rule("toc").Output
+	sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk@2", "android_arm64_armv8-a_shared_apex10000_mysdk_2").Rule("toc").Output
 
 	cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_1")
 	cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_2")
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 6016981..dc58d93 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -83,12 +83,12 @@
 
 		sdk_snapshot {
 			name: "mysdk@1",
-			java_header_libs: ["sdkmember_mysdk_1"],
+			java_header_libs: ["sdkmember_mysdk@1"],
 		}
 
 		sdk_snapshot {
 			name: "mysdk@2",
-			java_header_libs: ["sdkmember_mysdk_2"],
+			java_header_libs: ["sdkmember_mysdk@2"],
 		}
 
 		java_library {
@@ -100,13 +100,13 @@
 		}
 
 		java_import {
-			name: "sdkmember_mysdk_1",
+			name: "sdkmember_mysdk@1",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
 		}
 
 		java_import {
-			name: "sdkmember_mysdk_2",
+			name: "sdkmember_mysdk@2",
 			sdk_member_name: "sdkmember",
 			host_supported: true,
 		}
@@ -144,8 +144,8 @@
 		}
 	`)
 
-	sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output
-	sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output
+	sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk@1", "android_common").Rule("combineJar").Output
+	sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk@2", "android_common").Rule("combineJar").Output
 
 	javalibForMyApex := result.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_1")
 	javalibForMyApex2 := result.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_2")
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 95a4930..624c0fa 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -307,8 +307,8 @@
 
 		// Generate the snapshot from the member info.
 		p := s.buildSnapshot(ctx, sdkVariants)
-		s.snapshotFile = android.OptionalPathForPath(p)
-		ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), s.Name()+"-current.zip", p)
+		zip := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), p.Base(), p)
+		s.snapshotFile = android.OptionalPathForPath(zip)
 	}
 }
 
@@ -444,7 +444,7 @@
 // built with libfoo.mysdk.11 and libfoo.mysdk.12, respectively depending on which sdk they are
 // using.
 func memberInterVersionMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
+	if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() && m.IsVersioned() {
 		if !m.ContainingSdk().Unversioned() {
 			memberName := m.MemberName()
 			tag := sdkMemberVersionedDepTag{member: memberName, version: m.ContainingSdk().Version}
@@ -483,7 +483,7 @@
 // Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
 // versioned module is used instead of the un-versioned (in-development) module libfoo
 func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
-	if versionedSdkMember, ok := mctx.Module().(android.SdkAware); ok && versionedSdkMember.IsInAnySdk() {
+	if versionedSdkMember, ok := mctx.Module().(android.SdkAware); ok && versionedSdkMember.IsInAnySdk() && versionedSdkMember.IsVersioned() {
 		if sdk := versionedSdkMember.ContainingSdk(); !sdk.Unversioned() {
 			// Only replace dependencies to <sdkmember> with <sdkmember@required-version>
 			// if the depending module requires it. e.g.
@@ -499,7 +499,7 @@
 			// TODO(b/183204176): Remove this after fixing.
 			defer func() {
 				if r := recover(); r != nil {
-					mctx.ModuleErrorf("%s", r)
+					mctx.ModuleErrorf("sdkDepsReplaceMutator %s", r)
 				}
 			}()
 
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index b7da95c..e9129e0 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -464,3 +464,65 @@
     "struct-0" has value "should-be-but-is-not-common0"
     "struct-1" has value "should-be-but-is-not-common1"`, err)
 }
+
+// Ensure that sdk snapshot related environment variables work correctly.
+func TestSnapshot_EnvConfiguration(t *testing.T) {
+	bp := `
+		sdk {
+			name: "mysdk",
+			java_header_libs: ["myjavalib"],
+		}
+
+		java_library {
+			name: "myjavalib",
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+			host_supported: true,
+		}
+	`
+	preparer := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		android.FixtureWithRootAndroidBp(bp),
+	)
+
+	checkZipFile := func(t *testing.T, result *android.TestResult, expected string) {
+		zipRule := result.ModuleForTests("mysdk", "common_os").Rule("SnapshotZipFiles")
+		android.AssertStringEquals(t, "snapshot zip file", expected, zipRule.Output.String())
+	}
+
+	t.Run("no env variables", func(t *testing.T) {
+		result := preparer.RunTest(t)
+
+		checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
+
+		CheckSnapshot(t, result, "mysdk", "",
+			checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+    name: "myjavalib",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:platform"],
+    jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    visibility: ["//visibility:public"],
+    java_header_libs: ["mysdk_myjavalib@current"],
+}
+			`),
+		)
+	})
+}
diff --git a/sdk/update.go b/sdk/update.go
index 72b02e8..457cbd9 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -133,9 +133,9 @@
 			export := memberTag.ExportMember()
 			s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{s, memberType, child.(android.SdkAware), export})
 
-			// If the member type supports transitive sdk members then recurse down into
-			// its dependencies, otherwise exit traversal.
-			return memberType.HasTransitiveSdkMembers()
+			// Recurse down into the member's dependencies as it may have dependencies that need to be
+			// automatically added to the sdk.
+			return true
 		}
 
 		return false