Merge "Rollforward w/fix of "Use json encoding for cquery ParseResult" Previous commit: commit fcc53f992b40786b216d38844ab61945fe5c9071."
diff --git a/android/Android.bp b/android/Android.bp
index e0ad58f..29a88f2 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -30,6 +30,7 @@
     srcs: [
         "androidmk.go",
         "apex.go",
+        "api_domain.go",
         "api_levels.go",
         "arch.go",
         "arch_list.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index cad9ec7..cfaa1d4 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -296,6 +296,8 @@
 		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/unwinding/libunwindstack":                        Bp2BuildDefaultTrueRecursively,
 
+		"frameworks/proto_logging/stats": Bp2BuildDefaultTrueRecursively,
+
 		"tools/apksig": Bp2BuildDefaultTrue,
 		"tools/platform-compat/java/android/compat":  Bp2BuildDefaultTrueRecursively,
 		"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
@@ -386,6 +388,7 @@
 		"libnativeloader-headers",
 		"libnativewindow_headers",
 		"libneuralnetworks_headers",
+		"libneuralnetworks_packageinfo",
 		"libopus",
 		"libpdx_headers",
 		"libprocpartition",
@@ -425,11 +428,14 @@
 		"neuralnetworks_types",
 		"neuralnetworks_utils_hal_aidl",
 		"neuralnetworks_utils_hal_common",
+		"neuralnetworks_utils_hal_service",
 		"neuralnetworks_utils_hal_1_0",
 		"neuralnetworks_utils_hal_1_1",
 		"neuralnetworks_utils_hal_1_2",
 		"neuralnetworks_utils_hal_1_3",
 		"libneuralnetworks_common",
+		// packagemanager_aidl_interface is created implicitly in packagemanager_aidl module
+		"packagemanager_aidl_interface",
 		"philox_random",
 		"philox_random_headers",
 		"server_configurable_flags",
@@ -502,6 +508,45 @@
 
 		//frameworks/native/cmds/cmd
 		"libcmd",
+
+		//system/core/fs_mgr/libdm
+		"libdm",
+
+		//system/core/fs_mgr/libfiemap
+		"libfiemap_headers",
+		"libfiemap_passthrough_srcs",
+		"libfiemap_srcs",
+
+		//system/gsid
+		"libgsi",
+		"libgsi_headers",
+
+		//system/core/libkeyutils
+		"libkeyutils",
+
+		//bootable/recovery/minadbd
+		"libminadbd_headers",
+
+		//bootable/recovery/otautil
+		"libotautil",
+
+		//system/vold
+		"libvold_headers",
+
+		//system/extras/libfscrypt
+		"libfscrypt",
+
+		//system/core/fs_mgr
+		"libfstab",
+
+		//bootable/recovery/fuse_sideload
+		"libfusesideload",
+
+		//system/core/fs_mgr/libfs_avb
+		"libfs_avb",
+
+		//system/core/fs_mgr
+		"libfs_mgr",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -551,9 +596,6 @@
 		"prebuilt_platform-robolectric-4.4-prebuilt",   // aosp/1999250, needs .aar support in Jars
 		"prebuilt_platform-robolectric-4.5.1-prebuilt", // aosp/1999250, needs .aar support in Jars
 
-		// proto support
-		"libstats_proto_host", // TODO(b/236055697): handle protos from other packages
-
 		// path property for filegroups
 		"conscrypt",                        // TODO(b/210751803), we don't handle path property for filegroups
 		"conscrypt-for-host",               // TODO(b/210751803), we don't handle path property for filegroups
@@ -620,7 +662,6 @@
 		"pbtombstone", "crash_dump", // depends on libdebuggerd, libunwindstack
 		"robolectric-sqlite4java-0.282",             // depends on unconverted modules: robolectric-sqlite4java-import, robolectric-sqlite4java-native
 		"static_crasher",                            // depends on unconverted modules: libdebuggerd_handler
-		"stats-log-api-gen",                         // depends on unconverted modules: libstats_proto_host
 		"statslog.cpp", "statslog.h", "statslog.rs", // depends on unconverted modules: stats-log-api-gen
 		"statslog_art.cpp", "statslog_art.h", "statslog_header.rs", // depends on unconverted modules: stats-log-api-gen
 		"test_fips",           // depends on unconverted modules: adb
@@ -1088,6 +1129,12 @@
 		"libtest_with_dependency_loop_b_tmp",
 		"libtest_with_dependency_loop_c",
 		"libtestshared",
+
+		// depends on unconverted libprotobuf-java-nano
+		"dnsresolverprotosnano",
+		"launcherprotosnano",
+		"datastallprotosnano",
+		"devicepolicyprotosnano",
 	}
 
 	Bp2buildCcLibraryStaticOnlyList = []string{}
@@ -1136,6 +1183,20 @@
 		"prebuilt_platform-robolectric-4.4-prebuilt",
 		"prebuilt_platform-robolectric-4.5.1-prebuilt",
 		"prebuilt_currysrc_org.eclipse",
+
+		// TODO(b/247782695 and/or b/242847534) Fix mixed build between unconverted gensrcs and converted filegroup
+		"libstats_atom_enum_protos",
+		"data_stall_event_proto",
+		"device_policy_proto",
+		"dns_resolver_proto",
+		"launcher_proto",
+		"network_stack_proto",
+		"srcs_bluetooth_protos",
+		"srcs_bluetooth_leaudio_protos",
+		"style_proto",
+		"tethering_proto",
+		"text_classifier_proto",
+		"libstats_atom_message_protos",
 	}
 
 	ProdMixedBuildsEnabledList = []string{
diff --git a/android/api_domain.go b/android/api_domain.go
new file mode 100644
index 0000000..a808e32
--- /dev/null
+++ b/android/api_domain.go
@@ -0,0 +1,100 @@
+// Copyright 2022 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 android
+
+import (
+	"github.com/google/blueprint"
+
+	"android/soong/bazel"
+)
+
+func init() {
+	RegisterApiDomainBuildComponents(InitRegistrationContext)
+}
+
+func RegisterApiDomainBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("api_domain", ApiDomainFactory)
+}
+
+type apiDomain struct {
+	ModuleBase
+	BazelModuleBase
+
+	properties apiDomainProperties
+}
+
+type apiDomainProperties struct {
+	// cc library contributions (.h files/.map.txt) of this API domain
+	// This dependency is a no-op in Soong, but the corresponding Bazel target in the bp2build workspace will provide a `CcApiContributionInfo` provider
+	Cc_api_contributions []string
+}
+
+func ApiDomainFactory() Module {
+	m := &apiDomain{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, DeviceSupported, MultilibBoth)
+	InitBazelModule(m)
+	return m
+}
+
+func (a *apiDomain) DepsMutator(ctx BottomUpMutatorContext) {
+	for _, cc := range a.properties.Cc_api_contributions {
+		// Use FarVariationDependencies since the variants of api_domain is a subset of the variants of the dependency cc module
+		// Creating a dependency on the first variant is ok since this is a no-op in Soong
+		// The primary function of this dependency is to create a connected graph in the corresponding bp2build workspace
+		ctx.AddFarVariationDependencies([]blueprint.Variation{}, nil, cc)
+	}
+}
+
+// API domain does not have any builld actions yet
+func (a *apiDomain) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+const (
+	apiContributionSuffix = ".contribution"
+)
+
+// ApiContributionTargetName returns the name of the bp2build target (e.g. cc_api_contribution)  of contribution modules (e.g. ndk_library)
+// A suffix is necessary to prevent a name collision with the base target in the same bp2build bazel package
+func ApiContributionTargetName(moduleName string) string {
+	return moduleName + apiContributionSuffix
+}
+
+// For each contributing cc_library, format the name to its corresponding contribution bazel target in the bp2build workspace
+func contributionBazelAttributes(ctx TopDownMutatorContext, contributions []string) bazel.LabelListAttribute {
+	addSuffix := func(ctx BazelConversionPathContext, module blueprint.Module) string {
+		baseLabel := BazelModuleLabel(ctx, module)
+		return ApiContributionTargetName(baseLabel)
+	}
+	bazelLabels := BazelLabelForModuleDepsWithFn(ctx, contributions, addSuffix)
+	return bazel.MakeLabelListAttribute(bazelLabels)
+}
+
+type bazelApiDomainAttributes struct {
+	Cc_api_contributions bazel.LabelListAttribute
+}
+
+func (a *apiDomain) ConvertWithBp2build(ctx TopDownMutatorContext) {
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "api_domain",
+		Bzl_load_location: "//build/bazel/rules/apis:api_domain.bzl",
+	}
+	attrs := &bazelApiDomainAttributes{
+		Cc_api_contributions: contributionBazelAttributes(ctx, a.properties.Cc_api_contributions),
+	}
+	ctx.CreateBazelTargetModule(props, CommonAttributes{
+		Name: ctx.ModuleName(),
+	}, attrs)
+}
diff --git a/android/config.go b/android/config.go
index 745410f..ee432a2 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1619,6 +1619,14 @@
 	return uncheckedFinalApiLevel(apiLevel)
 }
 
+func (c *deviceConfig) BuildBrokenClangAsFlags() bool {
+	return c.config.productVariables.BuildBrokenClangAsFlags
+}
+
+func (c *deviceConfig) BuildBrokenClangCFlags() bool {
+	return c.config.productVariables.BuildBrokenClangCFlags
+}
+
 func (c *deviceConfig) BuildBrokenClangProperty() bool {
 	return c.config.productVariables.BuildBrokenClangProperty
 }
