Merge "Make lint HTML output deterministic"
diff --git a/Android.bp b/Android.bp
index 9d5b07d..8f7f3e2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,101 +47,6 @@
 //
 
 toolchain_library {
-    name: "libatomic",
-    defaults: ["linux_bionic_supported"],
-    vendor_available: true,
-    product_available: true,
-    ramdisk_available: true,
-    vendor_ramdisk_available: true,
-    recovery_available: true,
-    native_bridge_supported: true,
-
-    arch: {
-        arm: {
-            src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/arm-linux-androideabi/lib/libatomic.a",
-        },
-        arm64: {
-            src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/aarch64-linux-android/lib64/libatomic.a",
-        },
-        x86: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/x86_64-linux-android/lib/libatomic.a",
-        },
-        x86_64: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/x86_64-linux-android/lib64/libatomic.a",
-        },
-    },
-}
-
-toolchain_library {
-    name: "libgcc",
-    defaults: ["linux_bionic_supported"],
-    vendor_available: true,
-    product_available: true,
-    recovery_available: true,
-    native_bridge_supported: true,
-    apex_available: [
-        "//apex_available:platform",
-        "//apex_available:anyapex",
-    ],
-
-    arch: {
-        arm: {
-            src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
-        },
-        arm64: {
-            src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
-        },
-        x86: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
-        },
-        x86_64: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
-        },
-    },
-}
-
-toolchain_library {
-    name: "libgcc_stripped",
-    defaults: ["linux_bionic_supported"],
-    vendor_available: true,
-    product_available: true,
-    ramdisk_available: true,
-    vendor_ramdisk_available: true,
-    recovery_available: true,
-    native_bridge_supported: true,
-    sdk_version: "current",
-
-    arch: {
-        arm: {
-            src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
-            repack_objects_to_keep: [],
-            enabled: false,
-        },
-        arm64: {
-            src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
-            repack_objects_to_keep: [
-                "unwind-dw2.o",
-                "unwind-dw2-fde-dip.o",
-            ],
-        },
-        x86: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
-            repack_objects_to_keep: [
-                "unwind-dw2.o",
-                "unwind-dw2-fde-dip.o",
-            ],
-        },
-        x86_64: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
-            repack_objects_to_keep: [
-                "unwind-dw2.o",
-                "unwind-dw2-fde-dip.o",
-            ],
-        },
-    },
-}
-
-toolchain_library {
     name: "libwinpthread",
     host_supported: true,
     enabled: false,
@@ -159,26 +64,6 @@
     notice: ":mingw-libwinpthread-notice",
 }
 
-toolchain_library {
-    name: "libgcov",
-    defaults: ["linux_bionic_supported"],
-
-    arch: {
-        arm: {
-            src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcov.a",
-        },
-        arm64: {
-            src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcov.a",
-        },
-        x86: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcov.a",
-        },
-        x86_64: {
-            src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcov.a",
-        },
-    },
-}
-
 kernel_headers {
     name: "device_kernel_headers",
     vendor: true,
diff --git a/android/bazel.go b/android/bazel.go
index a08da0e..b2170be 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -174,8 +174,6 @@
 		"liblinker_debuggerd_stub",      // ruperts@, cc_library_static, depends on //system/libbase
 		"libbionic_tests_headers_posix", // ruperts@, cc_library_static
 		"libc_dns",                      // ruperts@, cc_library_static
-		"note_memtag_heap_async",        // cparsons@, cc_library_static
-		"note_memtag_heap_sync",         // cparsons@, cc_library_static
 	}
 
 	// Used for quicker lookups
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 04b70d6..5b9d3bf 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -34,13 +34,6 @@
 	"android/soong/shared"
 )
 
-type CqueryRequestType int
-
-const (
-	getAllFiles CqueryRequestType = iota
-	getAllFilesAndCcObjectFiles
-)
-
 // Map key to describe bazel cquery requests.
 type cqueryKey struct {
 	label       string
@@ -481,7 +474,7 @@
     return id_string + ">>" + %s(target)
 `
 
-	for _, requestType := range cquery.RequestTypes {
+	for requestType, _ := range requestTypeToCqueryIdEntries {
 		labelMapName := requestType.Name() + "_Labels"
 		functionName := requestType.Name() + "_Fn"
 		labelRegistrationMapSection += fmt.Sprintf(mapDeclarationFormatString,
@@ -688,7 +681,7 @@
 	// Register bazel-owned build statements (obtained from the aquery invocation).
 	for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
 		if len(buildStatement.Command) < 1 {
-			panic(fmt.Sprintf("unhandled build statement: %s", buildStatement))
+			panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
 		}
 		rule := NewRuleBuilder(pctx, ctx)
 		cmd := rule.Command()
diff --git a/android/sdk_version.go b/android/sdk_version.go
index ce22b5f..5fdaa91 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -75,58 +75,15 @@
 	}
 }
 
-// SdkVersion represents a specific version number of an SDK spec of a particular kind
-type SdkVersion int
-
-const (
-	// special version number for a not-yet-frozen SDK
-	SdkVersionCurrent SdkVersion = SdkVersion(FutureApiLevelInt)
-	// special version number to be used for SDK specs where version number doesn't
-	// make sense, e.g. "none", "", etc.
-	SdkVersionNone SdkVersion = SdkVersion(0)
-)
-
-// IsCurrent checks if the SdkVersion refers to the not-yet-published version of an SdkKind
-func (v SdkVersion) IsCurrent() bool {
-	return v == SdkVersionCurrent
-}
-
-// IsNumbered checks if the SdkVersion refers to the published (a.k.a numbered) version of an SdkKind
-func (v SdkVersion) IsNumbered() bool {
-	return !v.IsCurrent() && v != SdkVersionNone
-}
-
-// String returns the string representation of this SdkVersion.
-func (v SdkVersion) String() string {
-	if v.IsCurrent() {
-		return "current"
-	} else if v.IsNumbered() {
-		return strconv.Itoa(int(v))
-	}
-	return "(no version)"
-}
-
-func (v SdkVersion) ApiLevel(ctx EarlyModuleContext) ApiLevel {
-	return ApiLevelOrPanic(ctx, v.String())
-}
-
-// AsNumberString directly converts the numeric value of this sdk version as a string.
-// When isNumbered() is true, this method is the same as String(). However, for SdkVersionCurrent
-// and SdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"),
-// respectively.
-func (v SdkVersion) AsNumberString() string {
-	return strconv.Itoa(int(v))
-}
-
 // SdkSpec represents the kind and the version of an SDK for a module to build against
 type SdkSpec struct {
-	Kind    SdkKind
-	Version SdkVersion
-	Raw     string
+	Kind     SdkKind
+	ApiLevel ApiLevel
+	Raw      string
 }
 
 func (s SdkSpec) String() string {
-	return fmt.Sprintf("%s_%s", s.Kind, s.Version)
+	return fmt.Sprintf("%s_%s", s.Kind, s.ApiLevel)
 }
 
 // Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the
@@ -177,10 +134,10 @@
 	}
 
 	if s.Kind == SdkPublic || s.Kind == SdkSystem {
-		if s.Version.IsCurrent() {
+		if s.ApiLevel.IsCurrent() {
 			if i, err := strconv.Atoi(currentSdkVersion); err == nil {
-				version := SdkVersion(i)
-				return SdkSpec{s.Kind, version, s.Raw}
+				apiLevel := uncheckedFinalApiLevel(i)
+				return SdkSpec{s.Kind, apiLevel, s.Raw}
 			}
 			panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
 		}
@@ -190,10 +147,10 @@
 
 // UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context.
 func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool {
-	if s.Version.IsCurrent() {
+	if s.ApiLevel.IsCurrent() {
 		// "current" can be built from source and be from prebuilt SDK
 		return ctx.Config().AlwaysUsePrebuiltSdks()
-	} else if s.Version.IsNumbered() {
+	} else if !s.ApiLevel.IsPreview() {
 		// validation check
 		if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule {
 			panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind))
@@ -206,50 +163,60 @@
 	return false
 }
 
-// EffectiveVersion converts an SdkSpec into the concrete SdkVersion that the module
-// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
-// it returns FutureApiLevel(10000).
-func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (SdkVersion, error) {
+// EffectiveVersion converts an SdkSpec into the concrete ApiLevel that the module should use. For
+// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns
+// FutureApiLevel(10000).
+func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) {
 	if !s.Valid() {
-		return s.Version, fmt.Errorf("invalid sdk version %q", s.Raw)
+		return s.ApiLevel, fmt.Errorf("invalid sdk version %q", s.Raw)
 	}
 
 	if ctx.DeviceSpecific() || ctx.SocSpecific() {
 		s = s.ForVendorPartition(ctx)
 	}
-	if s.Version.IsNumbered() {
-		return s.Version, nil
+	if !s.ApiLevel.IsPreview() {
+		return s.ApiLevel, nil
 	}
-	return SdkVersion(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()), nil
+	ret := ctx.Config().DefaultAppTargetSdk(ctx)
+	if ret.IsPreview() {
+		return FutureApiLevel, nil
+	}
+	return ret, nil
 }
 
 // EffectiveVersionString converts an SdkSpec into the concrete version string that the module
 // should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
 // it returns the codename (P, Q, R, etc.)
 func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) {
-	ver, err := s.EffectiveVersion(ctx)
-	if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt() {
-		return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
+	if !s.Valid() {
+		return s.ApiLevel.String(), fmt.Errorf("invalid sdk version %q", s.Raw)
 	}
-	return ver.String(), err
+
+	if ctx.DeviceSpecific() || ctx.SocSpecific() {
+		s = s.ForVendorPartition(ctx)
+	}
+	if !s.ApiLevel.IsPreview() {
+		return s.ApiLevel.String(), nil
+	}
+	return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
 }
 
 func SdkSpecFrom(str string) SdkSpec {
 	switch str {
 	// special cases first
 	case "":
-		return SdkSpec{SdkPrivate, SdkVersionNone, str}
+		return SdkSpec{SdkPrivate, NoneApiLevel, str}
 	case "none":
-		return SdkSpec{SdkNone, SdkVersionNone, str}
+		return SdkSpec{SdkNone, NoneApiLevel, str}
 	case "core_platform":
-		return SdkSpec{SdkCorePlatform, SdkVersionNone, str}
+		return SdkSpec{SdkCorePlatform, NoneApiLevel, str}
 	default:
 		// the syntax is [kind_]version
 		sep := strings.LastIndex(str, "_")
 
 		var kindString string
 		if sep == 0 {
-			return SdkSpec{SdkInvalid, SdkVersionNone, str}
+			return SdkSpec{SdkInvalid, NoneApiLevel, str}
 		} else if sep == -1 {
 			kindString = ""
 		} else {
@@ -272,19 +239,19 @@
 		case "system_server":
 			kind = SdkSystemServer
 		default:
-			return SdkSpec{SdkInvalid, SdkVersionNone, str}
+			return SdkSpec{SdkInvalid, NoneApiLevel, str}
 		}
 
-		var version SdkVersion
+		var apiLevel ApiLevel
 		if versionString == "current" {
-			version = SdkVersionCurrent
+			apiLevel = FutureApiLevel
 		} else if i, err := strconv.Atoi(versionString); err == nil {
-			version = SdkVersion(i)
+			apiLevel = uncheckedFinalApiLevel(i)
 		} else {
-			return SdkSpec{SdkInvalid, SdkVersionNone, str}
+			return SdkSpec{SdkInvalid, apiLevel, str}
 		}
 
-		return SdkSpec{kind, version, str}
+		return SdkSpec{kind, apiLevel, str}
 	}
 }
 
@@ -292,7 +259,7 @@
 	// Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
 	// Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
 	// sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
-	if s.Kind != SdkSystem || !s.Version.IsNumbered() {
+	if s.Kind != SdkSystem || s.ApiLevel.IsPreview() {
 		return true
 	}
 	allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
@@ -302,7 +269,7 @@
 			allowedVersions = systemSdkVersions
 		}
 	}
-	if len(allowedVersions) > 0 && !InList(s.Version.String(), allowedVersions) {
+	if len(allowedVersions) > 0 && !InList(s.ApiLevel.String(), allowedVersions) {
 		ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
 			s.Raw, allowedVersions)
 		return false
diff --git a/apex/apex.go b/apex/apex.go
index 9d06e1c..bad382a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1049,6 +1049,16 @@
 	if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
 		apexBundleName := mctx.ModuleName()
 		mctx.CreateVariations(apexBundleName)
+		if strings.HasPrefix(apexBundleName, "com.android.art") {
+			// Create an alias from the platform variant. This is done to make
+			// test_for dependencies work for modules that are split by the APEX
+			// mutator, since test_for dependencies always go to the platform variant.
+			// This doesn't happen for normal APEXes that are disjunct, so only do
+			// this for the overlapping ART APEXes.
+			// TODO(b/183882457): Remove this if the test_for functionality is
+			// refactored to depend on the proper APEX variants instead of platform.
+			mctx.CreateAliasVariation("", apexBundleName)
+		}
 	} else if o, ok := mctx.Module().(*OverrideApex); ok {
 		apexBundleName := o.GetOverriddenModuleName()
 		if apexBundleName == "" {
@@ -1056,6 +1066,10 @@
 			return
 		}
 		mctx.CreateVariations(apexBundleName)
+		if strings.HasPrefix(apexBundleName, "com.android.art") {
+			// TODO(b/183882457): See note for CreateAliasVariation above.
+			mctx.CreateAliasVariation("", apexBundleName)
+		}
 	}
 }
 
@@ -2925,9 +2939,7 @@
 		"com.google.android.material_material",
 		"com.google.android.material_material-nodeps",
 
-		"libatomic",
 		"libclang_rt",
-		"libgcc_stripped",
 		"libprofile-clang-extras",
 		"libprofile-clang-extras_ndk",
 		"libprofile-extras",
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 98b40fd..87d551b 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -216,7 +216,7 @@
 		variables.Platform_sdk_codename = proptools.StringPtr("Q")
 		variables.Platform_sdk_final = proptools.BoolPtr(false)
 		variables.Platform_version_active_codenames = []string{"Q"}
-		variables.Platform_vndk_version = proptools.StringPtr("VER")
+		variables.Platform_vndk_version = proptools.StringPtr("29")
 	}),
 )
 
@@ -1366,13 +1366,13 @@
 			ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 			ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
 
-			mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"]
-			ensureContains(t, mylibLdFlags, "libbar/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
+			mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.29_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"]
+			ensureContains(t, mylibLdFlags, "libbar/android_vendor.29_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
 			for _, ver := range tc.shouldNotLink {
-				ensureNotContains(t, mylibLdFlags, "libbar/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
+				ensureNotContains(t, mylibLdFlags, "libbar/android_vendor.29_arm64_armv8-a_shared_"+ver+"/libbar.so")
 			}
 
-			mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
+			mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.29_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
 			ver := tc.shouldLink
 			if tc.shouldLink == "current" {
 				ver = strconv.Itoa(android.FutureApiLevelInt)
@@ -2411,8 +2411,8 @@
 	inputsString := strings.Join(inputsList, " ")
 
 	// ensure that the apex includes vendor variants of the direct and indirect deps
-	ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib.so")
-	ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib2.so")
+	ensureContains(t, inputsString, "android_vendor.29_arm64_armv8-a_shared_apex10000/mylib.so")
+	ensureContains(t, inputsString, "android_vendor.29_arm64_armv8-a_shared_apex10000/mylib2.so")
 
 	// ensure that the apex does not include core variants
 	ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib.so")
@@ -2558,7 +2558,7 @@
 		}
 	`)
 
-	vendorVariant := "android_vendor.VER_arm64_armv8-a"
+	vendorVariant := "android_vendor.29_arm64_armv8-a"
 
 	ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld")
 	libs := names(ldRule.Args["libFlags"])
@@ -2607,7 +2607,7 @@
 	)
 
 	cflags := strings.Fields(
-		ctx.ModuleForTests("foo", "android_product.VER_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"])
+		ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"])
 	ensureListContains(t, cflags, "-D__ANDROID_VNDK__")
 	ensureListContains(t, cflags, "-D__ANDROID_APEX__")
 	ensureListContains(t, cflags, "-D__ANDROID_PRODUCT__")
@@ -3305,11 +3305,11 @@
 		"lib64/libvndk.so",
 		"lib64/libvndksp.so",
 		"lib64/libc++.so",
-		"etc/llndk.libraries.VER.txt",
-		"etc/vndkcore.libraries.VER.txt",
-		"etc/vndksp.libraries.VER.txt",
-		"etc/vndkprivate.libraries.VER.txt",
-		"etc/vndkproduct.libraries.VER.txt",
+		"etc/llndk.libraries.29.txt",
+		"etc/vndkcore.libraries.29.txt",
+		"etc/vndksp.libraries.29.txt",
+		"etc/vndkprivate.libraries.29.txt",
+		"etc/vndkproduct.libraries.29.txt",
 	})
 }
 
@@ -3495,7 +3495,7 @@
 		}
 	}
 
-	assertApexName("com.android.vndk.vVER", "com.android.vndk.current")
+	assertApexName("com.android.vndk.v29", "com.android.vndk.current")
 	assertApexName("com.android.vndk.v28", "com.android.vndk.v28")
 }
 
@@ -6947,6 +6947,56 @@
 	ensureLinkedLibIs("myprivlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
 }
 