diff --git a/android/sdk.go b/android/sdk.go
index a477cba..a9cc547 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -74,6 +74,26 @@
 	sdkAwareWithoutModule
 }
 
+// minApiLevelForSdkSnapshot provides access to the min_sdk_version for MinApiLevelForSdkSnapshot
+type minApiLevelForSdkSnapshot interface {
+	MinSdkVersion(ctx EarlyModuleContext) SdkSpec
+}
+
+// MinApiLevelForSdkSnapshot returns the ApiLevel of the min_sdk_version of the supplied module.
+//
+// If the module does not provide a min_sdk_version then it defaults to 1.
+func MinApiLevelForSdkSnapshot(ctx EarlyModuleContext, module Module) ApiLevel {
+	minApiLevel := NoneApiLevel
+	if m, ok := module.(minApiLevelForSdkSnapshot); ok {
+		minApiLevel = m.MinSdkVersion(ctx).ApiLevel
+	}
+	if minApiLevel == NoneApiLevel {
+		// The default min API level is 1.
+		minApiLevel = uncheckedFinalApiLevel(1)
+	}
+	return minApiLevel
+}
+
 // SdkRef refers to a version of an SDK
 type SdkRef struct {
 	Name    string
diff --git a/android/variable.go b/android/variable.go
index b156051..37ecab5 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -430,6 +430,8 @@
 
 	ShippingApiLevel *string `json:",omitempty"`
 
+	BuildBrokenClangAsFlags            bool     `json:",omitempty"`
+	BuildBrokenClangCFlags             bool     `json:",omitempty"`
 	BuildBrokenClangProperty           bool     `json:",omitempty"`
 	BuildBrokenDepfile                 *bool    `json:",omitempty"`
 	BuildBrokenEnforceSyspropOwner     bool     `json:",omitempty"`
diff --git a/bp2build/api_domain_conversion_test.go b/bp2build/api_domain_conversion_test.go
new file mode 100644
index 0000000..fc9d1d5
--- /dev/null
+++ b/bp2build/api_domain_conversion_test.go
@@ -0,0 +1,68 @@
+// Copyright 2022 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 bp2build
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+func registerApiDomainModuleTypes(ctx android.RegistrationContext) {
+	android.RegisterApiDomainBuildComponents(ctx)
+	cc.RegisterNdkModuleTypes(ctx)
+	cc.RegisterLibraryBuildComponents(ctx)
+}
+
+func TestApiDomainContributionsTest(t *testing.T) {
+	bp := `
+	api_domain {
+		name: "system",
+		cc_api_contributions: [
+			"libfoo.ndk",
+			"libbar",
+		],
+	}
+	`
+	fs := map[string]string{
+		"libfoo/Android.bp": `
+		ndk_library {
+			name: "libfoo",
+		}
+		`,
+		"libbar/Android.bp": `
+		cc_library {
+			name: "libbar",
+		}
+		`,
+	}
+	expectedBazelTarget := MakeBazelTargetNoRestrictions(
+		"api_domain",
+		"system",
+		AttrNameToString{
+			"cc_api_contributions": `[
+        "//libfoo:libfoo.ndk.contribution",
+        "//libbar:libbar.contribution",
+    ]`,
+			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+		},
+	)
+	RunBp2BuildTestCase(t, registerApiDomainModuleTypes, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: []string{expectedBazelTarget},
+		Filesystem:           fs,
+	})
+}
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 1c9fba2..c23779e 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -676,3 +676,77 @@
 		},
 	})
 }
+
+func TestCcBinaryWithSyspropSrcs(t *testing.T) {
+	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary with sysprop sources",
+		blueprint: `
+{rule_name} {
+	name: "foo",
+	srcs: [
+		"bar.sysprop",
+		"baz.sysprop",
+		"blah.cpp",
+	],
+	min_sdk_version: "5",
+}`,
+		targets: []testBazelTarget{
+			{"sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `[
+        "bar.sysprop",
+        "baz.sysprop",
+    ]`,
+			}},
+			{"cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}},
+			{"cc_binary", "foo", AttrNameToString{
+				"srcs":               `["blah.cpp"]`,
+				"local_includes":     `["."]`,
+				"min_sdk_version":    `"5"`,
+				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
+			}},
+		},
+	})
+}
+
+func TestCcBinaryWithSyspropSrcsSomeConfigs(t *testing.T) {
+	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary with sysprop sources in some configs but not others",
+		blueprint: `
+{rule_name} {
+	name: "foo",
+	srcs: [
+		"blah.cpp",
+	],
+	target: {
+		android: {
+			srcs: ["bar.sysprop"],
+		},
+	},
+	min_sdk_version: "5",
+}`,
+		targets: []testBazelTarget{
+			{"sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `select({
+        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//conditions:default": [],
+    })`,
+			}},
+			{"cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}},
+			{"cc_binary", "foo", AttrNameToString{
+				"srcs":            `["blah.cpp"]`,
+				"local_includes":  `["."]`,
+				"min_sdk_version": `"5"`,
+				"whole_archive_deps": `select({
+        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//conditions:default": [],
+    })`,
+			}},
+		},
+	})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index ffa6b3f..f633040 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -3112,3 +3112,97 @@
 		},
 	})
 }
+
+func TestCcLibraryWithSyspropSrcs(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with sysprop sources",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "foo",
+	srcs: [
+		"bar.sysprop",
+		"baz.sysprop",
+		"blah.cpp",
+	],
+	min_sdk_version: "5",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `[
+        "bar.sysprop",
+        "baz.sysprop",
+    ]`,
+			}),
+			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}),
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"srcs":               `["blah.cpp"]`,
+				"local_includes":     `["."]`,
+				"min_sdk_version":    `"5"`,
+				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"srcs":               `["blah.cpp"]`,
+				"local_includes":     `["."]`,
+				"min_sdk_version":    `"5"`,
+				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryWithSyspropSrcsSomeConfigs(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with sysprop sources in some configs but not others",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "foo",
+	host_supported: true,
+	srcs: [
+		"blah.cpp",
+	],
+	target: {
+		android: {
+			srcs: ["bar.sysprop"],
+		},
+	},
+	min_sdk_version: "5",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `select({
+        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTargetNoRestrictions("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}),
+			MakeBazelTargetNoRestrictions("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"srcs":            `["blah.cpp"]`,
+				"local_includes":  `["."]`,
+				"min_sdk_version": `"5"`,
+				"whole_archive_deps": `select({
+        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTargetNoRestrictions("cc_library_shared", "foo", AttrNameToString{
+				"srcs":            `["blah.cpp"]`,
+				"local_includes":  `["."]`,
+				"min_sdk_version": `"5"`,
+				"whole_archive_deps": `select({
+        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 48515c8..b1a9240 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -488,22 +488,21 @@
 `,
 		},
 		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: []string{MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-			"has_stubs": `True`,
-		}),
-			makeCcStubSuiteTargets("a", AttrNameToString{
-				"soname":            `"a.so"`,
-				"source_library":    `":a"`,
-				"stubs_symbol_file": `"a.map.txt"`,
-				"stubs_versions": `[
+		ExpectedBazelTargets: []string{makeCcStubSuiteTargets("a", AttrNameToString{
+			"soname":            `"a.so"`,
+			"source_library":    `":a"`,
+			"stubs_symbol_file": `"a.map.txt"`,
+			"stubs_versions": `[
         "28",
         "29",
         "current",
     ]`,
+		}),
+			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+				"has_stubs": `True`,
 			}),
 		},
-	},
-	)
+	})
 }
 
 func TestCcLibrarySharedSystemSharedLibsSharedEmpty(t *testing.T) {
@@ -728,3 +727,77 @@
 		},
 	})
 }
+
+func TestCcLibrarySharedWithSyspropSrcs(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared with sysprop sources",
+		Blueprint: `
+cc_library_shared {
+	name: "foo",
+	srcs: [
+		"bar.sysprop",
+		"baz.sysprop",
+		"blah.cpp",
+	],
+	min_sdk_version: "5",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `[
+        "bar.sysprop",
+        "baz.sysprop",
+    ]`,
+			}),
+			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"srcs":               `["blah.cpp"]`,
+				"local_includes":     `["."]`,
+				"min_sdk_version":    `"5"`,
+				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibrarySharedWithSyspropSrcsSomeConfigs(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared with sysprop sources in some configs but not others",
+		Blueprint: `
+cc_library_shared {
+	name: "foo",
+	srcs: [
+		"blah.cpp",
+	],
+	target: {
+		android: {
+			srcs: ["bar.sysprop"],
+		},
+	},
+	min_sdk_version: "5",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `select({
+        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"srcs":            `["blah.cpp"]`,
+				"local_includes":  `["."]`,
+				"min_sdk_version": `"5"`,
+				"whole_archive_deps": `select({
+        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 37722ed..e3ea9a0 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1629,3 +1629,77 @@
 		},
 	})
 }
+
+func TestCcLibraryStaticWithSyspropSrcs(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static with sysprop sources",
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+		"bar.sysprop",
+		"baz.sysprop",
+		"blah.cpp",
+	],
+	min_sdk_version: "5",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `[
+        "bar.sysprop",
+        "baz.sysprop",
+    ]`,
+			}),
+			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}),
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"srcs":               `["blah.cpp"]`,
+				"local_includes":     `["."]`,
+				"min_sdk_version":    `"5"`,
+				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryStaticWithSyspropSrcsSomeConfigs(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static with sysprop sources in some configs but not others",
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+		"blah.cpp",
+	],
+	target: {
+		android: {
+			srcs: ["bar.sysprop"],
+		},
+	},
+	min_sdk_version: "5",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
+				"srcs": `select({
+        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//conditions:default": [],
+    })`,
+			}),
+			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
+				"dep":             `":foo_sysprop_library"`,
+				"min_sdk_version": `"5"`,
+			}),
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"srcs":            `["blah.cpp"]`,
+				"local_includes":  `["."]`,
+				"min_sdk_version": `"5"`,
+				"whole_archive_deps": `select({
+        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	})
+}
diff --git a/cc/Android.bp b/cc/Android.bp
index 91a3fb0..8860f78 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -45,6 +45,7 @@
         "snapshot_utils.go",
         "stl.go",
         "strip.go",
+        "sysprop.go",
         "tidy.go",
         "util.go",
         "vendor_snapshot.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 95ac598..972a828 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -28,14 +28,15 @@
 )
 
 const (
-	cSrcPartition     = "c"
-	asSrcPartition    = "as"
-	asmSrcPartition   = "asm"
-	lSrcPartition     = "l"
-	llSrcPartition    = "ll"
-	cppSrcPartition   = "cpp"
-	protoSrcPartition = "proto"
-	aidlSrcPartition  = "aidl"
+	cSrcPartition       = "c"
+	asSrcPartition      = "as"
+	asmSrcPartition     = "asm"
+	lSrcPartition       = "l"
+	llSrcPartition      = "ll"
+	cppSrcPartition     = "cpp"
+	protoSrcPartition   = "proto"
+	aidlSrcPartition    = "aidl"
+	syspropSrcPartition = "sysprop"
 
 	stubsSuffix = "_stub_libs_current"
 )
@@ -104,7 +105,8 @@
 		llSrcPartition: bazel.LabelPartition{Extensions: []string{".ll"}},
 		// C++ is the "catch-all" group, and comprises generated sources because we don't
 		// know the language of these sources until the genrule is executed.
-		cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
+		cppSrcPartition:     bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
+		syspropSrcPartition: bazel.LabelPartition{Extensions: []string{".sysprop"}},
 	}
 
 	return bazel.PartitionLabelListAttribute(ctx, &srcs, labels)
@@ -320,6 +322,9 @@
 	llSrcs  bazel.LabelListAttribute
 	lexopts bazel.StringListAttribute
 
+	// Sysprop sources
+	syspropSrcs bazel.LabelListAttribute
+
 	hdrs bazel.LabelListAttribute
 
 	rtti bazel.BoolAttribute
@@ -482,6 +487,7 @@
 	ca.asmSrcs = partitionedSrcs[asmSrcPartition]
 	ca.lSrcs = partitionedSrcs[lSrcPartition]
 	ca.llSrcs = partitionedSrcs[llSrcPartition]
+	ca.syspropSrcs = partitionedSrcs[syspropSrcPartition]
 
 	ca.absoluteIncludes.DeduplicateAxesFromBase()
 	ca.localIncludes.DeduplicateAxesFromBase()
@@ -734,6 +740,10 @@
 	(&compilerAttrs).srcs.Add(&convertedLSrcs.srcName)
 	(&compilerAttrs).cSrcs.Add(&convertedLSrcs.cSrcName)
 
+	if !compilerAttrs.syspropSrcs.IsEmpty() {
+		(&linkerAttrs).wholeArchiveDeps.Add(bp2buildCcSysprop(ctx, module.Name(), module.Properties.Min_sdk_version, compilerAttrs.syspropSrcs))
+	}
+
 	features := compilerAttrs.features.Clone().Append(linkerAttrs.features)
 	features.DeduplicateAxesFromBase()
 
@@ -1208,10 +1218,14 @@
 	return exported
 }
 
+func BazelLabelNameForStaticModule(baseLabel string) string {
+	return baseLabel + "_bp2build_cc_library_static"
+}
+
 func bazelLabelForStaticModule(ctx android.BazelConversionPathContext, m blueprint.Module) string {
 	label := android.BazelModuleLabel(ctx, m)
 	if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary && !android.GetBp2BuildAllowList().GenerateCcLibraryStaticOnly(m.Name()) {
-		label += "_bp2build_cc_library_static"
+		return BazelLabelNameForStaticModule(label)
 	}
 	return label
 }
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 5d569cc..01ac133 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4386,3 +4386,93 @@
 		})
 	}
 }
+
+func TestCcBuildBrokenClangAsFlags(t *testing.T) {
+	tests := []struct {
+		name                    string
+		clangAsFlags            []string
+		BuildBrokenClangAsFlags bool
+		err                     string
+	}{
+		{
+			name:         "error when clang_asflags is set",
+			clangAsFlags: []string{"-a", "-b"},
+			err:          "clang_asflags: property is deprecated",
+		},
+		{
+			name:                    "no error when BuildBrokenClangAsFlags is explicitly set to true",
+			clangAsFlags:            []string{"-a", "-b"},
+			BuildBrokenClangAsFlags: true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			bp := fmt.Sprintf(`
+			cc_library {
+			   name: "foo",
+			   clang_asflags: %s,
+			}`, `["`+strings.Join(test.clangAsFlags, `","`)+`"]`)
+
+			if test.err == "" {
+				android.GroupFixturePreparers(
+					prepareForCcTest,
+					android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+						if test.BuildBrokenClangAsFlags {
+							variables.BuildBrokenClangAsFlags = test.BuildBrokenClangAsFlags
+						}
+					}),
+				).RunTestWithBp(t, bp)
+			} else {
+				prepareForCcTest.
+					ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(test.err)).
+					RunTestWithBp(t, bp)
+			}
+		})
+	}
+}
+
+func TestCcBuildBrokenClangCFlags(t *testing.T) {
+	tests := []struct {
+		name                   string
+		clangCFlags            []string
+		BuildBrokenClangCFlags bool
+		err                    string
+	}{
+		{
+			name:        "error when clang_cflags is set",
+			clangCFlags: []string{"-a", "-b"},
+			err:         "clang_cflags: property is deprecated",
+		},
+		{
+			name:                   "no error when BuildBrokenClangCFlags is explicitly set to true",
+			clangCFlags:            []string{"-a", "-b"},
+			BuildBrokenClangCFlags: true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			bp := fmt.Sprintf(`
+			cc_library {
+			   name: "foo",
+			   clang_cflags: %s,
+			}`, `["`+strings.Join(test.clangCFlags, `","`)+`"]`)
+
+			if test.err == "" {
+				android.GroupFixturePreparers(
+					prepareForCcTest,
+					android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+						if test.BuildBrokenClangCFlags {
+							variables.BuildBrokenClangCFlags = test.BuildBrokenClangCFlags
+						}
+					}),
+				).RunTestWithBp(t, bp)
+			} else {
+				prepareForCcTest.
+					ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(test.err)).
+					RunTestWithBp(t, bp)
+			}
+		})
+	}
+}
diff --git a/cc/compiler.go b/cc/compiler.go
index f9f7b6f..a751754 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -441,12 +441,24 @@
 	// TODO: debug
 	flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Release.Cflags)...)
 
-	CheckBadCompilerFlags(ctx, "clang_cflags", compiler.Properties.Clang_cflags)
-	CheckBadCompilerFlags(ctx, "clang_asflags", compiler.Properties.Clang_asflags)
+	if !ctx.DeviceConfig().BuildBrokenClangCFlags() && len(compiler.Properties.Clang_cflags) != 0 {
+		ctx.PropertyErrorf("clang_cflags", "property is deprecated, see Changes.md file")
+	} else {
+		CheckBadCompilerFlags(ctx, "clang_cflags", compiler.Properties.Clang_cflags)
+	}
+	if !ctx.DeviceConfig().BuildBrokenClangAsFlags() && len(compiler.Properties.Clang_asflags) != 0 {
+		ctx.PropertyErrorf("clang_asflags", "property is deprecated, see Changes.md file")
+	} else {
+		CheckBadCompilerFlags(ctx, "clang_asflags", compiler.Properties.Clang_asflags)
+	}
 
 	flags.Local.CFlags = config.ClangFilterUnknownCflags(flags.Local.CFlags)
-	flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Clang_cflags)...)
-	flags.Local.AsFlags = append(flags.Local.AsFlags, esc(compiler.Properties.Clang_asflags)...)
+	if !ctx.DeviceConfig().BuildBrokenClangCFlags() {
+		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Clang_cflags)...)
+	}
+	if !ctx.DeviceConfig().BuildBrokenClangAsFlags() {
+		flags.Local.AsFlags = append(flags.Local.AsFlags, esc(compiler.Properties.Clang_asflags)...)
+	}
 	flags.Local.CppFlags = config.ClangFilterUnknownCflags(flags.Local.CppFlags)
 	flags.Local.ConlyFlags = config.ClangFilterUnknownCflags(flags.Local.ConlyFlags)
 	flags.Local.LdFlags = config.ClangFilterUnknownCflags(flags.Local.LdFlags)
diff --git a/cc/gen.go b/cc/gen.go
index 08b49c9..dfbb177 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -229,6 +229,34 @@
 	return cppFile, headers.Paths()
 }
 
+func bp2buildCcSysprop(ctx android.Bp2buildMutatorContext, moduleName string, minSdkVersion *string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
+	labels := SyspropLibraryLabels{
+		SyspropLibraryLabel: moduleName + "_sysprop_library",
+		StaticLibraryLabel:  moduleName + "_cc_sysprop_library_static",
+	}
+	Bp2buildSysprop(ctx, labels, srcs, minSdkVersion)
+	return createLabelAttributeCorrespondingToSrcs(":"+labels.StaticLibraryLabel, srcs)
+}
+
+// Creates a LabelAttribute for a given label where the value is only set for
+// the same config values that have values in a given LabelListAttribute
+func createLabelAttributeCorrespondingToSrcs(baseLabelName string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
+	baseLabel := bazel.Label{Label: baseLabelName}
+	label := bazel.LabelAttribute{}
+	if !srcs.Value.IsNil() && !srcs.Value.IsEmpty() {
+		label.Value = &baseLabel
+		return &label
+	}
+	for axis, configToSrcs := range srcs.ConfigurableValues {
+		for config, val := range configToSrcs {
+			if !val.IsNil() && !val.IsEmpty() {
+				label.SetSelectValue(axis, config, baseLabel)
+			}
+		}
+	}
+	return &label
+}
+
 // Used to communicate information from the genSources method back to the library code that uses
 // it.
 type generatedSourceInfo struct {
diff --git a/cc/library.go b/cc/library.go
index 83a2c68..56534a6 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -2704,6 +2704,7 @@
 		modType = "cc_library_static"
 	} else {
 		modType = "cc_library_shared"
+		createStubsBazelTargetIfNeeded(ctx, module, compilerAttrs, exportedIncludes, baseAttributes)
 	}
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class:        modType,
@@ -2711,8 +2712,6 @@
 	}
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
-
-	createStubsBazelTargetIfNeeded(ctx, module, compilerAttrs, exportedIncludes, baseAttributes)
 }
 
 // TODO(b/199902614): Can this be factored to share with the other Attributes?
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5e06948..08e2a39 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -147,16 +147,6 @@
 	}
 }
 
-const (
-	apiContributionSuffix = ".contribution"
-)
-
-// apiContributionTargetName returns the name of the cc_api(headers|contribution) bp2build target of ndk modules
-// A suffix is necessary to prevent a name collision with the base ndk_(library|header) target in the same bp2build bazel package
-func apiContributionTargetName(moduleName string) string {
-	return moduleName + apiContributionSuffix
-}
-
 // TODO(b/243196151): Populate `system` and `arch` metadata
 type bazelCcApiHeadersAttributes struct {
 	Hdrs        bazel.LabelListAttribute
@@ -179,7 +169,7 @@
 		Include_dir: include_dir,
 	}
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: apiContributionTargetName(ctx.ModuleName()),
+		Name: android.ApiContributionTargetName(ctx.ModuleName()),
 	}, attrs)
 }
 
diff --git a/cc/sysprop.go b/cc/sysprop.go
new file mode 100644
index 0000000..2b1e354
--- /dev/null
+++ b/cc/sysprop.go
@@ -0,0 +1,71 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+	"android/soong/bazel"
+)
+
+// TODO(b/240463568): Additional properties will be added for API validation
+type bazelSyspropLibraryAttributes struct {
+	Srcs bazel.LabelListAttribute
+}
+
+type bazelCcSyspropLibraryAttributes struct {
+	Dep             bazel.LabelAttribute
+	Min_sdk_version *string
+}
+
+type SyspropLibraryLabels struct {
+	SyspropLibraryLabel string
+	SharedLibraryLabel  string
+	StaticLibraryLabel  string
+}
+
+func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "sysprop_library",
+			Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
+		},
+		android.CommonAttributes{Name: labels.SyspropLibraryLabel},
+		&bazelSyspropLibraryAttributes{
+			Srcs: srcs,
+		})
+
+	attrs := &bazelCcSyspropLibraryAttributes{
+		Dep:             *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
+		Min_sdk_version: minSdkVersion,
+	}
+
+	if labels.SharedLibraryLabel != "" {
+		ctx.CreateBazelTargetModule(
+			bazel.BazelTargetModuleProperties{
+				Rule_class:        "cc_sysprop_library_shared",
+				Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
+			},
+			android.CommonAttributes{Name: labels.SharedLibraryLabel},
+			attrs)
+	}
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "cc_sysprop_library_static",
+			Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
+		},
+		android.CommonAttributes{Name: labels.StaticLibraryLabel},
+		attrs)
+}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 8e1e565..f5b5f99 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -257,7 +257,7 @@
 	// Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the
 	// module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a
 	// versioned sdk.
-	produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
+	produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
 
 	// produceBootImageFiles will attempt to produce rules to create the boot image files at the paths
 	// predefined in the bootImageConfig.
@@ -759,7 +759,7 @@
 
 	// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
 	common := ctx.Module().(commonBootclasspathFragment)
-	output := common.produceHiddenAPIOutput(ctx, contents, input)
+	output := common.produceHiddenAPIOutput(ctx, contents, fragments, input)
 
 	// If the source or prebuilts module does not provide a signature patterns file then generate one
 	// from the flags.
@@ -767,7 +767,7 @@
 	//  their own.
 	if output.SignaturePatternsPath == nil {
 		output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
-			ctx, output.AllFlagsPath, []string{"*"}, nil, nil)
+			ctx, output.AllFlagsPath, []string{"*"}, nil, nil, "")
 	}
 
 	// Initialize a HiddenAPIInfo structure.
@@ -841,12 +841,12 @@
 	return b.testFragment
 }
 
-// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files)
-// for the fragment as well as encoding the flags in the boot dex jars.
-func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+// generateHiddenApiFlagRules generates rules to generate hidden API flags and compute the signature
+// patterns file.
+func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput {
 	// Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
 	// paths to the created files.
-	output := hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
+	flagOutput := hiddenAPIFlagRulesForBootclasspathFragment(ctx, bootDexInfoByModule, contents, input, suffix)
 
 	// If the module specifies split_packages or package_prefixes then use those to generate the
 	// signature patterns.
@@ -854,8 +854,8 @@
 	packagePrefixes := input.PackagePrefixes
 	singlePackages := input.SinglePackages
 	if splitPackages != nil || packagePrefixes != nil || singlePackages != nil {
-		output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
-			ctx, output.AllFlagsPath, splitPackages, packagePrefixes, singlePackages)
+		flagOutput.SignaturePatternsPath = buildRuleSignaturePatternsFile(
+			ctx, flagOutput.AllFlagsPath, splitPackages, packagePrefixes, singlePackages, suffix)
 	} else if !b.isTestFragment() {
 		ctx.ModuleErrorf(`Must specify at least one of the split_packages, package_prefixes and single_packages properties
   If this is a new bootclasspath_fragment or you are unsure what to do add the