+func TestTestForForLibInOtherApex(t *testing.T) {
+	// This case is only allowed for known overlapping APEXes, i.e. the ART APEXes.
+	_ = testApex(t, `
+		apex {
+			name: "com.android.art",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+			updatable: false,
+		}
+
+		apex {
+			name: "com.android.art.debug",
+			key: "myapex.key",
+			native_shared_libs: ["mylib", "mytestlib"],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			stubs: {
+				versions: ["1"],
+			},
+			apex_available: ["com.android.art", "com.android.art.debug"],
+		}
+
+		cc_library {
+			name: "mytestlib",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			shared_libs: ["mylib"],
+			stl: "none",
+			apex_available: ["com.android.art.debug"],
+			test_for: ["com.android.art"],
+		}
+	`,
+		android.MockFS{
+			"system/sepolicy/apex/com.android.art-file_contexts":       nil,
+			"system/sepolicy/apex/com.android.art.debug-file_contexts": nil,
+		}.AddToFixture())
+}
+
 // TODO(jungjw): Move this to proptools
 func intPtr(i int) *int {
 	return &i
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 015283d..d580e5a 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -59,11 +59,11 @@
 		"lib/libc++.so",
 		"lib64/libvndksp.so",
 		"lib64/libc++.so",
-		"etc/llndk.libraries.VER.txt",
-		"etc/vndkcore.libraries.VER.txt",
-		"etc/vndksp.libraries.VER.txt",
-		"etc/vndkprivate.libraries.VER.txt",
-		"etc/vndkproduct.libraries.VER.txt",
+		"etc/llndk.libraries.29.txt",
+		"etc/vndkcore.libraries.29.txt",
+		"etc/vndksp.libraries.29.txt",
+		"etc/vndkprivate.libraries.29.txt",
+		"etc/vndkproduct.libraries.29.txt",
 	})
 }
 
@@ -111,7 +111,7 @@
 
 		// VNDK APEX doesn't create apex variant
 		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
 	})
 
 	t.Run("VNDK APEX gathers only vendor variants even if product variants are available", func(t *testing.T) {
@@ -123,7 +123,7 @@
 		)
 
 		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
 	})
 
 	t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
@@ -135,9 +135,9 @@
 		)
 
 		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared/libfoo.so")
+		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
 
 		files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.VER_arm_armv7-a-neon_shared_cov/libfoo.so")
+		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared_cov/libfoo.so")
 	})
 }
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index bd1ece1..affb5ce 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -14,11 +14,6 @@
 	CcObjectFiles []string
 }
 
-var RequestTypes []RequestType = []RequestType{
-	GetOutputFiles,
-	GetOutputFilesAndCcObjectFiles,
-}
-
 type RequestType interface {
 	// Name returns a string name for this request type. Such request type names must be unique,
 	// and must only consist of alphanumeric characters.
@@ -83,7 +78,17 @@
 	splitString := strings.Split(rawString, "|")
 	outputFilesString := splitString[0]
 	ccObjectsString := splitString[1]
-	outputFiles = strings.Split(outputFilesString, ", ")
-	ccObjects = strings.Split(ccObjectsString, ", ")
+	outputFiles = splitOrEmpty(outputFilesString, ", ")
+	ccObjects = splitOrEmpty(ccObjectsString, ", ")
 	return GetOutputFilesAndCcObjectFiles_Result{outputFiles, ccObjects}
 }
+
+// splitOrEmpty is a modification of strings.Split() that returns an empty list
+// if the given string is empty.
+func splitOrEmpty(s string, sep string) []string {
+	if len(s) < 1 {
+		return []string{}
+	} else {
+		return strings.Split(s, sep)
+	}
+}
diff --git a/bazel/properties.go b/bazel/properties.go
index 250fea4..2440ca1 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -96,21 +96,10 @@
 )
 
 var (
-	// This is the list of architectures with a Bazel config_setting and
-	// constraint value equivalent. is actually android.ArchTypeList, but the
-	// android package depends on the bazel package, so a cyclic dependency
-	// prevents using that here.
-	selectableArchs = []string{ARCH_X86, ARCH_X86_64, ARCH_ARM, ARCH_ARM64}
-
-	// Likewise, this is the list of target operating systems.
-	selectableTargetOs = []string{
-		OS_ANDROID,
-		OS_DARWIN,
-		OS_FUCHSIA,
-		OS_LINUX,
-		OS_LINUX_BIONIC,
-		OS_WINDOWS,
-	}
+	// These are the list of OSes and architectures with a Bazel config_setting
+	// and constraint value equivalent. These exist in arch.go, but the android
+	// package depends on the bazel package, so a cyclic dependency prevents
+	// using those variables here.
 
 	// A map of architectures to the Bazel label of the constraint_value
 	// for the @platforms//cpu:cpu constraint_setting
@@ -133,6 +122,10 @@
 	}
 )
 