@@ -867,6 +867,68 @@
   should specify here. If you are happy with its suggestions then you can add
   the --fix option and it will fix them for you.`, b.BaseModuleName())
 	}
+	return flagOutput
+}
+
+// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files)
+// for the fragment as well as encoding the flags in the boot dex jars.
+func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+	// Gather information about the boot dex files for the boot libraries provided by this fragment.
+	bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
+
+	// Generate the flag file needed to encode into the dex files.
+	flagOutput := b.generateHiddenApiFlagRules(ctx, contents, input, bootDexInfoByModule, "")
+
+	// Encode those flags into the dex files of the contents of this fragment.
+	encodedBootDexFilesByModule := hiddenAPIEncodeRulesForBootclasspathFragment(ctx, bootDexInfoByModule, flagOutput.AllFlagsPath)
+
+	// Store that information for return for use by other rules.
+	output := &HiddenAPIOutput{
+		HiddenAPIFlagOutput:         flagOutput,
+		EncodedBootDexFilesByModule: encodedBootDexFilesByModule,
+	}
+
+	// Get the ApiLevel associated with SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE, defaulting to current
+	// if not set.
+	config := ctx.Config()
+	targetApiLevel := android.ApiLevelOrPanic(ctx,
+		config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", "current"))
+
+	// Filter the contents list to remove any modules that do not support the target build release.
+	// The current build release supports all the modules.
+	contentsForSdkSnapshot := []android.Module{}
+	for _, module := range contents {
+		// If the module has a min_sdk_version that is higher than the target build release then it will
+		// not work on the target build release and so must not be included in the sdk snapshot.
+		minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, module)
+		if minApiLevel.GreaterThan(targetApiLevel) {
+			continue
+		}
+
+		contentsForSdkSnapshot = append(contentsForSdkSnapshot, module)
+	}
+
+	var flagFilesByCategory FlagFilesByCategory
+	if len(contentsForSdkSnapshot) != len(contents) {
+		// The sdk snapshot has different contents to the runtime fragment so it is not possible to
+		// reuse the hidden API information generated for the fragment. So, recompute that information
+		// for the sdk snapshot.
+		filteredInput := b.createHiddenAPIFlagInput(ctx, contentsForSdkSnapshot, fragments)
+
+		// Gather information about the boot dex files for the boot libraries provided by this fragment.
+		filteredBootDexInfoByModule := extractBootDexInfoFromModules(ctx, contentsForSdkSnapshot)
+		flagOutput = b.generateHiddenApiFlagRules(ctx, contentsForSdkSnapshot, filteredInput, filteredBootDexInfoByModule, "-for-sdk-snapshot")
+		flagFilesByCategory = filteredInput.FlagFilesByCategory
+	} else {
+		// The sdk snapshot has the same contents as the runtime fragment so reuse that information.
+		flagFilesByCategory = input.FlagFilesByCategory
+	}
+
+	// Make the information available for the sdk snapshot.
+	ctx.SetProvider(HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
+		FlagFilesByCategory: flagFilesByCategory,
+		HiddenAPIFlagOutput: flagOutput,
+	})
 
 	return output
 }
@@ -1032,7 +1094,7 @@
 
 	// Get the hidden API information from the module.
 	mctx := ctx.SdkModuleContext()
-	hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoProvider).(HiddenAPIInfo)
+	hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoForSdkProvider).(HiddenAPIInfoForSdk)
 	b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
 
 	// Copy all the generated file paths.
@@ -1174,7 +1236,7 @@
 }
 
 // produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
-func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
 	pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path {
 		if src == nil {
 			return defaultPath
diff --git a/java/dex.go b/java/dex.go
index a44d792..2b78703 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -200,6 +200,16 @@
 			"--verbose")
 	}
 
+	// Supplying the platform build flag disables various features like API modeling and desugaring.
+	// For targets with a stable min SDK version (i.e., when the min SDK is both explicitly specified
+	// and managed+versioned), we suppress this flag to ensure portability.
+	// Note: Targets with a min SDK kind of core_platform (e.g., framework.jar) or unspecified (e.g.,
+	// services.jar), are not classified as stable, which is WAI.
+	// TODO(b/232073181): Expand to additional min SDK cases after validation.
+	if !minSdkVersion.Stable() {
+		flags = append(flags, "--android-platform-build")
+	}
+
 	effectiveVersion, err := minSdkVersion.EffectiveVersion(ctx)
 	if err != nil {
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
diff --git a/java/dex_test.go b/java/dex_test.go
index a3e2ded..6617873 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -30,6 +30,19 @@
 			platform_apis: true,
 		}
 
+		android_app {
+			name: "stable_app",
+			srcs: ["foo.java"],
+			sdk_version: "current",
+			min_sdk_version: "31",
+		}
+
+		android_app {
+			name: "core_platform_app",
+			srcs: ["foo.java"],
+			sdk_version: "core_platform",
+		}
+
 		java_library {
 			name: "lib",
 			srcs: ["foo.java"],
@@ -42,11 +55,15 @@
 	`)
 
 	app := result.ModuleForTests("app", "android_common")
+	stableApp := result.ModuleForTests("stable_app", "android_common")
+	corePlatformApp := result.ModuleForTests("core_platform_app", "android_common")
 	lib := result.ModuleForTests("lib", "android_common")
 	staticLib := result.ModuleForTests("static_lib", "android_common")
 
 	appJavac := app.Rule("javac")
 	appR8 := app.Rule("r8")
+	stableAppR8 := stableApp.Rule("r8")
+	corePlatformAppR8 := corePlatformApp.Rule("r8")
 	libHeader := lib.Output("turbine-combined/lib.jar").Output
 	staticLibHeader := staticLib.Output("turbine-combined/static_lib.jar").Output
 
@@ -61,6 +78,12 @@
 		appR8.Args["r8Flags"], staticLibHeader.String())
 	android.AssertStringDoesContain(t, "expected -ignorewarnings in app r8 flags",
 		appR8.Args["r8Flags"], "-ignorewarnings")
+	android.AssertStringDoesContain(t, "expected --android-platform-build in app r8 flags",
+		appR8.Args["r8Flags"], "--android-platform-build")
+	android.AssertStringDoesNotContain(t, "expected no --android-platform-build in stable_app r8 flags",
+		stableAppR8.Args["r8Flags"], "--android-platform-build")
+	android.AssertStringDoesContain(t, "expected --android-platform-build in core_platform_app r8 flags",
+		corePlatformAppR8.Args["r8Flags"], "--android-platform-build")
 }
 
 func TestR8Flags(t *testing.T) {
@@ -88,7 +111,8 @@
 		appR8.Args["r8Flags"], "-dontobfuscate")
 	android.AssertStringDoesNotContain(t, "expected no -ignorewarnings in app r8 flags",
 		appR8.Args["r8Flags"], "-ignorewarnings")
-
+	android.AssertStringDoesContain(t, "expected --android-platform-build in app r8 flags",
+		appR8.Args["r8Flags"], "--android-platform-build")
 }
 
 func TestD8(t *testing.T) {
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 7b67803..5474ae1 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -594,6 +594,23 @@
 
 var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
 
+// HiddenAPIInfoForSdk contains information provided by the hidden API processing for use
+// by the sdk snapshot.
+//
+// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
+// processing.
+type HiddenAPIInfoForSdk struct {
+	// FlagFilesByCategory maps from the flag file category to the paths containing information for
+	// that category.
+	FlagFilesByCategory FlagFilesByCategory
+
+	// The output from the hidden API processing needs to be made available to other modules.
+	HiddenAPIFlagOutput
+}
+
+// Provides hidden API info for the sdk snapshot.
+var HiddenAPIInfoForSdkProvider = blueprint.NewProvider(HiddenAPIInfoForSdk{})
+
 // ModuleStubDexJars contains the stub dex jars provided by a single module.
 //
 // It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See
@@ -1024,8 +1041,11 @@
 // patterns that will select a subset of the monolithic flags.
 func buildRuleSignaturePatternsFile(
 	ctx android.ModuleContext, flagsPath android.Path,
-	splitPackages []string, packagePrefixes []string, singlePackages []string) android.Path {
-	patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
+	splitPackages []string, packagePrefixes []string, singlePackages []string,
+	suffix string) android.Path {
+	hiddenApiSubDir := "modular-hiddenapi" + suffix
+
+	patternsFile := android.PathForModuleOut(ctx, hiddenApiSubDir, "signature-patterns.csv")
 	// Create a rule to validate the output from the following rule.
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -1042,7 +1062,7 @@
 		FlagForEachArg("--package-prefix ", packagePrefixes).
 		FlagForEachArg("--single-package ", singlePackages).
 		FlagWithOutput("--output ", patternsFile)
-	rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
+	rule.Build("hiddenAPISignaturePatterns"+suffix, "hidden API signature patterns"+suffix)
 
 	return patternsFile
 }
@@ -1116,8 +1136,8 @@
 	return validFile
 }
 
-// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
-// bootclasspath and then encode the flags into the boot dex files.
+// hiddenAPIFlagRulesForBootclasspathFragment will generate all the flags for a fragment of the
+// bootclasspath.
 //
 // It takes:
 // * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
@@ -1130,31 +1150,27 @@
 // * metadata.csv
 // * index.csv
 // * all-flags.csv
-// * encoded boot dex files
-func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
-	hiddenApiSubDir := "modular-hiddenapi"
-
-	// Gather information about the boot dex files for the boot libraries provided by this fragment.
-	bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
+func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput {
+	hiddenApiSubDir := "modular-hiddenapi" + suffix
 
 	// Generate the stub-flags.csv.
 	stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
-	buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
+	buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile"+suffix, "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
 
 	// Extract the classes jars from the contents.
 	classesJars := extractClassesJarsFromModules(contents)
 
 	// Generate the set of flags from the annotations in the source code.
 	annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
-	buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
+	buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags"+suffix, classesJars, stubFlagsCSV, annotationFlagsCSV)
 
 	// Generate the metadata from the annotations in the source code.
 	metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
-	buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
+	buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata"+suffix, classesJars, stubFlagsCSV, metadataCSV)
 
 	// Generate the index file from the CSV files in the classes jars.
 	indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
-	buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
+	buildRuleToGenerateIndex(ctx, "modular hiddenapi index"+suffix, classesJars, indexCSV)
 
 	// Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files
 	// containing dex signatures of all the removed APIs. In the monolithic files that is done by
@@ -1162,15 +1178,44 @@
 	// signatures, see the combined-removed-dex module. This does that automatically by using the
 	// *removed.txt files retrieved from the java_sdk_library modules that are specified in the
 	// stub_libs and contents properties of a bootclasspath_fragment.
-	removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
+	removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, suffix, input.RemovedTxtFiles)
 
 	// Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
 	// files.
 	allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
-	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
+	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags"+suffix, "modular hiddenapi all flags"+suffix, allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
 