+type Attribute interface {
+	HasConfigurableValues() bool
+}
+
 // Arch-specific label_list typed Bazel attribute values. This should correspond
 // to the types of architectures supported for compilation in arch.go.
 type labelListArchValues struct {
@@ -176,14 +169,14 @@
 
 // HasArchSpecificValues returns true if the attribute contains
 // architecture-specific label_list values.
-func (attrs *LabelListAttribute) HasConfigurableValues() bool {
-	for _, arch := range selectableArchs {
+func (attrs LabelListAttribute) HasConfigurableValues() bool {
+	for arch := range PlatformArchMap {
 		if len(attrs.GetValueForArch(arch).Includes) > 0 {
 			return true
 		}
 	}
 
-	for _, os := range selectableTargetOs {
+	for os := range PlatformOsMap {
 		if len(attrs.GetValueForOS(os).Includes) > 0 {
 			return true
 		}
@@ -253,8 +246,15 @@
 	// The base value of the string list attribute.
 	Value []string
 
-	// Optional additive set of list values to the base value.
+	// The arch-specific attribute string list values. Optional. If used, these
+	// are generated in a select statement and appended to the non-arch specific
+	// label list Value.
 	ArchValues stringListArchValues
+
+	// The os-specific attribute string list values. Optional. If used, these
+	// are generated in a select statement and appended to the non-os specific
+	// label list Value.
+	OsValues stringListOsValues
 }
 
 // Arch-specific string_list typed Bazel attribute values. This should correspond
@@ -267,14 +267,29 @@
 	Common []string
 }
 
+type stringListOsValues struct {
+	Android     []string
+	Darwin      []string
+	Fuchsia     []string
+	Linux       []string
+	LinuxBionic []string
+	Windows     []string
+}
+
 // HasConfigurableValues returns true if the attribute contains
 // architecture-specific string_list values.
-func (attrs *StringListAttribute) HasConfigurableValues() bool {
-	for _, arch := range selectableArchs {
+func (attrs StringListAttribute) HasConfigurableValues() bool {
+	for arch := range PlatformArchMap {
 		if len(attrs.GetValueForArch(arch)) > 0 {
 			return true
 		}
 	}
+
+	for os := range PlatformOsMap {
+		if len(attrs.GetValueForOS(os)) > 0 {
+			return true
+		}
+	}
 	return false
 }
 
@@ -305,6 +320,35 @@
 	*v = value
 }
 
+func (attrs *StringListAttribute) osValuePtrs() map[string]*[]string {
+	return map[string]*[]string{
+		OS_ANDROID:      &attrs.OsValues.Android,
+		OS_DARWIN:       &attrs.OsValues.Darwin,
+		OS_FUCHSIA:      &attrs.OsValues.Fuchsia,
+		OS_LINUX:        &attrs.OsValues.Linux,
+		OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
+		OS_WINDOWS:      &attrs.OsValues.Windows,
+	}
+}
+
+// GetValueForOS returns the string_list attribute value for an OS target.
+func (attrs *StringListAttribute) GetValueForOS(os string) []string {
+	var v *[]string
+	if v = attrs.osValuePtrs()[os]; v == nil {
+		panic(fmt.Errorf("Unknown os: %s", os))
+	}
+	return *v
+}
+
+// SetValueForArch sets the string_list attribute value for an OS target.
+func (attrs *StringListAttribute) SetValueForOS(os string, value []string) {
+	var v *[]string
+	if v = attrs.osValuePtrs()[os]; v == nil {
+		panic(fmt.Errorf("Unknown os: %s", os))
+	}
+	*v = value
+}
+
 // TryVariableSubstitution, replace string substitution formatting within each string in slice with
 // Starlark string.format compatible tag for productVariable.
 func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
diff --git a/bootstrap_test.sh b/bootstrap_test.sh
index 6c5338a..9d87697 100755
--- a/bootstrap_test.sh
+++ b/bootstrap_test.sh
@@ -402,6 +402,14 @@
   fi
 }
 
+function test_dump_json_module_graph() {
+  setup
+  SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong
+  if [[ ! -r "$MOCK_TOP/modules.json" ]]; then
+    fail "JSON file was not created"
+  fi
+}
+
 test_bazel_smoke
 test_smoke
 test_null_build
@@ -413,3 +421,4 @@
 test_delete_android_bp
 test_add_file_to_soong_build
 test_soong_build_rerun_iff_environment_changes
+test_dump_json_module_graph
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 1d254c8..dd14c7d 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -415,12 +415,10 @@
 	case reflect.Struct:
 		// Special cases where the bp2build sends additional information to the codegenerator
 		// by wrapping the attributes in a custom struct type.
-		if labels, ok := propertyValue.Interface().(bazel.LabelListAttribute); ok {
-			return prettyPrintLabelListAttribute(labels, indent)
+		if attr, ok := propertyValue.Interface().(bazel.Attribute); ok {
+			return prettyPrintAttribute(attr, indent)
 		} else if label, ok := propertyValue.Interface().(bazel.Label); ok {
 			return fmt.Sprintf("%q", label.Label), nil
-		} else if stringList, ok := propertyValue.Interface().(bazel.StringListAttribute); ok {
-			return prettyPrintStringListAttribute(stringList, indent)
 		}
 
 		ret = "{\n"
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index d828168..dbea37a 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -37,17 +37,6 @@
 	recovery_available: true,
 	native_bridge_supported: true,
 	src: "",
-}
-
-toolchain_library {
-	name: "libatomic",
-	defaults: ["linux_bionic_supported"],
-	vendor_available: true,
-	vendor_ramdisk_available: true,
-	product_available: true,
-	recovery_available: true,
-	native_bridge_supported: true,
-	src: "",
 }`
 )
 
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 7bf5fd3..467b0b2 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -37,17 +37,6 @@
 	recovery_available: true,
 	native_bridge_supported: true,
 	src: "",
-}
-
-toolchain_library {
-	name: "libatomic",
-	defaults: ["linux_bionic_supported"],
-	vendor_available: true,
-	vendor_ramdisk_available: true,
-	product_available: true,
-	recovery_available: true,
-	native_bridge_supported: true,
-	src: "",
 }`
 )
 
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index fcc3080..4f3babe 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -415,6 +415,54 @@
 )`,
 			},
 		},
+		{
+			description:                        "cc_object setting cflags for multiple OSes",
+			moduleTypeUnderTest:                "cc_object",
+			moduleTypeUnderTestFactory:         cc.ObjectFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+			blueprint: `cc_object {
+    name: "foo",
+    srcs: ["base.cpp"],
+    target: {
+        android: {
+            cflags: ["-fPIC"],
+        },
+        windows: {
+            cflags: ["-fPIC"],
+        },
+        darwin: {
+            cflags: ["-Wall"],
+        },
+    },
+    bazel_module: { bp2build_available: true },
+}
+`,
+			expectedBazelTargets: []string{
+				`cc_object(
+    name = "foo",
+    copts = [
+        "-fno-addrsig",
+    ] + select({
+        "//build/bazel/platforms/os:android": [
+            "-fPIC",
+        ],
+        "//build/bazel/platforms/os:darwin": [
+            "-Wall",
+        ],
+        "//build/bazel/platforms/os:windows": [
+            "-fPIC",
+        ],
+        "//conditions:default": [],
+    }),
+    local_include_dirs = [
+        ".",
+    ],
+    srcs = [
+        "base.cpp",
+    ],
+)`,
+			},
+		},
 	}
 
 	dir := "."
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 6ca0d6d..b2b3379 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -9,48 +9,67 @@
 
 // Configurability support for bp2build.
 
-// prettyPrintStringListAttribute converts a StringListAttribute to its Bazel
-// syntax. May contain a select statement.
-func prettyPrintStringListAttribute(stringList bazel.StringListAttribute, indent int) (string, error) {
-	ret, err := prettyPrint(reflect.ValueOf(stringList.Value), indent)
-	if err != nil {
-		return ret, err
+type selects map[string]reflect.Value
+
+func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) {
+	value := reflect.ValueOf(list.Value)
+	if !list.HasConfigurableValues() {
+		return value, nil, nil
 	}
 
-	if !stringList.HasConfigurableValues() {
-		// Select statement not needed.
-		return ret, nil
-	}
-
-	// Create the selects for arch specific values.
-	selects := map[string]reflect.Value{}
-	for arch, selectKey := range bazel.PlatformArchMap {
-		selects[selectKey] = reflect.ValueOf(stringList.GetValueForArch(arch))
-	}
-
-	selectMap, err := prettyPrintSelectMap(selects, "[]", indent)
-	return ret + selectMap, err
-}
-
-// prettyPrintLabelListAttribute converts a LabelListAttribute to its Bazel
-// syntax. May contain select statements.
-func prettyPrintLabelListAttribute(labels bazel.LabelListAttribute, indent int) (string, error) {
-	// TODO(b/165114590): convert glob syntax
-	ret, err := prettyPrint(reflect.ValueOf(labels.Value.Includes), indent)
-	if err != nil {
-		return ret, err
-	}
-
-	if !labels.HasConfigurableValues() {
-		// Select statements not needed.
-		return ret, nil
-	}
-
-	// Create the selects for arch specific values.
 	archSelects := map[string]reflect.Value{}
 	for arch, selectKey := range bazel.PlatformArchMap {
-		archSelects[selectKey] = reflect.ValueOf(labels.GetValueForArch(arch).Includes)
+		archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
 	}
+
+	osSelects := map[string]reflect.Value{}
+	for os, selectKey := range bazel.PlatformOsMap {
+		osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
+	}
+
+	return value, archSelects, osSelects
+}
+
+func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
+	value := reflect.ValueOf(list.Value.Includes)
+	if !list.HasConfigurableValues() {
+		return value, nil, nil
+	}
+
+	archSelects := map[string]reflect.Value{}
+	for arch, selectKey := range bazel.PlatformArchMap {
+		archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch).Includes)
+	}
+
+	osSelects := map[string]reflect.Value{}
+	for os, selectKey := range bazel.PlatformOsMap {
+		osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
+	}
+
+	return value, archSelects, osSelects
+}
+
+// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
+// select statements.
+func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
+	var value reflect.Value
+	var archSelects, osSelects selects
+
+	switch list := v.(type) {
+	case bazel.StringListAttribute:
+		value, archSelects, osSelects = getStringListValues(list)
+	case bazel.LabelListAttribute:
+		value, archSelects, osSelects = getLabelListValues(list)
+	default:
+		return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
+	}
+
+	ret, err := prettyPrint(value, indent)
+	if err != nil {
+		return ret, err
+	}
+
+	// Create the selects for arch specific values.
 	selectMap, err := prettyPrintSelectMap(archSelects, "[]", indent)
 	if err != nil {
 		return "", err
@@ -58,17 +77,22 @@
 	ret += selectMap
 
 	// Create the selects for target os specific values.
-	osSelects := map[string]reflect.Value{}
-	for os, selectKey := range bazel.PlatformOsMap {
-		osSelects[selectKey] = reflect.ValueOf(labels.GetValueForOS(os).Includes)
-	}
 	selectMap, err = prettyPrintSelectMap(osSelects, "[]", indent)
-	return ret + selectMap, err
+	if err != nil {
+		return "", err
+	}
+	ret += selectMap
+
+	return ret, err
 }
 
 // prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
 // to construct a select map for any kind of attribute type.
 func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) {
+	if selectMap == nil {
+		return "", nil
+	}
+
 	var selects string
 	for _, selectKey := range android.SortedStringKeys(selectMap) {
 		value := selectMap[selectKey]
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 2a590eb..497d227 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -58,6 +58,31 @@
 	ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...)
 }
 
+// bp2buildParseCflags creates a label list attribute containing the cflags of a module, including
+func bp2BuildParseCflags(ctx android.TopDownMutatorContext, module *Module) bazel.StringListAttribute {
+	var ret bazel.StringListAttribute
+	for _, props := range module.compiler.compilerProps() {
+		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+			ret.Value = baseCompilerProps.Cflags
+			break
+		}
+	}
+
+	for arch, props := range module.GetArchProperties(&BaseCompilerProperties{}) {
+		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+			ret.SetValueForArch(arch.Name, baseCompilerProps.Cflags)
+		}
+	}
+
+	for os, props := range module.GetTargetProperties(&BaseCompilerProperties{}) {
+		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+			ret.SetValueForOS(os.Name, baseCompilerProps.Cflags)
+		}
+	}
+
+	return ret
+}
+
 // bp2BuildParseHeaderLibs creates a label list attribute containing the header library deps of a module, including
 // configurable attribute values.
 func bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelListAttribute {
diff --git a/cc/cc.go b/cc/cc.go
index 0f9a556..1ce83a9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1646,12 +1646,12 @@
 		c.hideApexVariantFromMake = true
 	}
 
+	c.makeLinkType = GetMakeLinkType(actx, c)
+
 	if c.maybeGenerateBazelActions(actx) {
 		return
 	}
 
-	c.makeLinkType = GetMakeLinkType(actx, c)
-
 	ctx := &moduleContext{
 		ModuleContext: actx,
 		moduleContextImpl: moduleContextImpl{
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 675c020..465283d 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -35,7 +35,7 @@
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
 		variables.ProductVndkVersion = StringPtr("current")
-		variables.Platform_vndk_version = StringPtr("VER")
+		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
 
@@ -75,7 +75,7 @@
 func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
 	t.Helper()
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	return testCcWithConfig(t, config)
 }
@@ -89,7 +89,7 @@
 	t.Helper()
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	return testCcWithConfig(t, config)
 }
@@ -116,7 +116,7 @@
 	t.Helper()
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	testCcErrorWithConfig(t, pattern, config)
 	return
 }
@@ -131,15 +131,15 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	testCcErrorWithConfig(t, pattern, config)
 	return
 }
 
 const (
 	coreVariant     = "android_arm64_armv8-a_shared"
-	vendorVariant   = "android_vendor.VER_arm64_armv8-a_shared"
-	productVariant  = "android_product.VER_arm64_armv8-a_shared"
+	vendorVariant   = "android_vendor.29_arm64_armv8-a_shared"
+	productVariant  = "android_product.29_arm64_armv8-a_shared"
 	recoveryVariant = "android_recovery_arm64_armv8-a_shared"
 )
 
@@ -456,7 +456,7 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	ctx := testCcWithConfig(t, config)
 
@@ -486,8 +486,8 @@
 	vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
 	vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
 
-	variant := "android_vendor.VER_arm64_armv8-a_shared"
-	variant2nd := "android_vendor.VER_arm_armv7-a-neon_shared"
+	variant := "android_vendor.29_arm64_armv8-a_shared"
+	variant2nd := "android_vendor.29_arm_armv7-a-neon_shared"
 
 	snapshotSingleton := ctx.SingletonForTests("vndk-snapshot")
 
@@ -577,12 +577,12 @@
 		}`
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := testCcWithConfig(t, config)
 
 	module := ctx.ModuleForTests("llndk.libraries.txt", "")
 	entries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
-	assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.VER.txt"})
+	assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.29.txt"})
 }
 
 func TestVndkUsingCoreVariant(t *testing.T) {
@@ -627,7 +627,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
 
 	setVndkMustUseVendorVariantListForTest(config, []string{"libvndk"})
@@ -654,7 +654,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
 
 	ctx := testCcWithConfig(t, config)
@@ -705,7 +705,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
 
 	ctx := testCcWithConfig(t, config)
@@ -1331,7 +1331,7 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	ctx := testCcWithConfig(t, config)
 
@@ -1776,7 +1776,7 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	testCcWithConfig(t, config)
 }
@@ -2140,7 +2140,7 @@
 }
 
 func TestEnforceProductVndkVersionErrors(t *testing.T) {
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
 		cc_library {
 			name: "libprod",
 			product_specific: true,
@@ -2155,7 +2155,7 @@
 			nocrt: true,
 		}
 	`)
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
 		cc_library {
 			name: "libprod",
 			product_specific: true,
@@ -2169,7 +2169,7 @@
 			nocrt: true,
 		}
 	`)
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
 		cc_library {
 			name: "libprod",
 			product_specific: true,
@@ -2204,7 +2204,7 @@
 			nocrt: true,
 		}
 	`)
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.VER", `
+	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
 		cc_library {
 			name: "libprod",
 			product_specific: true,
@@ -2330,7 +2330,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	// native:vndk
 	ctx := testCcWithConfig(t, config)
 
@@ -2664,27 +2664,27 @@
 	`)
 	actual := ctx.ModuleVariantsForTests("libllndk")
 	for i := 0; i < len(actual); i++ {
-		if !strings.HasPrefix(actual[i], "android_vendor.VER_") {
+		if !strings.HasPrefix(actual[i], "android_vendor.29_") {
 			actual = append(actual[:i], actual[i+1:]...)
 			i--
 		}
 	}
 	expected := []string{
-		"android_vendor.VER_arm64_armv8-a_shared_1",
-		"android_vendor.VER_arm64_armv8-a_shared_2",
-		"android_vendor.VER_arm64_armv8-a_shared_current",
-		"android_vendor.VER_arm64_armv8-a_shared",
-		"android_vendor.VER_arm_armv7-a-neon_shared_1",
-		"android_vendor.VER_arm_armv7-a-neon_shared_2",
-		"android_vendor.VER_arm_armv7-a-neon_shared_current",
-		"android_vendor.VER_arm_armv7-a-neon_shared",
+		"android_vendor.29_arm64_armv8-a_shared_1",
+		"android_vendor.29_arm64_armv8-a_shared_2",
+		"android_vendor.29_arm64_armv8-a_shared_current",
+		"android_vendor.29_arm64_armv8-a_shared",
+		"android_vendor.29_arm_armv7-a-neon_shared_1",
+		"android_vendor.29_arm_armv7-a-neon_shared_2",
+		"android_vendor.29_arm_armv7-a-neon_shared_current",
+		"android_vendor.29_arm_armv7-a-neon_shared",
 	}
 	checkEquals(t, "variants for llndk stubs", expected, actual)
 
-	params := ctx.ModuleForTests("libllndk", "android_vendor.VER_arm_armv7-a-neon_shared").Description("generate stub")
+	params := ctx.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub")
 	checkEquals(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
 
-	params = ctx.ModuleForTests("libllndk", "android_vendor.VER_arm_armv7-a-neon_shared_1").Description("generate stub")
+	params = ctx.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared_1").Description("generate stub")
 	checkEquals(t, "override apiLevel for versioned stubs", "1", params.Args["apiLevel"])
 }
 
@@ -2714,7 +2714,7 @@
 	`)
 
 	// _static variant is used since _shared reuses *.o from the static variant
-	cc := ctx.ModuleForTests("libvendor", "android_vendor.VER_arm_armv7-a-neon_static").Rule("cc")
+	cc := ctx.ModuleForTests("libvendor", "android_vendor.29_arm_armv7-a-neon_static").Rule("cc")
 	cflags := cc.Args["cFlags"]
 	if !strings.Contains(cflags, "-Imy_include") {
 		t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags)
@@ -2835,7 +2835,7 @@
 
 	// runtime_libs for vendor variants have '.vendor' suffixes if the modules have both core
 	// and vendor variants.
-	variant = "android_vendor.VER_arm64_armv8-a_shared"
+	variant = "android_vendor.29_arm64_armv8-a_shared"
 
 	module = ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module)
 	checkRuntimeLibs(t, []string{"liball_available.vendor"}, module)
@@ -2845,7 +2845,7 @@
 
 	// runtime_libs for product variants have '.product' suffixes if the modules have both core
 	// and product variants.
-	variant = "android_product.VER_arm64_armv8-a_shared"
+	variant = "android_product.29_arm64_armv8-a_shared"
 
 	module = ctx.ModuleForTests("libproduct_available1", variant).Module().(*Module)
 	checkRuntimeLibs(t, []string{"liball_available.product"}, module)
@@ -2861,7 +2861,7 @@
 	module := ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module)
 	checkRuntimeLibs(t, []string{"liball_available"}, module)
 
-	variant = "android_vendor.VER_arm64_armv8-a_shared"
+	variant = "android_vendor.29_arm64_armv8-a_shared"
 	module = ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module)
 	checkRuntimeLibs(t, nil, module)
 }
@@ -2912,13 +2912,13 @@
 	// Check the shared version of lib2.
 	variant := "android_arm64_armv8-a_shared"
 	module := ctx.ModuleForTests("lib2", variant).Module().(*Module)
-	checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic"}, module)
+	checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins-aarch64-android"}, module)
 
 	// Check the static version of lib2.
 	variant = "android_arm64_armv8-a_static"
 	module = ctx.ModuleForTests("lib2", variant).Module().(*Module)
 	// libc++_static is linked additionally.