+	// Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
+	// compared against the monolithic stub flags.
+	filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
+	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags"+suffix,
+		"modular hiddenapi filtered stub flags"+suffix, stubFlagsCSV, filteredStubFlagsCSV,
+		HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
+
+	// Generate the filtered-flags.csv file which contains the filtered flags that will be compared
+	// against the monolithic flags.
+	filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
+	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags"+suffix,
+		"modular hiddenapi filtered flags"+suffix, allFlagsCSV, filteredFlagsCSV,
+		HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
+
+	// Store the paths in the info for use by other modules and sdk snapshot generation.
+	return HiddenAPIFlagOutput{
+		AnnotationFlagsPath:   annotationFlagsCSV,
+		MetadataPath:          metadataCSV,
+		IndexPath:             indexCSV,
+		StubFlagsPath:         stubFlagsCSV,
+		AllFlagsPath:          allFlagsCSV,
+		FilteredStubFlagsPath: filteredStubFlagsCSV,
+		FilteredFlagsPath:     filteredFlagsCSV,
+	}
+}
+
+// hiddenAPIEncodeRulesForBootclasspathFragment generates rules to encode hidden API flags into the
+// dex jars in bootDexInfoByModule.
+func hiddenAPIEncodeRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, allFlagsCSV android.Path) bootDexJarByModule {
 	// Encode the flags into the boot dex files.
-	encodedBootDexJarsByModule := map[string]android.Path{}
+	encodedBootDexJarsByModule := bootDexJarByModule{}
 	outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
 	for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
 		bootDexInfo := bootDexInfoByModule[name]
@@ -1178,43 +1223,15 @@
 		encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir)
 		encodedBootDexJarsByModule[name] = encodedDex
 	}
-
-	// Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
-	// compared against the monolithic stub flags.
-	filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
-	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags",
-		"modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV,
-		HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
-
-	// Generate the filtered-flags.csv file which contains the filtered flags that will be compared
-	// against the monolithic flags.
-	filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
-	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags",
-		"modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV,
-		HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
-
-	// Store the paths in the info for use by other modules and sdk snapshot generation.
-	output := HiddenAPIOutput{
-		HiddenAPIFlagOutput: HiddenAPIFlagOutput{
-			AnnotationFlagsPath:   annotationFlagsCSV,
-			MetadataPath:          metadataCSV,
-			IndexPath:             indexCSV,
-			StubFlagsPath:         stubFlagsCSV,
-			AllFlagsPath:          allFlagsCSV,
-			FilteredStubFlagsPath: filteredStubFlagsCSV,
-			FilteredFlagsPath:     filteredFlagsCSV,
-		},
-		EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
-	}
-	return &output
+	return encodedBootDexJarsByModule
 }
 
-func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
+func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix string, removedTxtFiles android.Paths) android.OptionalPath {
 	if len(removedTxtFiles) == 0 {
 		return android.OptionalPath{}
 	}
 
-	output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
+	output := android.PathForModuleOut(ctx, "module-hiddenapi"+suffix, "removed-dex-signatures.txt")
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
@@ -1222,7 +1239,7 @@
 		Flag("--no-banner").
 		Inputs(removedTxtFiles).
 		FlagWithOutput("--dex-api ", output)
-	rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
+	rule.Build("modular-hiddenapi-removed-dex-signatures"+suffix, "modular hiddenapi removed dex signatures"+suffix)
 	return android.OptionalPathForPath(output)
 }
 
diff --git a/python/python.go b/python/python.go
index 8364169..daf7c14 100644
--- a/python/python.go
+++ b/python/python.go
@@ -120,6 +120,15 @@
 	// whether the binary is required to be built with embedded launcher for this actual_version.
 	// this is set by the python version mutator based on version-specific properties
 	Embedded_launcher *bool `blueprint:"mutated"`
+
+	Proto struct {
+		// Whether generated python protos should include the pkg_path in
+		// their import statements. This is a temporary flag to help transition to
+		// the new behavior where this is always true. It will be removed after all
+		// usages of protos with pkg_path have been updated. The default is currently
+		// false.
+		Respect_pkg_path *bool
+	}
 }
 
 type baseAttributes struct {
@@ -672,8 +681,26 @@
 		protoFlags := android.GetProtoFlags(ctx, &p.protoProperties)
 		protoFlags.OutTypeFlag = "--python_out"
 
+		// TODO(b/247578564): Change the default to true, and then eventually remove respect_pkg_path
+		protosRespectPkgPath := proptools.BoolDefault(p.properties.Proto.Respect_pkg_path, false)
+		pkgPathForProtos := pkgPath
+		if pkgPathForProtos != "" && protosRespectPkgPath {
+			pkgPathStagingDir := android.PathForModuleGen(ctx, "protos_staged_for_pkg_path")
+			rule := android.NewRuleBuilder(pctx, ctx)
+			var stagedProtoSrcs android.Paths
+			for _, srcFile := range protoSrcs {
+				stagedProtoSrc := pkgPathStagingDir.Join(ctx, pkgPath, srcFile.Rel())
+				rule.Command().Text("mkdir -p").Flag(filepath.Base(stagedProtoSrc.String()))
+				rule.Command().Text("cp -f").Input(srcFile).Output(stagedProtoSrc)
+				stagedProtoSrcs = append(stagedProtoSrcs, stagedProtoSrc)
+			}
+			rule.Build("stage_protos_for_pkg_path", "Stage protos for pkg_path")
+			protoSrcs = stagedProtoSrcs
+			pkgPathForProtos = ""
+		}
+
 		for _, srcFile := range protoSrcs {
-			zip := genProto(ctx, srcFile, protoFlags, pkgPath)
+			zip := genProto(ctx, srcFile, protoFlags, pkgPathForProtos)
 			zips = append(zips, zip)
 		}
 	}
diff --git a/python/tests/proto_pkg_path/Android.bp b/python/tests/proto_pkg_path/Android.bp
new file mode 100644
index 0000000..17afde2
--- /dev/null
+++ b/python/tests/proto_pkg_path/Android.bp
@@ -0,0 +1,13 @@
+python_test_host {
+    name: "py_proto_pkg_path_test",
+    main: "main.py",
+    srcs: [
+        "main.py",
+        "proto/*.proto",
+    ],
+    pkg_path: "mylib/subpackage",
+    proto: {
+        canonical_path_from_root: false,
+        respect_pkg_path: true,
+    },
+}
diff --git a/python/tests/proto_pkg_path/main.py b/python/tests/proto_pkg_path/main.py
new file mode 100644
index 0000000..c4acdde
--- /dev/null
+++ b/python/tests/proto_pkg_path/main.py
@@ -0,0 +1,18 @@
+import sys
+
+import unittest
+import mylib.subpackage.proto.test_pb2 as test_pb2
+import mylib.subpackage.proto.common_pb2 as common_pb2
+
+print(sys.path)
+
+class TestProtoWithPkgPath(unittest.TestCase):
+
+    def test_main(self):
+        x = test_pb2.MyMessage(name="foo",
+                               common = common_pb2.MyCommonMessage(common="common"))
+        self.assertEqual(x.name, "foo")
+        self.assertEqual(x.common.common, "common")
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/python/tests/proto_pkg_path/proto/common.proto b/python/tests/proto_pkg_path/proto/common.proto
new file mode 100644
index 0000000..b24b8ea
--- /dev/null
+++ b/python/tests/proto_pkg_path/proto/common.proto
@@ -0,0 +1,5 @@
+syntax = "proto3";
+
+message MyCommonMessage {
+  string common = 1;
+}
diff --git a/python/tests/proto_pkg_path/proto/test.proto b/python/tests/proto_pkg_path/proto/test.proto
new file mode 100644
index 0000000..55f3b17
--- /dev/null
+++ b/python/tests/proto_pkg_path/proto/test.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+
+import "mylib/subpackage/proto/common.proto";
+
+message MyMessage {
+  string name = 1;
+  MyCommonMessage common = 2;
+}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index b5b588b..5dd45cd 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -199,6 +199,17 @@
     ],
 }
 