-	checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins-aarch64-android", "libatomic"}, module)
+	checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins-aarch64-android"}, module)
 }
 
 var compilerFlagsTestCases = []struct {
@@ -3044,7 +3044,7 @@
 	`)
 
 	coreVariant := "android_arm64_armv8-a_shared"
-	vendorVariant := "android_vendor.VER_arm64_armv8-a_shared"
+	vendorVariant := "android_vendor.29_arm64_armv8-a_shared"
 
 	// test if header search paths are correctly added
 	// _static variant is used since _shared reuses *.o from the static variant
@@ -3124,7 +3124,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
 
 	ctx := testCcWithConfig(t, config)
diff --git a/cc/library.go b/cc/library.go
index 50fff7f..11b6737 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -425,11 +425,14 @@
 	if !ok {
 		return ok
 	}
-	if len(outputPaths) != 1 {
+	if len(outputPaths) > 1 {
 		// TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
 		// We should support this.
-		ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths)
+		ctx.ModuleErrorf("expected at most one output file for '%s', but got %s", label, objPaths)
 		return false
+	} else if len(outputPaths) == 0 {
+		handler.module.outputFile = android.OptionalPath{}
+		return true
 	}
 	outputFilePath := android.PathForBazelOut(ctx, outputPaths[0])
 	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
@@ -453,7 +456,15 @@
 			Direct(outputFilePath).
 			Build(),
 	})
-	handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
+	if i, ok := handler.module.linker.(snapshotLibraryInterface); ok {
+		// Dependencies on this library will expect collectedSnapshotHeaders to
+		// be set, otherwise validation will fail. For now, set this to an empty
+		// list.
+		// TODO(cparsons): More closely mirror the collectHeadersForSnapshot
+		// implementation.
+		i.(*libraryDecorator).collectedSnapshotHeaders = android.Paths{}
+	}
+
 	return ok
 }
 
diff --git a/cc/library_headers.go b/cc/library_headers.go
index c8dd2c2..82af16a 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -62,6 +62,7 @@
 }
 
 type bazelCcLibraryHeadersAttributes struct {
+	Copts    bazel.StringListAttribute
 	Hdrs     bazel.LabelListAttribute
 	Includes bazel.LabelListAttribute
 	Deps     bazel.LabelListAttribute
@@ -99,6 +100,7 @@
 	headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module)
 
 	attrs := &bazelCcLibraryHeadersAttributes{
+		Copts:    bp2BuildParseCflags(ctx, module),
 		Includes: exportedIncludesLabels,
 		Hdrs:     exportedIncludesHeadersLabels,
 		Deps:     headerLibsLabels,
diff --git a/cc/linker.go b/cc/linker.go
index 21281d2..ae33356 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -321,10 +321,9 @@
 	}
 
 	if ctx.toolchain().Bionic() {
-		// libclang_rt.builtins and libatomic have to be last on the command line
+		// libclang_rt.builtins has to be last on the command line
 		if !Bool(linker.Properties.No_libcrt) {
 			deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
-			deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
 		}
 
 		deps.SystemSharedLibs = linker.Properties.System_shared_libs
diff --git a/cc/object.go b/cc/object.go
index ea8d7d3..4f8797d 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -156,13 +156,11 @@
 	}
 
 	// Set arch-specific configurable attributes
-	var copts bazel.StringListAttribute
 	var srcs bazel.LabelListAttribute
 	var localIncludeDirs []string
 	var asFlags []string
 	for _, props := range m.compiler.compilerProps() {
 		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			copts.Value = baseCompilerProps.Cflags
 			srcs = bazel.MakeLabelListAttribute(
 				android.BazelLabelForModuleSrcExcludes(
 					ctx,
@@ -205,14 +203,13 @@
 	for arch, p := range m.GetArchProperties(&BaseCompilerProperties{}) {
 		if cProps, ok := p.(*BaseCompilerProperties); ok {
 			srcs.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcExcludes(ctx, cProps.Srcs, cProps.Exclude_srcs))
-			copts.SetValueForArch(arch.Name, cProps.Cflags)
 		}
 	}
 
 	attrs := &bazelObjectAttributes{
 		Srcs:               srcs,
 		Deps:               deps,
-		Copts:              copts,
+		Copts:              bp2BuildParseCflags(ctx, m),
 		Asflags:            asFlags,
 		Local_include_dirs: localIncludeDirs,
 	}
diff --git a/cc/testing.go b/cc/testing.go
index 6e35655..ff32bff 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -63,17 +63,6 @@
 func commonDefaultModules() string {
 	return `
 		toolchain_library {
-			name: "libatomic",
-			defaults: ["linux_bionic_supported"],
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			product_available: true,
-			recovery_available: true,
-			native_bridge_supported: true,
-			src: "",
-		}
-
-		toolchain_library {
 			name: "libcompiler_rt-extras",
 			vendor_available: true,
 			vendor_ramdisk_available: true,
@@ -200,29 +189,6 @@
 			srcs: [""],
 		}
 
-		toolchain_library {
-			name: "libgcc",
-			defaults: ["linux_bionic_supported"],
-			vendor_available: true,
-			product_available: true,
-			recovery_available: true,
-			src: "",
-			apex_available: [
-				"//apex_available:platform",
-				"//apex_available:anyapex",
-			],
-		}
-
-		toolchain_library {
-			name: "libgcc_stripped",
-			defaults: ["linux_bionic_supported"],
-			vendor_available: true,
-			product_available: true,
-			recovery_available: true,
-			sdk_version: "current",
-			src: "",
-		}
-
 		cc_library {
 			name: "libc",
 			defaults: ["linux_bionic_supported"],
@@ -398,16 +364,6 @@
 				"//apex_available:anyapex",
 			],
 		}
-		cc_library {
-			name: "libunwind_llvm",
-			no_libcrt: true,
-			nocrt: true,
-			system_shared_libs: [],
-			stl: "none",
-			vendor_available: true,
-			product_available: true,
-			recovery_available: true,
-		}
 
 		cc_defaults {
 			name: "crt_defaults",
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 8d13ceb..20cd031 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -88,7 +88,7 @@
 `
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := testCcWithConfig(t, config)
 
 	// Check Vendor snapshot output.
@@ -108,7 +108,7 @@
 		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
 
 		// For shared libraries, only non-VNDK vendor_available modules are captured
-		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
 		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
 		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
 		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
@@ -121,8 +121,8 @@
 
 		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
 		// Also cfi variants are captured, except for prebuilts like toolchain_library
-		staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
-		staticCfiVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static_cfi", archType, archVariant)
+		staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant)
+		staticCfiVariant := fmt.Sprintf("android_vendor.29_%s_%s_static_cfi", archType, archVariant)
 		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
 		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
 		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
@@ -142,7 +142,7 @@
 
 		// For binary executables, all vendor:true and vendor_available modules are captured.
 		if archType == "arm64" {
-			binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+			binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
 			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
 			checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
 			checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
@@ -156,7 +156,7 @@
 		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json"))
 
 		// For object modules, all vendor:true and vendor_available modules are captured.
-		objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+		objectVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
 		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
 		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
 		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
@@ -214,7 +214,7 @@
 `
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	config.TestProductVariables.DirectedVendorSnapshot = true
 	config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
 	config.TestProductVariables.VendorSnapshotModules["libvendor"] = true
@@ -237,7 +237,7 @@
 		archVariant := arch[1]
 		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
 
-		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
 		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
 
 		// Included modules
@@ -308,7 +308,7 @@
 	vndkBp := `
 	vndk_prebuilt_shared {
 		name: "libvndk",
-		version: "BOARD",
+		version: "28",
 		target_arch: "arm64",
 		vendor_available: true,
 		product_available: true,
@@ -326,7 +326,7 @@
 	// old snapshot module which has to be ignored
 	vndk_prebuilt_shared {
 		name: "libvndk",
-		version: "OLD",
+		version: "26",
 		target_arch: "arm64",
 		vendor_available: true,
 		product_available: true,
@@ -381,7 +381,7 @@
 	vendor_snapshot {
 		name: "vendor_snapshot",
 		compile_multilib: "first",
-		version: "BOARD",
+		version: "28",
 		vndk_libs: [
 			"libvndk",
 		],
@@ -401,7 +401,7 @@
 
 	vendor_snapshot_static {
 		name: "libvndk",
-		version: "BOARD",
+		version: "28",
 		target_arch: "arm64",
 		vendor: true,
 		arch: {
@@ -414,7 +414,7 @@
 
 	vendor_snapshot_shared {
 		name: "libvendor",
-		version: "BOARD",
+		version: "28",
 		target_arch: "arm64",
 		compile_multilib: "64",
 		vendor: true,
@@ -433,7 +433,7 @@
 
 	vendor_snapshot_static {
 		name: "libvendor",
-		version: "BOARD",
+		version: "28",
 		target_arch: "arm64",
 		vendor: true,
 		arch: {
@@ -447,7 +447,7 @@
 	vendor_snapshot_shared {
 		name: "libvendor_available",
 		androidmk_suffix: ".vendor",
-		version: "BOARD",
+		version: "28",
 		target_arch: "arm64",
 		vendor: true,
 		arch: {
@@ -461,7 +461,7 @@
 	vendor_snapshot_static {
 		name: "libvendor_available",
 		androidmk_suffix: ".vendor",
-		version: "BOARD",
+		version: "28",
 		target_arch: "arm64",
 		vendor: true,
 		arch: {
@@ -474,7 +474,7 @@
 
 	vendor_snapshot_binary {
 		name: "bin",
-		version: "BOARD",
+		version: "28",
 		target_arch: "arm64",
 		vendor: true,
 		arch: {
@@ -487,7 +487,7 @@
 	// old snapshot module which has to be ignored
 	vendor_snapshot_binary {
 		name: "bin",
-		version: "OLD",
+		version: "26",
 		target_arch: "arm64",
 		vendor: true,
 		arch: {
@@ -517,8 +517,8 @@
 	}
 
 	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := CreateTestContext(config)
 	ctx.Register()
 
@@ -527,11 +527,11 @@
 	_, errs = ctx.PrepareBuildActions(config)
 	android.FailIfErrored(t, errs)
 
-	sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared"
-	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
-	binaryVariant := "android_vendor.BOARD_arm64_armv8-a"
+	sharedVariant := "android_vendor.28_arm64_armv8-a_shared"
+	staticVariant := "android_vendor.28_arm64_armv8-a_static"
+	binaryVariant := "android_vendor.28_arm64_armv8-a"
 
-	// libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot
+	// libclient uses libvndk.vndk.28.arm64, libvendor.vendor_static.28.arm64, libvendor_without_snapshot
 	libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
 	for _, includeFlags := range []string{
 		"-Ivndk/include/libvndk",     // libvndk
@@ -545,8 +545,8 @@
 
 	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
 	for _, input := range [][]string{
-		[]string{sharedVariant, "libvndk.vndk.BOARD.arm64"},
-		[]string{staticVariant, "libvendor.vendor_static.BOARD.arm64"},
+		[]string{sharedVariant, "libvndk.vndk.28.arm64"},
+		[]string{staticVariant, "libvendor.vendor_static.28.arm64"},
 		[]string{staticVariant, "libvendor_without_snapshot"},
 	} {
 		outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
@@ -565,7 +565,7 @@
 		t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
 	}
 
-	// bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64
+	// bin_without_snapshot uses libvndk.vendor_static.28.arm64
 	binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
 	if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") {
 		t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
@@ -573,28 +573,28 @@
 	}
 
 	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
-	libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"})
+	libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.28.arm64"})
 	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
 		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
 			libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
 	}
 
-	// libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64
-	ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so")
+	// libvendor.so is installed by libvendor.vendor_shared.28.arm64
+	ctx.ModuleForTests("libvendor.vendor_shared.28.arm64", sharedVariant).Output("libvendor.so")
 
-	// libvendor_available.so is installed by libvendor_available.vendor_shared.BOARD.arm64
-	ctx.ModuleForTests("libvendor_available.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor_available.so")
+	// libvendor_available.so is installed by libvendor_available.vendor_shared.28.arm64
+	ctx.ModuleForTests("libvendor_available.vendor_shared.28.arm64", sharedVariant).Output("libvendor_available.so")
 
 	// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
 	ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
 
-	// bin is installed by bin.vendor_binary.BOARD.arm64
-	ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin")
+	// bin is installed by bin.vendor_binary.28.arm64
+	ctx.ModuleForTests("bin.vendor_binary.28.arm64", binaryVariant).Output("bin")
 
 	// bin_without_snapshot is installed by bin_without_snapshot
 	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
 
-	// libvendor, libvendor_available and bin don't have vendor.BOARD variant
+	// libvendor, libvendor_available and bin don't have vendor.28 variant
 	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
 	if inList(sharedVariant, libvendorVariants) {
 		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
@@ -617,7 +617,7 @@
 		name: "libsnapshot",
 		vendor: true,
 		target_arch: "arm64",
-		version: "BOARD",
+		version: "28",
 		arch: {
 			arm64: {
 				src: "libsnapshot.a",
@@ -629,18 +629,18 @@
 	}
 `
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := testCcWithConfig(t, config)
 
 	// Check non-cfi and cfi variant.
-	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
-	staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi"
+	staticVariant := "android_vendor.28_arm64_armv8-a_static"
+	staticCfiVariant := "android_vendor.28_arm64_armv8-a_static_cfi"
 
-	staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module)
+	staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticVariant).Module().(*Module)
 	assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")
 
-	staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module)
+	staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticCfiVariant).Module().(*Module)
 	assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
 }
 
@@ -709,7 +709,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := CreateTestContext(config)
 	ctx.Register()
 
@@ -744,7 +744,7 @@
 		archVariant := arch[1]
 		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
 
-		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
 		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
 
 		// Included modules
@@ -801,7 +801,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := CreateTestContext(config)
 	ctx.Register()
 
@@ -875,7 +875,7 @@
 `
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := testCcWithConfig(t, config)
 
 	// Check Recovery snapshot output.
@@ -993,7 +993,7 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
 	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	ctx := CreateTestContext(config)
 	ctx.Register()
 
@@ -1094,7 +1094,7 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	config.TestProductVariables.DirectedRecoverySnapshot = true
 	config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
 	config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 3abf978..1863ece 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -135,10 +135,25 @@
 	}
 }
 
+func writeJsonModuleGraph(configuration android.Config, ctx *android.Context, path string, extraNinjaDeps []string) {
+	f, err := os.Create(path)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "%s", err)
+		os.Exit(1)
+	}
+
+	defer f.Close()
+	ctx.Context.PrintJSONGraph(f)
+	writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir())
+}
+
 func doChosenActivity(configuration android.Config, extraNinjaDeps []string) {
 	bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES")
 	mixedModeBuild := configuration.BazelContext.BazelEnabled()
 	generateQueryView := bazelQueryViewDir != ""
+	jsonModuleFile := configuration.Getenv("SOONG_DUMP_JSON_MODULE_GRAPH")
+
+	prepareBuildActions := !generateQueryView && jsonModuleFile == ""
 
 	if bazelConversionRequested {
 		// Run the alternate pipeline of bp2build mutators and singleton to convert
@@ -147,7 +162,7 @@
 		return
 	}
 
-	ctx := newContext(configuration, !generateQueryView)
+	ctx := newContext(configuration, prepareBuildActions)
 	if mixedModeBuild {
 		runMixedModeBuild(configuration, ctx, extraNinjaDeps)
 	} else {
@@ -159,6 +174,12 @@
 		runQueryView(configuration, ctx)
 		return
 	}
+
+	if jsonModuleFile != "" {
+		writeJsonModuleGraph(configuration, ctx, jsonModuleFile, extraNinjaDeps)
+		return
+	}
+
 	writeMetrics(configuration)
 }
 
@@ -230,6 +251,29 @@
 	}
 }
 
+// Workarounds to support running bp2build in a clean AOSP checkout with no
+// prior builds, and exiting early as soon as the BUILD files get generated,
+// therefore not creating build.ninja files that soong_ui and callers of
+// soong_build expects.
+//
+// These files are: build.ninja and build.ninja.d. Since Kati hasn't been
+// ran as well, and `nothing` is defined in a .mk file, there isn't a ninja
+// target called `nothing`, so we manually create it here.
+func writeFakeNinjaFile(extraNinjaDeps []string, buildDir string) {
+	extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
+
+	ninjaFileName := "build.ninja"
+	ninjaFile := shared.JoinPath(topDir, buildDir, ninjaFileName)
+	ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName)
+	// A workaround to create the 'nothing' ninja target so `m nothing` works,
+	// since bp2build runs without Kati, and the 'nothing' target is declared in
+	// a Makefile.
+	ioutil.WriteFile(ninjaFile, []byte("build nothing: phony\n  phony_output = true\n"), 0666)
+	ioutil.WriteFile(ninjaFileD,
+		[]byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)),
+		0666)
+}
+
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
@@ -271,30 +315,5 @@
 	metrics.Print()
 
 	extraNinjaDeps = append(extraNinjaDeps, codegenContext.AdditionalNinjaDeps()...)
-	extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
-
-	// Workarounds to support running bp2build in a clean AOSP checkout with no
-	// prior builds, and exiting early as soon as the BUILD files get generated,
-	// therefore not creating build.ninja files that soong_ui and callers of
-	// soong_build expects.
-	//
-	// These files are: build.ninja and build.ninja.d. Since Kati hasn't been
-	// ran as well, and `nothing` is defined in a .mk file, there isn't a ninja
-	// target called `nothing`, so we manually create it here.
-	//
-	// Even though outFile (build.ninja) and depFile (build.ninja.d) are values
-	// passed into bootstrap.Main, they are package-private fields in bootstrap.
-	// Short of modifying Blueprint to add an exported getter, inlining them
-	// here is the next-best practical option.
-	ninjaFileName := "build.ninja"
-	ninjaFile := android.PathForOutput(codegenContext, ninjaFileName)
-	ninjaFileD := android.PathForOutput(codegenContext, ninjaFileName+".d")
-	// A workaround to create the 'nothing' ninja target so `m nothing` works,
-	// since bp2build runs without Kati, and the 'nothing' target is declared in
-	// a Makefile.
-	android.WriteFileToOutputDir(ninjaFile, []byte("build nothing: phony\n  phony_output = true\n"), 0666)
-	android.WriteFileToOutputDir(
-		ninjaFileD,
-		[]byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)),
-		0666)
+	writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir())
 }
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 6b7395b..8510f30 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -55,7 +55,7 @@
 		if err != nil {
 			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
 		}
-		if minSdkVersion >= 23 {
+		if minSdkVersion.FinalOrFutureInt() >= 23 {
 			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !useEmbeddedNativeLibs))
 		} else if useEmbeddedNativeLibs {
 			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
diff --git a/java/app.go b/java/app.go
index ec30b49..04406e7 100755
--- a/java/app.go
+++ b/java/app.go
@@ -288,7 +288,7 @@
 
 		if minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx); err == nil {
 			a.checkJniLibsSdkVersion(ctx, minSdkVersion)
-			android.CheckMinSdkVersion(a, ctx, minSdkVersion.ApiLevel(ctx))
+			android.CheckMinSdkVersion(a, ctx, minSdkVersion)
 		} else {
 			ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
 		}
@@ -304,7 +304,7 @@
 // because, sdk_version is overridden by min_sdk_version (if set as smaller)
 // and sdkLinkType is checked with dependencies so we can be sure that the whole dependency tree
 // will meet the requirements.
-func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.SdkVersion) {
+func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) {
 	// It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType()
 	ctx.VisitDirectDeps(func(m android.Module) {
 		if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) {
@@ -315,7 +315,7 @@
 		// We can rely on android.SdkSpec to convert it to <number> so that "current" is
 		// handled properly regardless of sdk finalization.
 		jniSdkVersion, err := android.SdkSpecFrom(dep.SdkVersion()).EffectiveVersion(ctx)
-		if err != nil || minSdkVersion < jniSdkVersion {
+		if err != nil || minSdkVersion.LessThan(jniSdkVersion) {
 			ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
 				dep.SdkVersion(), minSdkVersion, ctx.ModuleName())
 			return
@@ -333,7 +333,7 @@
 	}
 
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	return (minSdkVersion >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
+	return (minSdkVersion.FinalOrFutureInt() >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
 		!apexInfo.IsForPlatform()
 }
 
@@ -380,7 +380,11 @@
 }
 
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
-	a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
+	usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis)
+	if ctx.Module().(android.SdkContext).SdkVersion().Kind == android.SdkModule {
+		usePlatformAPI = true
+	}
+	a.aapt.usesNonSdkApis = usePlatformAPI
 
 	// Ask manifest_fixer to add or update the application element indicating this app has no code.
 	a.aapt.hasNoCode = !a.hasCode(ctx)
diff --git a/java/base.go b/java/base.go
index 73e5352..9bc0738 100644
--- a/java/base.go
+++ b/java/base.go
@@ -535,7 +535,7 @@
 }
 
 func (j *Module) MinSdkVersionString() string {
-	return j.MinSdkVersion().Version.String()
+	return j.MinSdkVersion().ApiLevel.String()
 }
 
 func (j *Module) AvailableFor(what string) bool {
@@ -1255,7 +1255,7 @@
 
 	if ctx.Device() {
 		lintSDKVersionString := func(sdkSpec android.SdkSpec) string {
-			if v := sdkSpec.Version; v.IsNumbered() {
+			if v := sdkSpec.ApiLevel; !v.IsPreview() {
 				return v.String()
 			} else {
 				return ctx.Config().DefaultAppTargetSdk(ctx).String()
@@ -1482,7 +1482,7 @@
 	if err != nil {
 		return err
 	}
-	if ver.ApiLevel(ctx).GreaterThan(sdkVersion) {
+	if ver.GreaterThan(sdkVersion) {
 		return fmt.Errorf("newer SDK(%v)", ver)
 	}
 	return nil
diff --git a/java/dex.go b/java/dex.go
index 5c6d41d..7898e9d 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -179,7 +180,7 @@
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
 	}
 
-	flags = append(flags, "--min-api "+effectiveVersion.AsNumberString())
+	flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt()))
 	return flags
 }
 
diff --git a/java/java.go b/java/java.go
index 5fe8814..fa7c96e 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1156,7 +1156,7 @@
 }
 
 func (j *Import) MinSdkVersionString() string {
-	return j.MinSdkVersion().Version.String()
+	return j.MinSdkVersion().ApiLevel.String()
 }
 
 func (j *Import) Prebuilt() *android.Prebuilt {
@@ -1370,7 +1370,7 @@
 	if err != nil {
 		return err
 	}
-	if ver.ApiLevel(ctx).GreaterThan(sdkVersion) {
+	if ver.GreaterThan(sdkVersion) {
 		return fmt.Errorf("newer SDK(%v)", ver)
 	}
 	return nil
diff --git a/java/sdk.go b/java/sdk.go
index b546ca0..f324b76 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -51,9 +51,9 @@
 	if err != nil {
 		ctx.PropertyErrorf("sdk_version", "%s", err)
 	}
-	if sdk <= 23 {
+	if sdk.FinalOrFutureInt() <= 23 {
 		return JAVA_VERSION_7
-	} else if sdk <= 29 {
+	} else if sdk.FinalOrFutureInt() <= 29 {
 		return JAVA_VERSION_8
 	} else {
 		return JAVA_VERSION_9
@@ -76,11 +76,11 @@
 	}
 
 	if sdkVersion.UsePrebuilt(ctx) {
-		dir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), sdkVersion.Kind.String())
+		dir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), sdkVersion.Kind.String())
 		jar := filepath.Join(dir, "android.jar")
 		// There's no aidl for other SDKs yet.
 		// TODO(77525052): Add aidl files for other SDKs too.
-		publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), "public")
+		publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), "public")
 		aidl := filepath.Join(publicDir, "framework.aidl")
 		jarPath := android.ExistentPathForSource(ctx, jar)
 		aidlPath := android.ExistentPathForSource(ctx, aidl)
@@ -89,7 +89,7 @@
 		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
 			return sdkDep{
 				invalidVersion: true,
-				bootclasspath:  []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.Version.String())},
+				bootclasspath:  []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.ApiLevel.String())},
 			}
 		}
 
@@ -105,7 +105,7 @@
 
 		var systemModules string
 		if defaultJavaLanguageVersion(ctx, sdkVersion).usesJavaModules() {
-			systemModules = "sdk_public_" + sdkVersion.Version.String() + "_system_modules"
+			systemModules = "sdk_public_" + sdkVersion.ApiLevel.String() + "_system_modules"
 		}
 
 		return sdkDep{
diff --git a/java/sdk_library.go b/java/sdk_library.go
index ebb2154..37b8d9f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -817,7 +817,7 @@
 func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
 
 	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
-	if sdkVersion.Version.IsNumbered() {
+	if !sdkVersion.ApiLevel.IsPreview() {
 		return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
 	}
 
@@ -1466,15 +1466,15 @@
 }
 
 func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths {
-	var ver android.SdkVersion
+	var ver android.ApiLevel
 	var kind android.SdkKind
 	if s.UsePrebuilt(ctx) {
-		ver = s.Version
+		ver = s.ApiLevel
 		kind = s.Kind
 	} else {
 		// We don't have prebuilt SDK for the specific sdkVersion.
 		// Instead of breaking the build, fallback to use "system_current"
-		ver = android.SdkVersionCurrent
+		ver = android.FutureApiLevel
 		kind = android.SdkSystem
 	}
 
diff --git a/rust/image_test.go b/rust/image_test.go
index e40599c..7677cce 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -38,7 +38,7 @@
 			}
 		`)
 