+python_binary_host {
+    name: "build-apex-bundle",
+    main: "build-apex-bundle.py",
+    srcs: [
+        "build-apex-bundle.py",
+    ],
+    required: [
+        "bundletool",
+    ],
+}
+
 sh_binary_host {
     name: "list_image",
     src: "list_image.sh",
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 3f4f9c0..7b003fd 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,5 +1,4 @@
 per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
-per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
 per-file construct_context.py = ngeoffray@google.com,calin@google.com,skvadrik@google.com
 per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com
-per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
\ No newline at end of file
+per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
deleted file mode 100755
index 1a16f7c..0000000
--- a/scripts/build-aml-prebuilts.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash -e
-
-# This script is similar to "m" but builds in --soong-only mode, and handles
-# special cases to make that mode work. All arguments are passed on to
-# build/soong/soong_ui.bash.
-#
-# --soong-only bypasses the kati step and hence the make logic that e.g. doesn't
-# handle more than two device architectures. It is particularly intended for use
-# with TARGET_PRODUCT=mainline_sdk to build 'sdk' and 'module_export' Soong
-# modules in TARGET_ARCH_SUITE=mainline_sdk mode so that they get all four
-# device architectures (artifacts get installed in $OUT_DIR/soong/mainline-sdks
-# - cf PathForMainlineSdksInstall in android/paths.go).
-#
-# TODO(b/174315599): Replace this script completely with a 'soong_ui.bash
-# --soong-only' invocation. For now it is still necessary to set up
-# build_number.txt.
-
-if [ ! -e build/soong/soong_ui.bash ]; then
-  echo "$0 must be run from the top of the tree"
-  exit 1
-fi
-
-export OUT_DIR=${OUT_DIR:-out}
-
-if [ -e ${OUT_DIR}/soong/.soong.kati_enabled ]; then
-  # If ${OUT_DIR} has been created without --soong-only, Soong will create an
-  # ${OUT_DIR}/soong/build.ninja that leaves out many targets which are
-  # expected to be supplied by the .mk files, and that might cause errors in
-  # "m --soong-only" below. We therefore default to a different out dir
-  # location in that case.
-  AML_OUT_DIR=out/aml
-  echo "Avoiding in-make OUT_DIR '${OUT_DIR}' - building in '${AML_OUT_DIR}' instead"
-  OUT_DIR=${AML_OUT_DIR}
-fi
-
-mkdir -p ${OUT_DIR}/soong
-
-# The --dumpvars-mode invocation will run Soong in normal make mode where it
-# creates .soong.kati_enabled. That would clobber our real out directory, so we
-# need to use a different OUT_DIR.
-vars="$(OUT_DIR=${OUT_DIR}/dumpvars_mode build/soong/soong_ui.bash \
-        --dumpvars-mode --vars=BUILD_NUMBER)"
-# Assign to a variable and eval that, since bash ignores any error status
-# from the command substitution if it's directly on the eval line.
-eval $vars
-
-# Some Soong build rules may require this, and the failure mode if it's missing
-# is confusing (b/172548608).
-echo -n ${BUILD_NUMBER} > ${OUT_DIR}/soong/build_number.txt
-
-build/soong/soong_ui.bash --make-mode --soong-only "$@"
diff --git a/scripts/build-apex-bundle.py b/scripts/build-apex-bundle.py
new file mode 100644
index 0000000..dcdd9ef
--- /dev/null
+++ b/scripts/build-apex-bundle.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""A tool to create an APEX bundle out of Soong-built base.zip"""
+
+from __future__ import print_function
+
+import argparse
+import sys
+import tempfile
+import zipfile
+import os
+import json
+import subprocess
+
+
+def parse_args():
+  """Parse commandline arguments."""
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--overwrite',
+      action='store_true',
+      help='If set, any previous existing output will be overwritten')
+  parser.add_argument('--output', help='specify the output .aab file')
+  parser.add_argument(
+      'input', help='specify the input <apex name>-base.zip file')
+  return parser.parse_args()
+
+
+def build_bundle(input, output, overwrite):
+  base_zip = zipfile.ZipFile(input)
+
+  tmpdir = tempfile.mkdtemp()
+  tmp_base_zip = os.path.join(tmpdir, 'base.zip')
+  tmp_bundle_config = os.path.join(tmpdir, 'bundle_config.json')
+
+  bundle_config = None
+  abi = []
+
+  # This block performs three tasks
+  # - extract/load bundle_config.json from input => bundle_config
+  # - get ABI from input => abi
+  # - discard bundle_config.json from input => tmp/base.zip
+  with zipfile.ZipFile(tmp_base_zip, 'a') as out:
+    for info in base_zip.infolist():
+
+      # discard bundle_config.json
+      if info.filename == 'bundle_config.json':
+        bundle_config = json.load(base_zip.open(info.filename))
+        continue
+
+      # get ABI from apex/{abi}.img
+      dir, basename = os.path.split(info.filename)
+      name, ext = os.path.splitext(basename)
+      if dir == 'apex' and ext == '.img':
+        abi.append(name)
+
+      # copy entries to tmp/base.zip
+      out.writestr(info, base_zip.open(info.filename).read())
+
+  base_zip.close()
+
+  if not bundle_config:
+    raise ValueError(f'bundle_config.json not found in {input}')
+  if len(abi) != 1:
+    raise ValueError(f'{input} should have only a single apex/*.img file')
+
+  # add ABI to tmp/bundle_config.json
+  apex_config = bundle_config['apex_config']
+  if 'supported_abi_set' not in apex_config:
+    apex_config['supported_abi_set'] = []
+  supported_abi_set = apex_config['supported_abi_set']
+  supported_abi_set.append({'abi': abi})
+
+  with open(tmp_bundle_config, 'w') as out:
+    json.dump(bundle_config, out)
+
+  # invoke bundletool
+  cmd = [
+      'bundletool', 'build-bundle', '--config', tmp_bundle_config, '--modules',
+      tmp_base_zip, '--output', output
+  ]
+  if overwrite:
+    cmd.append('--overwrite')
+  subprocess.check_call(cmd)
+
+
+def main():
+  """Program entry point."""
+  try:
+    args = parse_args()
+    build_bundle(args.input, args.output, args.overwrite)
+
+  # pylint: disable=broad-except
+  except Exception as err:
+    print('error: ' + str(err), file=sys.stderr)
+    sys.exit(-1)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index c93055a..4be0ace 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -895,3 +895,222 @@
 		snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
 	)
 }
+
+func testSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T, targetBuildRelease string,
+	expectedSdkSnapshot string,
+	expectedCopyRules string,
+	expectedStubFlagsInputs []string,
+	suffix string) {
+
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("mysdklibrary", "mynewsdklibrary"),
+		java.FixtureConfigureApexBootJars("myapex:mysdklibrary", "myapex:mynewsdklibrary"),
+		prepareForSdkTestWithApex,
+
+		// Add a platform_bootclasspath that depends on the fragment.
+		fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
+
+		android.FixtureMergeEnv(map[string]string{
+			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
+		}),
+
+		android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				apexes: ["myapex"],
+			}
+
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				min_sdk_version: "S",
+				bootclasspath_fragments: ["mybootclasspathfragment"],
+			}
+
+			bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				apex_available: ["myapex"],
+				contents: [
+					"mysdklibrary",
+					"mynewsdklibrary",
+				],
+
+				hidden_api: {
+					split_packages: [],
+				},
+			}
+
+			java_sdk_library {
+				name: "mysdklibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				shared_library: false,
+				public: {enabled: true},
+				min_sdk_version: "S",
+			}
+
+			java_sdk_library {
+				name: "mynewsdklibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				compile_dex: true,
+				public: {enabled: true},
+				min_sdk_version: "Tiramisu",
+				permitted_packages: ["mynewsdklibrary"],
+			}
+		`),
+	).RunTest(t)
+
+	bcpf := result.ModuleForTests("mybootclasspathfragment", "android_common")
+	rule := bcpf.Output("out/soong/.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi" + suffix + "/stub-flags.csv")
+	android.AssertPathsRelativeToTopEquals(t, "stub flags inputs", expectedStubFlagsInputs, rule.Implicits)
+
+	CheckSnapshot(t, result, "mysdk", "",
+		checkAndroidBpContents(expectedSdkSnapshot),
+		checkAllCopyRules(expectedCopyRules),
+	)
+}
+
+func TestSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T) {
+	t.Run("target S build", func(t *testing.T) {
+		expectedSnapshot := `
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_bootclasspath_fragment {
+    name: "mybootclasspathfragment",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    contents: ["mysdklibrary"],
+    hidden_api: {
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        stub_flags: "hiddenapi/stub-flags.csv",
+        all_flags: "hiddenapi/all-flags.csv",
+    },
+}
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+`
+		expectedCopyRules := `
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/stub-flags.csv -> hiddenapi/stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+`
+
+		// On S the stub flags should only be generated from mysdklibrary as mynewsdklibrary is not part
+		// of the snapshot.
+		expectedStubFlagsInputs := []string{
+			"out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar",
+			"out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar",
+		}
+
+		testSnapshotWithBootClasspathFragment_MinSdkVersion(t, "S",
+			expectedSnapshot, expectedCopyRules, expectedStubFlagsInputs, "-for-sdk-snapshot")
+	})
+
+	t.Run("target-Tiramisu-build", func(t *testing.T) {
+		expectedSnapshot := `
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_bootclasspath_fragment {
+    name: "mybootclasspathfragment",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    contents: [
+        "mysdklibrary",
+        "mynewsdklibrary",
+    ],
+    hidden_api: {
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        signature_patterns: "hiddenapi/signature-patterns.csv",
+        filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        filtered_flags: "hiddenapi/filtered-flags.csv",
+    },
+}
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+
+java_sdk_library_import {
+    name: "mynewsdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: true,
+    compile_dex: true,
+    permitted_packages: ["mynewsdklibrary"],
+    public: {
+        jars: ["sdk_library/public/mynewsdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mynewsdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mynewsdklibrary.txt",
+        removed_api: "sdk_library/public/mynewsdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+`
+		expectedCopyRules := `
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mynewsdklibrary.stubs/android_common/javac/mynewsdklibrary.stubs.jar -> sdk_library/public/mynewsdklibrary-stubs.jar
+.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_api.txt -> sdk_library/public/mynewsdklibrary.txt
+.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_removed.txt -> sdk_library/public/mynewsdklibrary-removed.txt
+`
+
+		// On tiramisu the stub flags should be generated from both mynewsdklibrary and mysdklibrary as
+		// they are both part of the snapshot.
+		expectedStubFlagsInputs := []string{
+			"out/soong/.intermediates/mynewsdklibrary.stubs/android_common/dex/mynewsdklibrary.stubs.jar",
+			"out/soong/.intermediates/mynewsdklibrary/android_common/aligned/mynewsdklibrary.jar",
+			"out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar",
+			"out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar",
+		}
+
+		testSnapshotWithBootClasspathFragment_MinSdkVersion(t, "Tiramisu",
+			expectedSnapshot, expectedCopyRules, expectedStubFlagsInputs, "")
+	})
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 7ab5285..d598834 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -1004,7 +1004,7 @@
 		java_sdk_library {
 			name: "myjavalib",
 			srcs: ["Test.java"],
-			sdk_version: "current",
+			sdk_version: "S",
 			shared_library: false,
 			annotations_enabled: true,
 			public: {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 1ec12c3..8b8e1d7 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -482,6 +482,7 @@
 				name: "mysdklibrary",
 				srcs: ["Test.java"],
 				compile_dex: true,
+				sdk_version: "S",
 				public: {enabled: true},
 				permitted_packages: ["mysdklibrary"],
 			}
diff --git a/sdk/update.go b/sdk/update.go
index 5c9376b..81f3672 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -211,11 +211,14 @@
 				container = parent.(android.SdkAware)
 			}
 
+			minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, child)
+
 			export := memberTag.ExportMember()
 			s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
 				sdkVariant:             s,
 				memberType:             memberType,
 				variant:                child.(android.SdkAware),
+				minApiLevel:            minApiLevel,
 				container:              container,
 				export:                 export,
 				exportedComponentsInfo: exportedComponentsInfo,
@@ -332,10 +335,28 @@
 //         <arch>/lib/
 //            libFoo.so   : a stub library
 
+func (s sdk) targetBuildRelease(ctx android.ModuleContext) *buildRelease {
+	config := ctx.Config()
+	targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", buildReleaseCurrent.name)
+	targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv)
+	if err != nil {
+		ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err)
+		targetBuildRelease = buildReleaseCurrent
+	}
+
+	return targetBuildRelease
+}
+
 // buildSnapshot is the main function in this source file. It creates rules to copy
 // the contents (header files, stub libraries, etc) into the zip file.
 func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) {
 
+	targetBuildRelease := s.targetBuildRelease(ctx)
+	targetApiLevel, err := android.ApiLevelFromUser(ctx, targetBuildRelease.name)
+	if err != nil {
+		targetApiLevel = android.FutureApiLevel
+	}
+
 	// Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
 	hasLicenses := false
 	var memberVariantDeps []sdkMemberVariantDep
@@ -346,12 +367,18 @@
 	// Filter out any sdkMemberVariantDep that is a component of another.
 	memberVariantDeps = filterOutComponents(ctx, memberVariantDeps)
 
-	// Record the names of all the members, both explicitly specified and implicitly
-	// included.
+	// Record the names of all the members, both explicitly specified and implicitly included. Also,
+	// record the names of any members that should be excluded from this snapshot.
 	allMembersByName := make(map[string]struct{})
 	exportedMembersByName := make(map[string]struct{})
+	excludedMembersByName := make(map[string]struct{})
 
-	addMember := func(name string, export bool) {
+	addMember := func(name string, export bool, exclude bool) {
+		if exclude {
+			excludedMembersByName[name] = struct{}{}
+			return
+		}
+
 		allMembersByName[name] = struct{}{}
 		if export {
 			exportedMembersByName[name] = struct{}{}
@@ -362,11 +389,15 @@
 		name := memberVariantDep.variant.Name()
 		export := memberVariantDep.export
 
-		addMember(name, export)
+		// If the minApiLevel of the member is greater than the target API level then exclude it from
+		// this snapshot.
+		exclude := memberVariantDep.minApiLevel.GreaterThan(targetApiLevel)
+
+		addMember(name, export, exclude)
 
 		// Add any components provided by the module.
 		for _, component := range memberVariantDep.exportedComponentsInfo.Components {
-			addMember(component, export)
+			addMember(component, export, exclude)
 		}
 
 		if memberVariantDep.memberType == android.LicenseModuleSdkMemberType {
@@ -382,18 +413,9 @@
 		modules: make(map[string]*bpModule),
 	}
 
-	config := ctx.Config()
-
 	// Always add -current to the end
 	snapshotFileSuffix := "-current"
 
-	targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", buildReleaseCurrent.name)
-	targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv)
-	if err != nil {
-		ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err)
-		targetBuildRelease = buildReleaseCurrent
-	}
-
 	builder := &snapshotBuilder{
 		ctx:                   ctx,
 		sdk:                   s,
@@ -404,6 +426,7 @@
 		prebuiltModules:       make(map[string]*bpModule),
 		allMembersByName:      allMembersByName,
 		exportedMembersByName: exportedMembersByName,
+		excludedMembersByName: excludedMembersByName,
 		targetBuildRelease:    targetBuildRelease,
 	}
 	s.builderForTests = builder
@@ -437,6 +460,10 @@
 		}
 
 		name := member.name
+		if _, ok := excludedMembersByName[name]; ok {
+			continue
+		}
+
 		requiredTraits := traits[name]
 		if requiredTraits == nil {
 			requiredTraits = android.EmptySdkMemberTraitSet()
@@ -1034,6 +1061,9 @@
 	// The set of exported members by name.
 	exportedMembersByName map[string]struct{}
 
+	// The set of members which have been excluded from this snapshot; by name.
+	excludedMembersByName map[string]struct{}
+
 	// The target build release for which the snapshot is to be generated.
 	targetBuildRelease *buildRelease
 
@@ -1218,6 +1248,9 @@
 func (s *snapshotBuilder) snapshotSdkMemberNames(members []string, required bool) []string {
 	var references []string = nil
 	for _, m := range members {
+		if _, ok := s.excludedMembersByName[m]; ok {
+			continue
+		}
 		references = append(references, s.snapshotSdkMemberName(m, required))
 	}
 	return references
@@ -1260,6 +1293,9 @@
 
 	// The names of additional component modules provided by the variant.
 	exportedComponentsInfo android.ExportedComponentsInfo
+
+	// The minimum API level on which this module is supported.
+	minApiLevel android.ApiLevel
 }
 
 var _ android.SdkMember = (*sdkMember)(nil)
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 578dc2b..1f0d28d 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -573,43 +573,14 @@
 }
 
 // TODO(b/240463568): Additional properties will be added for API validation
-type bazelSyspropLibraryAttributes struct {
-	Srcs bazel.LabelListAttribute
-}
-
-type bazelCcSyspropLibraryAttributes struct {
-	Dep             bazel.LabelAttribute
-	Min_sdk_version *string
-}
-
 func (m *syspropLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "sysprop_library",
-			Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
-		},
-		android.CommonAttributes{Name: m.Name()},
-		&bazelSyspropLibraryAttributes{
-			Srcs: bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)),
-		})
-
-	attrs := &bazelCcSyspropLibraryAttributes{
-		Dep:             *bazel.MakeLabelAttribute(":" + m.Name()),
-		Min_sdk_version: m.properties.Cpp.Min_sdk_version,
+	labels := cc.SyspropLibraryLabels{
+		SyspropLibraryLabel: m.BaseModuleName(),
+		SharedLibraryLabel:  m.CcImplementationModuleName(),
+		StaticLibraryLabel:  cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
 	}
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_sysprop_library_shared",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
-		},
-		android.CommonAttributes{Name: m.CcImplementationModuleName()},
-		attrs)
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_sysprop_library_static",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
-		},
-		android.CommonAttributes{Name: m.CcImplementationModuleName() + "_bp2build_cc_library_static"},
-		attrs)
+	cc.Bp2buildSysprop(ctx,
+		labels,
+		bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)),
+		m.properties.Cpp.Min_sdk_version)
 }
diff --git a/sysprop/sysprop_library_conversion_test.go b/sysprop/sysprop_library_conversion_test.go
index c72faf3..89adf7d 100644
--- a/sysprop/sysprop_library_conversion_test.go
+++ b/sysprop/sysprop_library_conversion_test.go
@@ -41,7 +41,7 @@
 `,
 		ExpectedBazelTargets: []string{
 			bp2build.MakeBazelTargetNoRestrictions("sysprop_library",
-				"sysprop_foo_sysprop_library",
+				"sysprop_foo",
 				bp2build.AttrNameToString{
 					"srcs": `[
         "foo.sysprop",
@@ -51,12 +51,12 @@
 			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_shared",
 				"libsysprop_foo",
 				bp2build.AttrNameToString{
-					"dep": `":sysprop_foo_sysprop_library"`,
+					"dep": `":sysprop_foo"`,
 				}),
 			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_static",
 				"libsysprop_foo_bp2build_cc_library_static",
 				bp2build.AttrNameToString{
-					"dep": `":sysprop_foo_sysprop_library"`,
+					"dep": `":sysprop_foo"`,
 				}),
 		},
 	})
@@ -86,7 +86,7 @@
 `,
 		ExpectedBazelTargets: []string{
 			bp2build.MakeBazelTargetNoRestrictions("sysprop_library",
-				"sysprop_foo_sysprop_library",
+				"sysprop_foo",
 				bp2build.AttrNameToString{
 					"srcs": `[
         "foo.sysprop",
@@ -96,13 +96,13 @@
 			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_shared",
 				"libsysprop_foo",
 				bp2build.AttrNameToString{
-					"dep":             `":sysprop_foo_sysprop_library"`,
+					"dep":             `":sysprop_foo"`,
 					"min_sdk_version": `"5"`,
 				}),
 			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_static",
 				"libsysprop_foo_bp2build_cc_library_static",
 				bp2build.AttrNameToString{
-					"dep":             `":sysprop_foo_sysprop_library"`,
+					"dep":             `":sysprop_foo"`,
 					"min_sdk_version": `"5"`,
 				}),
 		},