-	vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.VER_arm64_armv8-a").Module().(*cc.Module)
+	vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.29_arm64_armv8-a").Module().(*cc.Module)
 
 	if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
 		t.Errorf("vendorBinary should have a dependency on libfoo_vendor")
@@ -56,7 +56,7 @@
 			}
 		`)
 
-	vendor := ctx.ModuleForTests("libfoo", "android_vendor.VER_arm64_armv8-a_static").Rule("rustc")
+	vendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_static").Rule("rustc")
 
 	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
 		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 418bd93..890fb26 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -75,7 +75,7 @@
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr("current")
 				variables.ProductVndkVersion = StringPtr("current")
-				variables.Platform_vndk_version = StringPtr("VER")
+				variables.Platform_vndk_version = StringPtr("29")
 			},
 		),
 	).RunTestWithBp(t, bp)
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index f42f9e9..6d35f9c 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -129,7 +129,7 @@
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.DeviceSystemSdkVersions = []string{"28"}
 			variables.DeviceVndkVersion = proptools.StringPtr("current")
-			variables.Platform_vndk_version = proptools.StringPtr("VER")
+			variables.Platform_vndk_version = proptools.StringPtr("29")
 		}),
 		mockFS.AddToFixture(),
 		android.FixtureWithRootAndroidBp(bp),
@@ -246,10 +246,10 @@
 
 	// Check for generated cc_library
 	for _, variant := range []string{
-		"android_vendor.VER_arm_armv7-a-neon_shared",
-		"android_vendor.VER_arm_armv7-a-neon_static",
-		"android_vendor.VER_arm64_armv8-a_shared",
-		"android_vendor.VER_arm64_armv8-a_static",
+		"android_vendor.29_arm_armv7-a-neon_shared",
+		"android_vendor.29_arm_armv7-a-neon_static",
+		"android_vendor.29_arm64_armv8-a_shared",
+		"android_vendor.29_arm64_armv8-a_static",
 	} {
 		result.ModuleForTests("libsysprop-platform", variant)
 		result.ModuleForTests("libsysprop-vendor", variant)
@@ -277,15 +277,15 @@
 
 	// Check for exported includes
 	coreVariant := "android_arm64_armv8-a_static"
-	vendorVariant := "android_vendor.VER_arm64_armv8-a_static"
+	vendorVariant := "android_vendor.29_arm64_armv8-a_static"
 
 	platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/include"
 	platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/public/include"
-	platformPublicVendorPath := "libsysprop-platform/android_vendor.VER_arm64_armv8-a_static/gen/sysprop/public/include"
+	platformPublicVendorPath := "libsysprop-platform/android_vendor.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
 
-	vendorInternalPath := "libsysprop-vendor/android_vendor.VER_arm64_armv8-a_static/gen/sysprop/include"
+	vendorInternalPath := "libsysprop-vendor/android_vendor.29_arm64_armv8-a_static/gen/sysprop/include"
 	vendorPublicPath := "libsysprop-vendor-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	platformClient := result.ModuleForTests("cc-client-platform", coreVariant)