Merge "Add flag to not add top-level modules to PYTHONPATH"
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 cfaa1d4..f2b05dd 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -147,6 +147,7 @@
 		"external/mdnsresponder":                 Bp2BuildDefaultTrueRecursively,
 		"external/minijail":                      Bp2BuildDefaultTrueRecursively,
 		"external/openscreen":                    Bp2BuildDefaultTrueRecursively,
+		"external/objenesis":                     Bp2BuildDefaultTrueRecursively,
 		"external/pcre":                          Bp2BuildDefaultTrueRecursively,
 		"external/protobuf":                      Bp2BuildDefaultTrueRecursively,
 		"external/python/six":                    Bp2BuildDefaultTrueRecursively,
@@ -312,7 +313,7 @@
 		// build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive.
 		"build/make/tools":/* recursive = */ false,
 		"build/pesto":/* recursive = */ true,
-		"build/soong/ui/metrics/bp2build_progress_metrics_proto":/* recursive = */ true,
+		"build/soong":/* recursive = */ true,
 
 		// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
 		// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
@@ -323,6 +324,10 @@
 		"external/guava":/* recursive = */ true,
 		"external/jsr305":/* recursive = */ true,
 		"external/protobuf":/* recursive = */ false,
+
+		// this BUILD file is globbed by //external/icu/icu4c/source:icu4c_test_data's "data/**/*".
+		"external/icu/icu4c/source/data/unidata/norm2":/* recursive = */ false,
+
 		"frameworks/base/tools/codegen":/* recursive = */ true,
 		"frameworks/ex/common":/* recursive = */ true,
 
@@ -354,6 +359,7 @@
 		"com.android.media.swcodec-mediaswcodec.rc",
 		"com.android.media.swcodec.certificate",
 		"com.android.media.swcodec.key",
+		"com.android.neuralnetworks",
 		"com.android.neuralnetworks-androidManifest",
 		"com.android.neuralnetworks.certificate",
 		"com.android.neuralnetworks.key",
@@ -382,6 +388,7 @@
 		"libgrallocusage",
 		"libgralloctypes",
 		"libnativewindow",
+		"libneuralnetworks",
 		"libgraphicsenv",
 		"libhardware",
 		"libhardware_headers",
@@ -439,6 +446,8 @@
 		"philox_random",
 		"philox_random_headers",
 		"server_configurable_flags",
+		"statslog_neuralnetworks.cpp",
+		"statslog_neuralnetworks.h",
 		"tensorflow_headers",
 
 		"libgui_headers",
@@ -458,6 +467,10 @@
 		"libavb",
 		"avb_headers",
 
+		//external/libxml2
+		"xmllint",
+		"libxml2",
+
 		//external/fec
 		"libfec_rs",
 
@@ -547,17 +560,44 @@
 
 		//system/core/fs_mgr
 		"libfs_mgr",
+
+		"libcodec2_hidl@1.0",
+		"libcodec2_hidl@1.1",
+		"libcodec2_hidl@1.2",
+		"libcodec2_hidl_plugin_stub",
+		"libcodec2_hidl_plugin",
+		"libstagefright_bufferqueue_helper_novndk",
+		"libgui_bufferqueue_static",
+		"libGLESv2",
+		"libEGL",
+		"libcodec2_vndk",
+		"libnativeloader_lazy",
+		"libnativeloader",
+		"libEGL_getProcAddress",
+		"libEGL_blobCache",
+
+		"protoc-gen-cppstream",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
+		"aidl_interface_headers",
+		"api_domain",
 		"license",
 		"linker_config",
 		"java_import",
 		"java_import_host",
+		"ndk_headers",
+		"ndk_library",
 		"sysprop_library",
-		"aidl_interface_headers",
 	}
 
+	// Add the names of modules that bp2build should never convert, if it is
+	// in the package allowlist.  An error will be thrown if a module must
+	// not be here and in the alwaysConvert lists.
+	//
+	// For prebuilt modules (e.g. android_library_import), remember to add
+	// the "prebuilt_" prefix to the name, so that it's differentiable from
+	// the source versions within Soong's module graph.
 	Bp2buildModuleDoNotConvertList = []string{
 		// cc bugs
 		"libactivitymanager_aidl", // TODO(b/207426160): Unsupported use of aidl sources (via Dactivity_manager_procstate_aidl) in a cc_library
@@ -595,30 +635,26 @@
 		"prebuilt_car-ui-androidx-core-common",         // TODO(b/224773339), genrule dependency creates an .aar, not a .jar
 		"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
+		// ERROR: The dependencies for the following 1 jar(s) are not complete.
+		// 1.bazel-out/android_target-fastbuild/bin/prebuilts/tools/common/m2/_aar/robolectric-monitor-1.0.2-alpha1/classes_and_libs_merged.jar
+		"prebuilt_robolectric-monitor-1.0.2-alpha1",
 
 		// 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
 		"host-libprotobuf-java-full",       // TODO(b/210751803), we don't handle path property for filegroups
-		"libprotobuf-internal-protos",      // TODO(b/210751803), we don't handle path property for filegroups
 		"libprotobuf-internal-python-srcs", // TODO(b/210751803), we don't handle path property for filegroups
 		"libprotobuf-java-full",            // TODO(b/210751803), we don't handle path property for filegroups
 		"libprotobuf-java-util-full",       // TODO(b/210751803), we don't handle path property for filegroups
 		"auto_value_plugin_resources",      // TODO(b/210751803), we don't handle path property for filegroups
 
 		// go deps:
-		"aapt2-protos",                                                                               // depends on soong_zip, a go binary
-		"analyze_bcpf",                                                                               // depends on bpmodify a blueprint_go_binary.
-		"apex-protos",                                                                                // depends on soong_zip, a go binary
-		"generated_android_icu4j_src_files", "generated_android_icu4j_test_files", "icu4c_test_data", // depends on unconverted modules: soong_zip
-		"host_bionic_linker_asm",                                                  // depends on extract_linker, a go binary.
-		"host_bionic_linker_script",                                               // depends on extract_linker, a go binary.
-		"libc_musl_sysroot_bionic_arch_headers",                                   // depends on soong_zip
-		"libc_musl_sysroot_bionic_headers",                                        // 218405924, depends on soong_zip and generates duplicate srcs
-		"libc_musl_sysroot_libc++_headers", "libc_musl_sysroot_libc++abi_headers", // depends on soong_zip, zip2zip
-		"libc_musl_sysroot_zlib_headers", // depends on soong_zip and zip2zip
-		"robolectric-sqlite4java-native", // depends on soong_zip, a go binary
-		"robolectric_tzdata",             // depends on soong_zip, a go binary
+		"analyze_bcpf",              // depends on bpmodify a blueprint_go_binary.
+		"host_bionic_linker_asm",    // depends on extract_linker, a go binary.
+		"host_bionic_linker_script", // depends on extract_linker, a go binary.
+
+		// in cmd attribute of genrule rule //system/timezone/output_data:robolectric_tzdata: label '//system/timezone/output_data:iana/tzdata' in $(location) expression is not a declared prerequisite of this rule
+		"robolectric_tzdata",
 
 		// rust support
 		"libtombstoned_client_rust_bridge_code", "libtombstoned_client_wrapper", // rust conversions are not supported
@@ -634,8 +670,8 @@
 		"com.android.runtime",                                        // depends on unconverted modules: bionic-linker-config, linkerconfig
 		"currysrc",                                                   // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
 		"dex2oat-script",                                             // depends on unconverted modules: dex2oat
-		"generated_android_icu4j_resources",                          // depends on unconverted modules: android_icu4j_srcgen_binary, soong_zip
-		"generated_android_icu4j_test_resources",                     // depends on unconverted modules: android_icu4j_srcgen_binary, soong_zip
+		"generated_android_icu4j_resources",                          // depends on unconverted modules: android_icu4j_srcgen_binary
+		"generated_android_icu4j_test_resources",                     // depends on unconverted modules: android_icu4j_srcgen_binary
 		"host-libprotobuf-java-nano",                                 // b/220869005, depends on libprotobuf-java-nano
 		"jacoco-stubs",                                               // b/245767077, depends on droidstubs
 		"libapexutil",                                                // depends on unconverted modules: apex-info-list-tinyxml
@@ -660,14 +696,12 @@
 		"libstatslog_art",           // depends on unconverted modules: statslog_art.cpp, statslog_art.h
 		"linker_reloc_bench_main",   // depends on unconverted modules: liblinker_reloc_bench_*
 		"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
-		"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
-		"timezone-host",       // depends on unconverted modules: art.module.api.annotations
-		"truth-host-prebuilt", // depends on unconverted modules: truth-prebuilt
-		"truth-prebuilt",      // depends on unconverted modules: asm-7.0, guava
+		"robolectric-sqlite4java-0.282", // depends on unconverted modules: robolectric-sqlite4java-import, robolectric-sqlite4java-native
+		"static_crasher",                // depends on unconverted modules: libdebuggerd_handler
+		"test_fips",                     // depends on unconverted modules: adb
+		"timezone-host",                 // depends on unconverted modules: art.module.api.annotations
+		"truth-host-prebuilt",           // depends on unconverted modules: truth-prebuilt
+		"truth-prebuilt",                // depends on unconverted modules: asm-7.0, guava
 
 		// '//bionic/libc:libc_bp2build_cc_library_static' is duplicated in the 'deps' attribute of rule
 		"toybox-static",
@@ -675,6 +709,10 @@
 		// aidl files not created
 		"overlayable_policy_aidl_interface",
 
+		//prebuilts/tools/common/m2
+		// depends on //external/okio:okio-lib, which uses kotlin
+		"wire-runtime",
+
 		// cc_test related.
 		// Failing host cc_tests
 		"memunreachable_unit_test",
diff --git a/android/api_domain.go b/android/api_domain.go
new file mode 100644
index 0000000..8ff4752
--- /dev/null
+++ b/android/api_domain.go
@@ -0,0 +1,122 @@
+// 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 ApiSurface int
+
+// TODO(b/246656800): Reconcile with android.SdkKind
+const (
+	PublicApi ApiSurface = iota
+	SystemApi
+	VendorApi
+)
+
+func (a ApiSurface) String() string {
+	switch a {
+	case PublicApi:
+		return "publicapi"
+	case SystemApi:
+		return "systemapi"
+	case VendorApi:
+		return "vendorapi"
+	default:
+		return "invalid"
+	}
+}
+
+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/bazel_paths.go b/android/bazel_paths.go
index bbdae96..0d38bda 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -202,20 +202,26 @@
 	return labels
 }
 
-// Returns true if a prefix + components[:i] + /Android.bp exists
-// TODO(b/185358476) Could check for BUILD file instead of checking for Android.bp file, or ensure BUILD is always generated?
-func directoryHasBlueprint(fs pathtools.FileSystem, prefix string, components []string, componentIndex int) bool {
-	blueprintPath := prefix
-	if blueprintPath != "" {
-		blueprintPath = blueprintPath + "/"
-	}
-	blueprintPath = blueprintPath + strings.Join(components[:componentIndex+1], "/")
-	blueprintPath = blueprintPath + "/Android.bp"
-	if exists, _, _ := fs.Exists(blueprintPath); exists {
+// Returns true if a prefix + components[:i] is a package boundary.
+//
+// A package boundary is determined by a BUILD file in the directory. This can happen in 2 cases:
+//
+// 1. An Android.bp exists, which bp2build will always convert to a sibling BUILD file.
+// 2. An Android.bp doesn't exist, but a checked-in BUILD/BUILD.bazel file exists, and that file
+//    is allowlisted by the bp2build configuration to be merged into the symlink forest workspace.
+func isPackageBoundary(config Config, prefix string, components []string, componentIndex int) bool {
+	prefix = filepath.Join(prefix, filepath.Join(components[:componentIndex+1]...))
+	if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "Android.bp")); exists {
 		return true
-	} else {
-		return false
+	} else if config.Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(prefix) {
+		if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD")); exists {
+			return true
+		} else if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD.bazel")); exists {
+			return true
+		}
 	}
+
+	return false
 }
 
 // Transform a path (if necessary) to acknowledge package boundaries
@@ -245,14 +251,14 @@
 
 	newLabel := ""
 	pathComponents := strings.Split(path.Label, "/")
-	foundBlueprint := false
+	foundPackageBoundary := false
 	// Check the deepest subdirectory first and work upwards
 	for i := len(pathComponents) - 1; i >= 0; i-- {
 		pathComponent := pathComponents[i]
 		var sep string
-		if !foundBlueprint && directoryHasBlueprint(ctx.Config().fs, ctx.ModuleDir(), pathComponents, i) {
+		if !foundPackageBoundary && isPackageBoundary(ctx.Config(), ctx.ModuleDir(), pathComponents, i) {
 			sep = ":"
-			foundBlueprint = true
+			foundPackageBoundary = true
 		} else {
 			sep = "/"
 		}
@@ -262,7 +268,7 @@
 			newLabel = pathComponent + sep + newLabel
 		}
 	}
-	if foundBlueprint {
+	if foundPackageBoundary {
 		// Ensure paths end up looking like //bionic/... instead of //./bionic/...
 		moduleDir := ctx.ModuleDir()
 		if strings.HasPrefix(moduleDir, ".") {
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/module.go b/android/module.go
index 5d520f4..1617259 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1231,22 +1231,17 @@
 		}
 	}
 
-	required := depsToLabelList(mod.commonProperties.Required)
+	// The required property can contain the module itself. This causes a cycle
+	// when generated as the 'data' label list attribute in Bazel. Remove it if
+	// it exists. See b/247985196.
+	_, requiredWithoutCycles := RemoveFromList(ctx.ModuleName(), mod.commonProperties.Required)
+	required := depsToLabelList(requiredWithoutCycles)
 	archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
 	for axis, configToProps := range archVariantProps {
 		for config, _props := range configToProps {
 			if archProps, ok := _props.(*commonProperties); ok {
-				// TODO(b/234748998) Remove this requiredFiltered workaround when aapt2 converts successfully
-				requiredFiltered := archProps.Required
-				if attrs.Name == "apexer" {
-					requiredFiltered = make([]string, 0, len(archProps.Required))
-					for _, req := range archProps.Required {
-						if req != "aapt2" && req != "apexer" {
-							requiredFiltered = append(requiredFiltered, req)
-						}
-					}
-				}
-				required.SetSelectValue(axis, config, depsToLabelList(requiredFiltered).Value)
+				_, requiredWithoutCycles := RemoveFromList(ctx.ModuleName(), archProps.Required)
+				required.SetSelectValue(axis, config, depsToLabelList(requiredWithoutCycles).Value)
 				if !neitherHostNorDevice {
 					if archProps.Enabled != nil {
 						if axis != bazel.OsConfigurationAxis || osSupport[config] {
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/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index cf8e9f7..3b06f85 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -158,63 +158,30 @@
   # NOTE: It's OK if there's no ToC, as Soong just uses it for optimization
   pass
 
-returns = [
-  outputFiles,
-  ccObjectFiles,
-  sharedLibraries,
-  staticLibraries,
-  includes,
-  system_includes,
-  headers,
-  rootStaticArchives,
-  rootSharedLibraries,
-  [toc_file]
-]
+return json_encode({
+	"OutputFiles": outputFiles,
+	"CcObjectFiles": ccObjectFiles,
+	"CcSharedLibraryFiles": sharedLibraries,
+	"CcStaticLibraryFiles": staticLibraries,
+	"Includes": includes,
+	"SystemIncludes": system_includes,
+	"Headers": headers,
+	"RootStaticArchives": rootStaticArchives,
+	"RootDynamicLibraries": rootSharedLibraries,
+	"TocFile": toc_file
+})`
 
-return "|".join([", ".join(r) for r in returns])`
 }
 
 // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
 // The given rawString must correspond to the string output which was created by evaluating the
 // Starlark given in StarlarkFunctionBody.
 func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
-	const expectedLen = 10
-	splitString := strings.Split(rawString, "|")
-	if len(splitString) != expectedLen {
-		return CcInfo{}, fmt.Errorf("expected %d items, got %q", expectedLen, splitString)
-	}
-	outputFilesString := splitString[0]
-	ccObjectsString := splitString[1]
-	ccSharedLibrariesString := splitString[2]
-	ccStaticLibrariesString := splitString[3]
-	includesString := splitString[4]
-	systemIncludesString := splitString[5]
-	headersString := splitString[6]
-	rootStaticArchivesString := splitString[7]
-	rootDynamicLibrariesString := splitString[8]
-	tocFile := splitString[9] // NOTE: Will be the empty string if there wasn't
-
-	outputFiles := splitOrEmpty(outputFilesString, ", ")
-	ccObjects := splitOrEmpty(ccObjectsString, ", ")
-	ccSharedLibraries := splitOrEmpty(ccSharedLibrariesString, ", ")
-	ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
-	includes := splitOrEmpty(includesString, ", ")
-	systemIncludes := splitOrEmpty(systemIncludesString, ", ")
-	headers := splitOrEmpty(headersString, ", ")
-	rootStaticArchives := splitOrEmpty(rootStaticArchivesString, ", ")
-	rootDynamicLibraries := splitOrEmpty(rootDynamicLibrariesString, ", ")
-	return CcInfo{
-		OutputFiles:          outputFiles,
-		CcObjectFiles:        ccObjects,
-		CcSharedLibraryFiles: ccSharedLibraries,
-		CcStaticLibraryFiles: ccStaticLibraries,
-		Includes:             includes,
-		SystemIncludes:       systemIncludes,
-		Headers:              headers,
-		RootStaticArchives:   rootStaticArchives,
-		RootDynamicLibraries: rootDynamicLibraries,
-		TocFile:              tocFile,
-	}, nil
+	var ccInfo CcInfo
+	decoder := json.NewDecoder(strings.NewReader(rawString))
+	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
+	err := decoder.Decode(&ccInfo)
+	return ccInfo, err
 }
 
 // Query Bazel for the artifacts generated by the apex modules.
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 46eb0b6..afe478b 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -1,9 +1,8 @@
 package cquery
 
 import (
-	"fmt"
+	"encoding/json"
 	"reflect"
-	"strings"
 	"testing"
 )
 
@@ -63,74 +62,48 @@
 }
 
 func TestGetCcInfoParseResults(t *testing.T) {
-	const expectedSplits = 10
-	noResult := strings.Repeat("|", expectedSplits-1)
 	testCases := []struct {
-		description          string
-		input                string
-		expectedOutput       CcInfo
-		expectedErrorMessage string
+		description    string
+		inputCcInfo    CcInfo
+		expectedOutput CcInfo
 	}{
 		{
-			description: "no result",
-			input:       noResult,
-			expectedOutput: CcInfo{
-				OutputFiles:          []string{},
-				CcObjectFiles:        []string{},
-				CcSharedLibraryFiles: []string{},
-				CcStaticLibraryFiles: []string{},
-				Includes:             []string{},
-				SystemIncludes:       []string{},
-				Headers:              []string{},
-				RootStaticArchives:   []string{},
-				RootDynamicLibraries: []string{},
-				TocFile:              "",
-			},
+			description:    "no result",
+			inputCcInfo:    CcInfo{},
+			expectedOutput: CcInfo{},
 		},
 		{
 			description: "only output",
-			input:       "test" + noResult,
+			inputCcInfo: CcInfo{
+				OutputFiles: []string{"test", "test3"},
+			},
 			expectedOutput: CcInfo{
-				OutputFiles:          []string{"test"},
-				CcObjectFiles:        []string{},
-				CcSharedLibraryFiles: []string{},
-				CcStaticLibraryFiles: []string{},
-				Includes:             []string{},
-				SystemIncludes:       []string{},
-				Headers:              []string{},
-				RootStaticArchives:   []string{},
-				RootDynamicLibraries: []string{},
-				TocFile:              "",
+				OutputFiles: []string{"test", "test3"},
 			},
 		},
 		{
 			description: "only ToC",
-			input:       noResult + "test",
+			inputCcInfo: CcInfo{
+				TocFile: "test",
+			},
 			expectedOutput: CcInfo{
-				OutputFiles:          []string{},
-				CcObjectFiles:        []string{},
-				CcSharedLibraryFiles: []string{},
-				CcStaticLibraryFiles: []string{},
-				Includes:             []string{},
-				SystemIncludes:       []string{},
-				Headers:              []string{},
-				RootStaticArchives:   []string{},
-				RootDynamicLibraries: []string{},
-				TocFile:              "test",
+				TocFile: "test",
 			},
 		},
 		{
 			description: "all items set",
-			input: "out1, out2" +
-				"|object1, object2" +
-				"|shared_lib1, shared_lib2" +
-				"|static_lib1, static_lib2" +
-				"|., dir/subdir" +
-				"|system/dir, system/other/dir" +
-				"|dir/subdir/hdr.h" +
-				"|rootstaticarchive1" +
-				"|rootdynamiclibrary1" +
-				"|lib.so.toc",
+			inputCcInfo: CcInfo{
+				OutputFiles:          []string{"out1", "out2"},
+				CcObjectFiles:        []string{"object1", "object2"},
+				CcSharedLibraryFiles: []string{"shared_lib1", "shared_lib2"},
+				CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
+				Includes:             []string{".", "dir/subdir"},
+				SystemIncludes:       []string{"system/dir", "system/other/dir"},
+				Headers:              []string{"dir/subdir/hdr.h"},
+				RootStaticArchives:   []string{"rootstaticarchive1"},
+				RootDynamicLibraries: []string{"rootdynamiclibrary1"},
+				TocFile:              "lib.so.toc",
+			},
 			expectedOutput: CcInfo{
 				OutputFiles:          []string{"out1", "out2"},
 				CcObjectFiles:        []string{"object1", "object2"},
@@ -144,24 +117,12 @@
 				TocFile:              "lib.so.toc",
 			},
 		},
-		{
-			description:          "too few result splits",
-			input:                "|",
-			expectedOutput:       CcInfo{},
-			expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, []string{"", ""}),
-		},
-		{
-			description:          "too many result splits",
-			input:                strings.Repeat("|", expectedSplits+1), // 2 too many
-			expectedOutput:       CcInfo{},
-			expectedErrorMessage: fmt.Sprintf("expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)),
-		},
 	}
 	for _, tc := range testCases {
-		actualOutput, err := GetCcInfo.ParseResult(tc.input)
-		if (err == nil && tc.expectedErrorMessage != "") ||
-			(err != nil && err.Error() != tc.expectedErrorMessage) {
-			t.Errorf("%q:\n%12s: %q\n%12s: %q", tc.description, "expect Error", tc.expectedErrorMessage, "but got", err)
+		jsonInput, _ := json.Marshal(tc.inputCcInfo)
+		actualOutput, err := GetCcInfo.ParseResult(string(jsonInput))
+		if err != nil {
+			t.Errorf("%q:\n test case get error: %q", tc.description, err)
 		} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
 			t.Errorf("%q:\n expected %#v\n!= actual %#v", tc.description, tc.expectedOutput, actualOutput)
 		}
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/build_conversion.go b/bp2build/build_conversion.go
index ee162b2..36c3a48 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -242,6 +242,7 @@
 	// Simple metrics tracking for bp2build
 	metrics := CodegenMetrics{
 		ruleClassCount:           make(map[string]uint64),
+		convertedModulePathMap:   make(map[string]string),
 		convertedModuleTypeCount: make(map[string]uint64),
 		totalModuleTypeCount:     make(map[string]uint64),
 	}
@@ -272,20 +273,21 @@
 				// target in a BUILD file, we don't autoconvert them.
 
 				// Log the module.
-				metrics.AddConvertedModule(m, moduleType, Handcrafted)
+				metrics.AddConvertedModule(m, moduleType, dir, Handcrafted)
 			} else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
 				// Handle modules converted to generated targets.
 
 				// Log the module.
-				metrics.AddConvertedModule(aModule, moduleType, Generated)
+				metrics.AddConvertedModule(aModule, moduleType, dir, Generated)
 
 				// Handle modules with unconverted deps. By default, emit a warning.
 				if unconvertedDeps := aModule.GetUnconvertedBp2buildDeps(); len(unconvertedDeps) > 0 {
 					msg := fmt.Sprintf("%s %s:%s depends on unconverted modules: %s",
 						moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
-					if ctx.unconvertedDepMode == warnUnconvertedDeps {
+					switch ctx.unconvertedDepMode {
+					case warnUnconvertedDeps:
 						metrics.moduleWithUnconvertedDepsMsgs = append(metrics.moduleWithUnconvertedDepsMsgs, msg)
-					} else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
+					case errorModulesUnconvertedDeps:
 						errs = append(errs, fmt.Errorf(msg))
 						return
 					}
@@ -293,9 +295,10 @@
 				if unconvertedDeps := aModule.GetMissingBp2buildDeps(); len(unconvertedDeps) > 0 {
 					msg := fmt.Sprintf("%s %s:%s depends on missing modules: %s",
 						moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
-					if ctx.unconvertedDepMode == warnUnconvertedDeps {
+					switch ctx.unconvertedDepMode {
+					case warnUnconvertedDeps:
 						metrics.moduleWithMissingDepsMsgs = append(metrics.moduleWithMissingDepsMsgs, msg)
-					} else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
+					case errorModulesUnconvertedDeps:
 						errs = append(errs, fmt.Errorf(msg))
 						return
 					}
@@ -348,7 +351,7 @@
 		// TODO(b/198619163): We should change this to export_files(glob(["**/*"])) instead, but doing that causes these errors:
 		// "Error in exports_files: generated label '//external/avb:avbtool' conflicts with existing py_binary rule"
 		// So we need to solve all the "target ... is both a rule and a file" warnings first.
-		for dir, _ := range dirs {
+		for dir := range dirs {
 			buildFileToTargets[dir] = append(buildFileToTargets[dir], BazelTarget{
 				name:      "bp2build_all_srcs",
 				content:   `filegroup(name = "bp2build_all_srcs", srcs = glob(["**/*"]))`,
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index dd28c3c..9f4f7c1 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -987,57 +987,6 @@
 			},
 		},
 		{
-			Description:                "filegroup with glob",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "other/a.txt",
-        "other/b.txt",
-        "other/subdir/a.txt",
-    ]`,
-				}),
-			},
-			Filesystem: map[string]string{
-				"other/a.txt":        "",
-				"other/b.txt":        "",
-				"other/subdir/a.txt": "",
-				"other/file":         "",
-			},
-		},
-		{
-			Description:                "filegroup with glob in subdir",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Dir:                        "other",
-			Filesystem: map[string]string{
-				"other/Android.bp": `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-				"other/a.txt":        "",
-				"other/b.txt":        "",
-				"other/subdir/a.txt": "",
-				"other/file":         "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "subdir/a.txt",
-    ]`,
-				}),
-			},
-		},
-		{
 			Description:                "depends_on_other_dir_module",
 			ModuleTypeUnderTest:        "filegroup",
 			ModuleTypeUnderTestFactory: android.FileGroupFactory,
@@ -1429,6 +1378,226 @@
 	}
 }
 
+func TestGlob(t *testing.T) {
+	testCases := []Bp2buildTestCase{
+		{
+			Description:                "filegroup with glob",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "other/a.txt",
+        "other/b.txt",
+        "other/subdir/a.txt",
+    ]`,
+				}),
+			},
+			Filesystem: map[string]string{
+				"other/a.txt":        "",
+				"other/b.txt":        "",
+				"other/subdir/a.txt": "",
+				"other/file":         "",
+			},
+		},
+		{
+			Description:                "filegroup with glob in subdir",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Dir:                        "other",
+			Filesystem: map[string]string{
+				"other/Android.bp": `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+				"other/a.txt":        "",
+				"other/b.txt":        "",
+				"other/subdir/a.txt": "",
+				"other/file":         "",
+			},
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "a.txt",
+        "b.txt",
+        "subdir/a.txt",
+    ]`,
+				}),
+			},
+		},
+		{
+			Description:                "filegroup with glob with no kept BUILD files",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			KeepBuildFileForDirs:       []string{
+				// empty
+			},
+			Blueprint: `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			Filesystem: map[string]string{
+				"a.txt":         "",
+				"b.txt":         "",
+				"foo/BUILD":     "",
+				"foo/a.txt":     "",
+				"foo/bar/BUILD": "",
+				"foo/bar/b.txt": "",
+			},
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "a.txt",
+        "b.txt",
+        "foo/a.txt",
+        "foo/bar/b.txt",
+    ]`,
+				}),
+			},
+		},
+		{
+			Description:                "filegroup with glob with kept BUILD file",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			KeepBuildFileForDirs: []string{
+				"foo",
+			},
+			Blueprint: `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			Filesystem: map[string]string{
+				"a.txt":         "",
+				"b.txt":         "",
+				"foo/BUILD":     "",
+				"foo/a.txt":     "",
+				"foo/bar/BUILD": "",
+				"foo/bar/b.txt": "",
+			},
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "a.txt",
+        "b.txt",
+        "//foo:a.txt",
+        "//foo:bar/b.txt",
+    ]`,
+				}),
+			},
+		},
+		{
+			Description:                "filegroup with glob with kept BUILD.bazel file",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			KeepBuildFileForDirs: []string{
+				"foo",
+			},
+			Blueprint: `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			Filesystem: map[string]string{
+				"a.txt":               "",
+				"b.txt":               "",
+				"foo/BUILD.bazel":     "",
+				"foo/a.txt":           "",
+				"foo/bar/BUILD.bazel": "",
+				"foo/bar/b.txt":       "",
+			},
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "a.txt",
+        "b.txt",
+        "//foo:a.txt",
+        "//foo:bar/b.txt",
+    ]`,
+				}),
+			},
+		},
+		{
+			Description:                "filegroup with glob with Android.bp file as boundary",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			Filesystem: map[string]string{
+				"a.txt":              "",
+				"b.txt":              "",
+				"foo/Android.bp":     "",
+				"foo/a.txt":          "",
+				"foo/bar/Android.bp": "",
+				"foo/bar/b.txt":      "",
+			},
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "a.txt",
+        "b.txt",
+        "//foo:a.txt",
+        "//foo/bar:b.txt",
+    ]`,
+				}),
+			},
+		},
+		{
+			Description:                "filegroup with glob in subdir with kept BUILD and BUILD.bazel file",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Dir:                        "other",
+			KeepBuildFileForDirs: []string{
+				"other/foo",
+				"other/foo/bar",
+				// deliberately not other/foo/baz/BUILD.
+			},
+			Filesystem: map[string]string{
+				"other/Android.bp": `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+				"other/a.txt":               "",
+				"other/b.txt":               "",
+				"other/foo/BUILD":           "",
+				"other/foo/a.txt":           "",
+				"other/foo/bar/BUILD.bazel": "",
+				"other/foo/bar/b.txt":       "",
+				"other/foo/baz/BUILD":       "",
+				"other/foo/baz/c.txt":       "",
+			},
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "a.txt",
+        "b.txt",
+        "//other/foo:a.txt",
+        "//other/foo/bar:b.txt",
+        "//other/foo:baz/c.txt",
+    ]`,
+				}),
+			},
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.Description, func(t *testing.T) {
+			RunBp2BuildTestCaseSimple(t, testCase)
+		})
+	}
+}
+
 func TestGlobExcludeSrcs(t *testing.T) {
 	testCases := []Bp2buildTestCase{
 		{
@@ -1518,6 +1687,22 @@
 			},
 		},
 		{
+			Description:                "Required into data test, cyclic self reference is filtered out",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+filegroup {
+    name: "fg_foo",
+    required: ["reqd", "fg_foo"],
+    bazel_module: { bp2build_available: true },
+}`,
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"data": `[":reqd"]`,
+				}),
+			},
+		},
+		{
 			Description:                "Required via arch into data test",
 			ModuleTypeUnderTest:        "python_library",
 			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
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..1b8e9b4 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -3112,3 +3112,139 @@
 		},
 	})
 }
+
+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": [],
+    })`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryWithAidlAndSharedLibs(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_aidl_library depends on shared libs from parent cc_library_static",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+    name: "foo",
+    srcs: [
+        "Foo.aidl",
+    ],
+	shared_libs: [
+		"bar",
+		"baz",
+	],
+	export_shared_lib_headers: [
+		"baz",
+	],
+}` +
+			simpleModuleDoNotConvertBp2build("cc_library", "bar") +
+			simpleModuleDoNotConvertBp2build("cc_library", "baz"),
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
+				"srcs": `["Foo.aidl"]`,
+			}),
+			MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
+				"deps": `[":foo_aidl_library"]`,
+				"implementation_dynamic_deps": `[
+        ":baz",
+        ":bar",
+    ]`,
+			}),
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
+				"dynamic_deps":                      `[":baz"]`,
+				"implementation_dynamic_deps":       `[":bar"]`,
+				"local_includes":                    `["."]`,
+			}),
+		},
+	})
+}
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/bp2build/conversion.go b/bp2build/conversion.go
index b6190c6..522c10e 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -34,6 +34,12 @@
 
 	files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
 
+	convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t")
+	if err != nil {
+		panic(err)
+	}
+	files = append(files, newFile("metrics", "converted_modules_path_map.json", string(convertedModulePathMap)))
+
 	files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
 
 	files = append(files, newFile("product_config", "arch_configuration.bzl", android.StarlarkArchConfigurations()))
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 0cb711c..b696a98 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -116,6 +116,10 @@
 			basename: "converted_modules.txt",
 		},
 		{
+			dir:      "metrics",
+			basename: "converted_modules_path_map.json",
+		},
+		{
 			dir:      "product_config",
 			basename: "soong_config_variables.bzl",
 		},
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index a8bfecd..160395b 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -61,7 +61,7 @@
 		{
 			moduleType: "genrule",
 			factory:    genrule.GenRuleFactory,
-			genDir:     "$(GENDIR)",
+			genDir:     "$(RULEDIR)",
 		},
 		{
 			moduleType: "cc_genrule",
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 3a21c34..0b45996 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -9,6 +9,7 @@
 	"android/soong/android"
 	"android/soong/shared"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+
 	"github.com/google/blueprint"
 )
 
@@ -38,6 +39,9 @@
 	// List of converted modules
 	convertedModules []string
 
+	// Map of converted modules and paths to call
+	convertedModulePathMap map[string]string
+
 	// Counts of converted modules by module type.
 	convertedModuleTypeCount map[string]uint64
 
@@ -147,10 +151,11 @@
 	Handcrafted
 )
 
-func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, conversionType ConversionType) {
+func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string, conversionType ConversionType) {
 	// Undo prebuilt_ module name prefix modifications
 	moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
 	metrics.convertedModules = append(metrics.convertedModules, moduleName)
+	metrics.convertedModulePathMap[moduleName] = "//" + dir
 	metrics.convertedModuleTypeCount[moduleType] += 1
 	metrics.totalModuleTypeCount[moduleType] += 1
 
diff --git a/bp2build/ndk_library_conversion_test.go b/bp2build/ndk_library_conversion_test.go
new file mode 100644
index 0000000..244ce20
--- /dev/null
+++ b/bp2build/ndk_library_conversion_test.go
@@ -0,0 +1,77 @@
+// 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/cc"
+)
+
+func TestNdkLibraryContributionSymbolFile(t *testing.T) {
+	bp := `
+	ndk_library {
+		name: "libfoo",
+		symbol_file: "libfoo.map.txt",
+	}
+	`
+	expectedBazelTarget := MakeBazelTargetNoRestrictions(
+		"cc_api_contribution",
+		"libfoo.ndk.contribution",
+		AttrNameToString{
+			"api":                    `"libfoo.map.txt"`,
+			"api_surfaces":           `["publicapi"]`,
+			"library_name":           `"libfoo"`,
+			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+		},
+	)
+	RunBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: []string{expectedBazelTarget},
+	})
+}
+
+func TestNdkLibraryContributionHeaders(t *testing.T) {
+	bp := `
+	ndk_library {
+		name: "libfoo",
+		symbol_file: "libfoo.map.txt",
+		export_header_libs: ["libfoo_headers"],
+	}
+	`
+	fs := map[string]string{
+		"header_directory/Android.bp": `
+		ndk_headers {
+			name: "libfoo_headers",
+		}
+		`,
+	}
+	expectedBazelTarget := MakeBazelTargetNoRestrictions(
+		"cc_api_contribution",
+		"libfoo.ndk.contribution",
+		AttrNameToString{
+			"api":                    `"libfoo.map.txt"`,
+			"api_surfaces":           `["publicapi"]`,
+			"library_name":           `"libfoo"`,
+			"hdrs":                   `["//header_directory:libfoo_headers.contribution"]`,
+			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+		},
+	)
+	RunBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
+		Blueprint:            bp,
+		Filesystem:           fs,
+		ExpectedBazelTargets: []string{expectedBazelTarget},
+	})
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 8ce8bb2..c2c1b19 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -30,13 +30,6 @@
 )
 
 var (
-	// A default configuration for tests to not have to specify bp2build_available on top level targets.
-	bp2buildConfig = android.NewBp2BuildAllowlist().SetDefaultConfig(
-		allowlists.Bp2BuildConfig{
-			android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
-		},
-	)
-
 	buildDir string
 )
 
@@ -87,6 +80,11 @@
 	// An error with a string contained within the string of the expected error
 	ExpectedErr         error
 	UnconvertedDepsMode unconvertedDepsMode
+
+	// For every directory listed here, the BUILD file for that directory will
+	// be merged with the generated BUILD file. This allows custom BUILD targets
+	// to be used in tests, or use BUILD files to draw package boundaries.
+	KeepBuildFileForDirs []string
 }
 
 func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
@@ -107,6 +105,18 @@
 
 	registerModuleTypes(ctx)
 	ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
+
+	// A default configuration for tests to not have to specify bp2build_available on top level targets.
+	bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
+		allowlists.Bp2BuildConfig{
+			android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
+		},
+	)
+	for _, f := range tc.KeepBuildFileForDirs {
+		bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
+			f: /*recursive=*/ false,
+		})
+	}
 	ctx.RegisterBp2BuildConfig(bp2buildConfig)
 	ctx.RegisterForBazelConversion()
 
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..9b85ec4 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()
@@ -719,7 +725,7 @@
 	(&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib)
 	(&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib)
 
-	aidlDep := bp2buildCcAidlLibrary(ctx, module, compilerAttrs.aidlSrcs)
+	aidlDep := bp2buildCcAidlLibrary(ctx, module, compilerAttrs.aidlSrcs, linkerAttrs)
 	if aidlDep != nil {
 		if lib, ok := module.linker.(*libraryDecorator); ok {
 			if proptools.Bool(lib.Properties.Aidl.Export_aidl_headers) {
@@ -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()
 
@@ -750,6 +760,7 @@
 	ctx android.Bp2buildMutatorContext,
 	m *Module,
 	aidlLabelList bazel.LabelListAttribute,
+	linkerAttrs linkerAttributes,
 ) *bazel.LabelAttribute {
 	if !aidlLabelList.IsEmpty() {
 		aidlLibs, aidlSrcs := aidlLabelList.Partition(func(src bazel.Label) bool {
@@ -777,6 +788,16 @@
 
 		if !aidlLibs.IsEmpty() {
 			ccAidlLibrarylabel := m.Name() + "_cc_aidl_library"
+			// Since cc_aidl_library only needs the dynamic deps (aka shared libs) from the parent cc library for compiling,
+			// we err on the side of not re-exporting the headers of the dynamic deps from cc_aidl_lirary
+			// because the parent cc library already has all the dynamic deps
+			implementationDynamicDeps := bazel.MakeLabelListAttribute(
+				bazel.AppendBazelLabelLists(
+					linkerAttrs.dynamicDeps.Value,
+					linkerAttrs.implementationDynamicDeps.Value,
+				),
+			)
+
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{
 					Rule_class:        "cc_aidl_library",
@@ -784,7 +805,8 @@
 				},
 				android.CommonAttributes{Name: ccAidlLibrarylabel},
 				&ccAidlLibraryAttributes{
-					Deps: aidlLibs,
+					Deps:                        aidlLibs,
+					Implementation_dynamic_deps: implementationDynamicDeps,
 				},
 			)
 			label := &bazel.LabelAttribute{
@@ -1208,10 +1230,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.go b/cc/cc.go
index d42ab6d..1c845f6 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3650,6 +3650,7 @@
 	sharedLibrary
 	headerLibrary
 	testBin // testBinary already declared
+	ndkLibrary
 )
 
 func (c *Module) typ() moduleType {
@@ -3686,6 +3687,8 @@
 			return staticLibrary
 		}
 		return sharedLibrary
+	} else if c.isNDKStubLibrary() {
+		return ndkLibrary
 	}
 	return unknownType
 }
@@ -3726,6 +3729,8 @@
 		} else {
 			sharedOrStaticLibraryBp2Build(ctx, c, false)
 		}
+	case ndkLibrary:
+		ndkLibraryBp2build(ctx, c)
 	}
 }
 
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..441eb79 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -276,7 +276,8 @@
 }
 
 type ccAidlLibraryAttributes struct {
-	Deps bazel.LabelListAttribute
+	Deps                        bazel.LabelListAttribute
+	Implementation_dynamic_deps bazel.LabelListAttribute
 }
 
 type stripAttributes struct {
@@ -2704,6 +2705,7 @@
 		modType = "cc_library_static"
 	} else {
 		modType = "cc_library_shared"
+		createStubsBazelTargetIfNeeded(ctx, module, compilerAttrs, exportedIncludes, baseAttributes)
 	}
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class:        modType,
@@ -2711,8 +2713,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/lto.go b/cc/lto.go
index b3e5e74..581856b 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -15,9 +15,9 @@
 package cc
 
 import (
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 // LTO (link-time optimization) allows the compiler to optimize and generate
@@ -49,9 +49,12 @@
 
 	// Dep properties indicate that this module needs to be built with LTO
 	// since it is an object dependency of an LTO module.
-	FullDep  bool `blueprint:"mutated"`
-	ThinDep  bool `blueprint:"mutated"`
-	NoLtoDep bool `blueprint:"mutated"`
+	FullEnabled  bool `blueprint:"mutated"`
+	ThinEnabled  bool `blueprint:"mutated"`
+	NoLtoEnabled bool `blueprint:"mutated"`
+	FullDep      bool `blueprint:"mutated"`
+	ThinDep      bool `blueprint:"mutated"`
+	NoLtoDep     bool `blueprint:"mutated"`
 
 	// Use clang lld instead of gnu ld.
 	Use_clang_lld *bool
@@ -70,7 +73,7 @@
 
 func (lto *lto) begin(ctx BaseModuleContext) {
 	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
-		lto.Properties.Lto.Never = proptools.BoolPtr(true)
+		lto.Properties.NoLtoEnabled = true
 	}
 }
 
@@ -151,15 +154,15 @@
 }
 
 func (lto *lto) FullLTO() bool {
-	return lto != nil && Bool(lto.Properties.Lto.Full)
+	return lto != nil && (proptools.Bool(lto.Properties.Lto.Full) || lto.Properties.FullEnabled)
 }
 
 func (lto *lto) ThinLTO() bool {
-	return lto != nil && Bool(lto.Properties.Lto.Thin)
+	return lto != nil && (proptools.Bool(lto.Properties.Lto.Thin) || lto.Properties.ThinEnabled)
 }
 
 func (lto *lto) Never() bool {
-	return lto != nil && Bool(lto.Properties.Lto.Never)
+	return lto != nil && (proptools.Bool(lto.Properties.Lto.Never) || lto.Properties.NoLtoEnabled)
 }
 
 func GlobalThinLTO(ctx android.BaseModuleContext) bool {
@@ -255,13 +258,13 @@
 
 				// LTO properties for dependencies
 				if name == "lto-full" {
-					variation.lto.Properties.Lto.Full = proptools.BoolPtr(true)
+					variation.lto.Properties.FullEnabled = true
 				}
 				if name == "lto-thin" {
-					variation.lto.Properties.Lto.Thin = proptools.BoolPtr(true)
+					variation.lto.Properties.ThinEnabled = true
 				}
 				if name == "lto-none" {
-					variation.lto.Properties.Lto.Never = proptools.BoolPtr(true)
+					variation.lto.Properties.NoLtoEnabled = true
 				}
 				variation.Properties.PreventInstall = true
 				variation.Properties.HideFromMake = true
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/ndk_library.go b/cc/ndk_library.go
index e2b9682..06ded3f 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -25,6 +25,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/cc/config"
 )
 
@@ -568,5 +569,43 @@
 func NdkLibraryFactory() android.Module {
 	module := newStubLibrary()
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+	android.InitBazelModule(module)
 	return module
 }
+
+type bazelCcApiContributionAttributes struct {
+	Api          bazel.LabelAttribute
+	Api_surfaces bazel.StringListAttribute
+	Hdrs         bazel.LabelListAttribute
+	Library_name string
+}
+
+// Names of the cc_api_header targets in the bp2build workspace
+func (s *stubDecorator) apiHeaderLabels(ctx android.TopDownMutatorContext) bazel.LabelList {
+	addSuffix := func(ctx android.BazelConversionPathContext, module blueprint.Module) string {
+		label := android.BazelModuleLabel(ctx, module)
+		return android.ApiContributionTargetName(label)
+	}
+	return android.BazelLabelForModuleDepsWithFn(ctx, s.properties.Export_header_libs, addSuffix)
+}
+
+func ndkLibraryBp2build(ctx android.TopDownMutatorContext, m *Module) {
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "cc_api_contribution",
+		Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
+	}
+	stubLibrary := m.compiler.(*stubDecorator)
+	attrs := &bazelCcApiContributionAttributes{
+		Library_name: stubLibrary.implementationModuleName(m.Name()),
+		Api_surfaces: bazel.MakeStringListAttribute(
+			[]string{android.PublicApi.String()}),
+	}
+	if symbolFile := stubLibrary.properties.Symbol_file; symbolFile != nil {
+		apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(symbolFile)).Label
+		attrs.Api = *bazel.MakeLabelAttribute(apiLabel)
+	}
+	apiHeaders := stubLibrary.apiHeaderLabels(ctx)
+	attrs.Hdrs = bazel.MakeLabelListAttribute(apiHeaders)
+	apiContributionTargetName := android.ApiContributionTargetName(ctx.ModuleName())
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: apiContributionTargetName}, 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/cmd/zip2zip/BUILD.bazel b/cmd/zip2zip/BUILD.bazel
new file mode 100644
index 0000000..1915a2d
--- /dev/null
+++ b/cmd/zip2zip/BUILD.bazel
@@ -0,0 +1,18 @@
+# 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.
+
+alias(
+    name = "zip2zip",
+    actual = "//prebuilts/build-tools:linux-x86/bin/zip2zip",
+)
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 7520f58..362a8ef 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -678,9 +678,10 @@
 	Filename_from_src bazel.BoolAttribute
 }
 
-// ConvertWithBp2build performs bp2build conversion of PrebuiltEtc
-// All prebuilt_* modules are PrebuiltEtc, which we treat uniformily as *PrebuiltFile*
-func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+// Bp2buildHelper returns a bazelPrebuiltFileAttributes used for the conversion
+// of prebuilt_*  modules. bazelPrebuiltFileAttributes has the common attributes
+// used by both prebuilt_etc_xml and other prebuilt_* moodules
+func (module *PrebuiltEtc) Bp2buildHelper(ctx android.TopDownMutatorContext) *bazelPrebuiltFileAttributes {
 	var src bazel.LabelAttribute
 	for axis, configToProps := range module.GetArchVariantProperties(ctx, &prebuiltEtcProperties{}) {
 		for config, p := range configToProps {
@@ -727,10 +728,6 @@
 	}
 
 	var dir = module.installDirBase
-	// prebuilt_file supports only `etc` or `usr/share`
-	if !(dir == "etc" || dir == "usr/share") {
-		return
-	}
 	if subDir := module.subdirProperties.Sub_dir; subDir != nil {
 		dir = dir + "/" + *subDir
 	}
@@ -752,6 +749,22 @@
 		attrs.Filename_from_src = bazel.BoolAttribute{Value: moduleProps.Filename_from_src}
 	}
 
+	return attrs
+
+}
+
+// ConvertWithBp2build performs bp2build conversion of PrebuiltEtc
+// prebuilt_* modules (except prebuilt_etc_xml) are PrebuiltEtc,
+// which we treat as *PrebuiltFile*
+func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	var dir = module.installDirBase
+	// prebuilt_file supports only `etc` or `usr/share`
+	if !(dir == "etc" || dir == "usr/share") {
+		return
+	}
+
+	attrs := module.Bp2buildHelper(ctx)
+
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class:        "prebuilt_file",
 		Bzl_load_location: "//build/bazel/rules:prebuilt_file.bzl",
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 7a0dac3..d4ed363 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -909,12 +909,7 @@
 			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
 			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
 		}
-
-		genDir := "$(GENDIR)"
-		if t := ctx.ModuleType(); t == "cc_genrule" || t == "java_genrule" || t == "java_genrule_host" {
-			genDir = "$(RULEDIR)"
-		}
-		cmd = strings.Replace(cmd, "$(genDir)", genDir, -1)
+		cmd = strings.Replace(cmd, "$(genDir)", "$(RULEDIR)", -1)
 		if len(tools.Value.Includes) > 0 {
 			cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools.Value.Includes[0].Label), -1)
 			cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools.Value.Includes[0].Label), -1)
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index cd941cc..63f8fa9 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -790,6 +790,94 @@
 		result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
 }
 
+func TestGenSrcsWithNonRootAndroidBpOutputFiles(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForGenRuleTest,
+		android.FixtureMergeMockFs(android.MockFS{
+			"external-protos/path/Android.bp": []byte(`
+				filegroup {
+					name: "external-protos",
+					srcs: ["baz/baz.proto", "bar.proto"],
+				}
+			`),
+			"package-dir/Android.bp": []byte(`
+				gensrcs {
+					name: "module-name",
+					cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
+					srcs: [
+						"src/foo.proto",
+						":external-protos",
+					],
+					output_extension: "proto.h",
+				}
+			`),
+		}),
+	).RunTest(t)
+
+	exportedIncludeDir := "out/soong/.intermediates/package-dir/module-name/gen/gensrcs"
+	gen := result.Module("module-name", "").(*Module)
+
+	android.AssertPathsRelativeToTopEquals(
+		t,
+		"include path",
+		[]string{exportedIncludeDir},
+		gen.exportedIncludeDirs,
+	)
+	android.AssertPathsRelativeToTopEquals(
+		t,
+		"files",
+		[]string{
+			exportedIncludeDir + "/package-dir/src/foo.proto.h",
+			exportedIncludeDir + "/external-protos/path/baz/baz.proto.h",
+			exportedIncludeDir + "/external-protos/path/bar.proto.h",
+		},
+		gen.outputFiles,
+	)
+}
+
+func TestGenSrcsWithSrcsFromExternalPackage(t *testing.T) {
+	bp := `
+		gensrcs {
+			name: "module-name",
+			cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
+			srcs: [
+				":external-protos",
+			],
+			output_extension: "proto.h",
+		}
+	`
+	result := android.GroupFixturePreparers(
+		prepareForGenRuleTest,
+		android.FixtureMergeMockFs(android.MockFS{
+			"external-protos/path/Android.bp": []byte(`
+				filegroup {
+					name: "external-protos",
+					srcs: ["foo/foo.proto", "bar.proto"],
+				}
+			`),
+		}),
+	).RunTestWithBp(t, bp)
+
+	exportedIncludeDir := "out/soong/.intermediates/module-name/gen/gensrcs"
+	gen := result.Module("module-name", "").(*Module)
+
+	android.AssertPathsRelativeToTopEquals(
+		t,
+		"include path",
+		[]string{exportedIncludeDir},
+		gen.exportedIncludeDirs,
+	)
+	android.AssertPathsRelativeToTopEquals(
+		t,
+		"files",
+		[]string{
+			exportedIncludeDir + "/external-protos/path/foo/foo.proto.h",
+			exportedIncludeDir + "/external-protos/path/bar.proto.h",
+		},
+		gen.outputFiles,
+	)
+}
+
 func TestPrebuiltTool(t *testing.T) {
 	testcases := []struct {
 		name             string
diff --git a/java/Android.bp b/java/Android.bp
index 9df4ab4..8510e04 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -64,6 +64,7 @@
         "plugin.go",
         "prebuilt_apis.go",
         "proto.go",
+        "resourceshrinker.go",
         "robolectric.go",
         "rro.go",
         "sdk.go",
diff --git a/java/aapt2.go b/java/aapt2.go
index 5346ddf..7845a0b 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -256,17 +256,21 @@
 
 var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert",
 	blueprint.RuleParams{
-		Command:     `${config.Aapt2Cmd} convert --output-format proto $in -o $out`,
+		Command:     `${config.Aapt2Cmd} convert --output-format $format $in -o $out`,
 		CommandDeps: []string{"${config.Aapt2Cmd}"},
-	})
+	}, "format",
+)
 
 // Converts xml files and resource tables (resources.arsc) in the given jar/apk file to a proto
 // format. The proto definition is available at frameworks/base/tools/aapt2/Resources.proto.
-func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path) {
+func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path, format string) {
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aapt2ConvertRule,
 		Input:       in,
 		Output:      out,
-		Description: "convert to proto",
+		Description: "convert to " + format,
+		Args: map[string]string{
+			"format": format,
+		},
 	})
 }
diff --git a/java/app.go b/java/app.go
index 7f37ff3..dc02c68 100755
--- a/java/app.go
+++ b/java/app.go
@@ -668,10 +668,9 @@
 	if lineage := String(a.overridableAppProperties.Lineage); lineage != "" {
 		lineageFile = android.PathForModuleSrc(ctx, lineage)
 	}
-
 	rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion)
 
-	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
+	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, Bool(a.dexProperties.Optimize.Shrink_resources))
 	a.outputFile = packageFile
 	if v4SigningRequested {
 		a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
@@ -700,7 +699,7 @@
 		if v4SigningRequested {
 			v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
 		}
-		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, false)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
 		if v4SigningRequested {
 			a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
diff --git a/java/app_builder.go b/java/app_builder.go
index 18a9751..d20a6bf 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -52,7 +52,7 @@
 	})
 
 func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
-	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
+	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string, shrinkResources bool) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
 	unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -65,7 +65,6 @@
 	if jniJarFile != nil {
 		inputs = append(inputs, jniJarFile)
 	}
-
 	ctx.Build(pctx, android.BuildParams{
 		Rule:      combineApk,
 		Inputs:    inputs,
@@ -73,6 +72,11 @@
 		Implicits: deps,
 	})
 
+	if shrinkResources {
+		shrunkenApk := android.PathForModuleOut(ctx, "resource-shrunken", unsignedApk.Base())
+		ShrinkResources(ctx, unsignedApk, shrunkenApk)
+		unsignedApk = shrunkenApk
+	}
 	SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion)
 }
 
@@ -84,7 +88,6 @@
 		certificateArgs = append(certificateArgs, c.Pem.String(), c.Key.String())
 		deps = append(deps, c.Pem, c.Key)
 	}
-
 	outputFiles := android.WritablePaths{signedApk}
 	var flags []string
 	if v4SignatureFile != nil {
@@ -182,7 +185,7 @@
 	packageFile, jniJarFile, dexJarFile android.Path) {
 
 	protoResJarFile := android.PathForModuleOut(ctx, "package-res.pb.apk")
-	aapt2Convert(ctx, protoResJarFile, packageFile)
+	aapt2Convert(ctx, protoResJarFile, packageFile, "proto")
 
 	var zips android.Paths
 
diff --git a/java/config/config.go b/java/config/config.go
index 03288fe..ea44aaa 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -165,6 +165,7 @@
 	pctx.HostBinToolVariable("ApiCheckCmd", "apicheck")
 	pctx.HostBinToolVariable("D8Cmd", "d8")
 	pctx.HostBinToolVariable("R8Cmd", "r8")
+	pctx.HostBinToolVariable("ResourceShrinkerCmd", "resourceshrinker")
 	pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
 	pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
 	pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
diff --git a/java/dex.go b/java/dex.go
index a44d792..de36b18 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -63,6 +63,8 @@
 		// classes referenced by the app manifest.  Defaults to false.
 		No_aapt_flags *bool
 
+		Shrink_resources *bool
+
 		// Flags to pass to proguard.
 		Proguard_flags []string
 
@@ -200,6 +202,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/prebuilt_apis.go b/java/prebuilt_apis.go
index 9449707..c6acd55 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -255,12 +255,11 @@
 	if p.properties.Extensions_dir != nil {
 		extensionApiFiles := globExtensionDirs(mctx, p, "api/*.txt")
 		for k, v := range getLatest(extensionApiFiles) {
-			if v.version > mctx.Config().PlatformBaseSdkExtensionVersion() {
-				if _, exists := latest[k]; !exists {
-					mctx.ModuleErrorf("Module %v finalized for extension %d but never during an API level; likely error", v.module, v.version)
-				}
-				latest[k] = v
+			if _, exists := latest[k]; !exists {
+				mctx.ModuleErrorf("Module %v finalized for extension %d but never during an API level; likely error", v.module, v.version)
 			}
+			// The extension version is always at least as new as the last sdk int version (potentially identical)
+			latest[k] = v
 		}
 	}
 
diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go
index 75422ad..2b84353 100644
--- a/java/prebuilt_apis_test.go
+++ b/java/prebuilt_apis_test.go
@@ -61,7 +61,7 @@
 }
 
 func TestPrebuiltApis_WithExtensions(t *testing.T) {
-	runTestWithBaseExtensionLevel := func(v int) (foo_input string, bar_input string) {
+	runTestWithBaseExtensionLevel := func(v int) (foo_input, bar_input, baz_input string) {
 		result := android.GroupFixturePreparers(
 			prepareForJavaTest,
 			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -69,7 +69,7 @@
 			}),
 			FixtureWithPrebuiltApisAndExtensions(map[string][]string{
 				"31":      {"foo"},
-				"32":      {"foo", "bar"},
+				"32":      {"foo", "bar", "baz"},
 				"current": {"foo", "bar"},
 			}, map[string][]string{
 				"1": {"foo"},
@@ -78,15 +78,24 @@
 		).RunTest(t)
 		foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String()
 		bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String()
+		baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String()
 		return
 	}
-	// Here, the base extension level is 1, so extension level 2 is the latest
-	foo_input, bar_input := runTestWithBaseExtensionLevel(1)
-	android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input)
-	android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
+	// Extension 2 is the latest for both foo and bar, finalized after the base extension version.
+	foo_input, bar_input, baz_input := runTestWithBaseExtensionLevel(1)
+	android.AssertStringEquals(t, "Expected latest foo = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input)
+	android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
+	android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input)
 
-	// Here, the base extension level is 2, so 2 is not later than 32.
-	foo_input, bar_input = runTestWithBaseExtensionLevel(2)
-	android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/foo.txt", foo_input)
-	android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/bar.txt", bar_input)
+	// Extension 2 is the latest for both foo and bar, finalized together with 32
+	foo_input, bar_input, baz_input = runTestWithBaseExtensionLevel(2)
+	android.AssertStringEquals(t, "Expected latest foo = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input)
+	android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
+	android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input)
+
+	// Extension 3 is the current extension, but it has not yet been finalized.
+	foo_input, bar_input, baz_input = runTestWithBaseExtensionLevel(3)
+	android.AssertStringEquals(t, "Expected latest foo = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input)
+	android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
+	android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input)
 }
diff --git a/java/resourceshrinker.go b/java/resourceshrinker.go
new file mode 100644
index 0000000..6d59601
--- /dev/null
+++ b/java/resourceshrinker.go
@@ -0,0 +1,43 @@
+// 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 java
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+var shrinkResources = pctx.AndroidStaticRule("shrinkResources",
+	blueprint.RuleParams{
+		Command:     `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources`,
+		CommandDeps: []string{"${config.ResourceShrinkerCmd}"},
+	}, "raw_resources")
+
+func ShrinkResources(ctx android.ModuleContext, apk android.Path, outputFile android.WritablePath) {
+	protoFile := android.PathForModuleOut(ctx, apk.Base()+".proto.apk")
+	aapt2Convert(ctx, protoFile, apk, "proto")
+	strictModeFile := android.PathForSource(ctx, "prebuilts/cmdline-tools/shrinker.xml")
+	protoOut := android.PathForModuleOut(ctx, apk.Base()+".proto.out.apk")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   shrinkResources,
+		Input:  protoFile,
+		Output: protoOut,
+		Args: map[string]string{
+			"raw_resources": strictModeFile.String(),
+		},
+	})
+	aapt2Convert(ctx, outputFile, protoOut, "binary")
+}
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 75154f9..61b17bf 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -42,7 +42,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-0BSD",
-    conditions: ["unencumbered"],
+    conditions: ["permissive"],
     url: "https://spdx.org/licenses/0BSD",
 }
 
@@ -933,7 +933,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-MIT-0",
-    conditions: ["notice"],
+    conditions: ["permissive"],
     url: "https://spdx.org/licenses/MIT-0.html",
 }
 
diff --git a/python/tests/proto_pkg_path/Android.bp b/python/tests/proto_pkg_path/Android.bp
index 17afde2..ef79850 100644
--- a/python/tests/proto_pkg_path/Android.bp
+++ b/python/tests/proto_pkg_path/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 python_test_host {
     name: "py_proto_pkg_path_test",
     main: "main.py",
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/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"`,
 				}),
 		},
diff --git a/xml/Android.bp b/xml/Android.bp
index 1542930..d4753de 100644
--- a/xml/Android.bp
+++ b/xml/Android.bp
@@ -9,6 +9,7 @@
         "blueprint",
         "blueprint-pathtools",
         "soong",
+        "soong-bp2build",
         "soong-android",
         "soong-etc",
     ],
@@ -18,6 +19,7 @@
     ],
     testSrcs: [
         "xml_test.go",
+        "xml_conversion_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/xml/xml.go b/xml/xml.go
index c281078..8c0c072 100644
--- a/xml/xml.go
+++ b/xml/xml.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/etc"
 
 	"github.com/google/blueprint"
@@ -67,6 +68,8 @@
 }
 
 type prebuiltEtcXml struct {
+	android.BazelModuleBase
+
 	etc.PrebuiltEtc
 
 	properties prebuiltEtcXmlProperties
@@ -129,5 +132,40 @@
 	etc.InitPrebuiltEtcModule(&module.PrebuiltEtc, "etc")
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	android.InitBazelModule(module)
 	return module
 }
+
+type bazelPrebuiltEtcXmlAttributes struct {
+	Src               bazel.LabelAttribute
+	Filename          bazel.LabelAttribute
+	Dir               string
+	Installable       bazel.BoolAttribute
+	Filename_from_src bazel.BoolAttribute
+	Schema            *string
+}
+
+func (p *prebuiltEtcXml) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	baseAttrs := p.PrebuiltEtc.Bp2buildHelper(ctx)
+
+	var schema *string
+	if p.properties.Schema != nil {
+		schema = p.properties.Schema
+	}
+
+	attrs := &bazelPrebuiltEtcXmlAttributes{
+		Src:               baseAttrs.Src,
+		Filename:          baseAttrs.Filename,
+		Dir:               baseAttrs.Dir,
+		Installable:       baseAttrs.Installable,
+		Filename_from_src: baseAttrs.Filename_from_src,
+		Schema:            schema,
+	}
+
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "prebuilt_xml",
+		Bzl_load_location: "//build/bazel/rules/prebuilt_xml.bzl",
+	}
+
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: p.Name()}, attrs)
+}
diff --git a/xml/xml_conversion_test.go b/xml/xml_conversion_test.go
new file mode 100644
index 0000000..6606ddc
--- /dev/null
+++ b/xml/xml_conversion_test.go
@@ -0,0 +1,129 @@
+// 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 xml
+
+import (
+	"android/soong/android"
+	"android/soong/bp2build"
+
+	"testing"
+)
+
+func runXmlPrebuiltEtcTestCase(t *testing.T, tc bp2build.Bp2buildTestCase) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "prebuilt_etc_xml"
+	(&tc).ModuleTypeUnderTestFactory = PrebuiltEtcXmlFactory
+	bp2build.RunBp2BuildTestCase(t, registerXmlModuleTypes, tc)
+}
+
+func registerXmlModuleTypes(ctx android.RegistrationContext) {
+}
+
+func TestXmlPrebuiltEtcSimple(t *testing.T) {
+	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
+		Description: "prebuilt_etc_xml - simple example",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+prebuilt_etc_xml {
+    name: "foo",
+    src: "fooSrc",
+    filename: "fooFileName",
+    sub_dir: "fooDir",
+    schema: "foo.dtd",
+}
+`,
+		ExpectedBazelTargets: []string{
+			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
+				"src":      `"fooSrc"`,
+				"filename": `"fooFileName"`,
+				"dir":      `"etc/fooDir"`,
+				"schema":   `"foo.dtd"`,
+			})}})
+}
+
+func TestXmlPrebuiltEtcFilenameFromSrc(t *testing.T) {
+	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
+		Description: "prebuilt_etc_xml - filenameFromSrc True  ",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+prebuilt_etc_xml {
+    name: "foo",
+    src: "fooSrc",
+    filename_from_src: true,
+    sub_dir: "fooDir",
+    schema: "foo.dtd",
+}
+`,
+		ExpectedBazelTargets: []string{
+			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
+				"src":      `"fooSrc"`,
+				"filename": `"fooSrc"`,
+				"dir":      `"etc/fooDir"`,
+				"schema":   `"foo.dtd"`,
+			})}})
+}
+
+func TestXmlPrebuiltEtcFilenameAndFilenameFromSrc(t *testing.T) {
+	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
+		Description: "prebuilt_etc_xml - filename provided and filenameFromSrc True  ",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+prebuilt_etc_xml {
+    name: "foo",
+    src: "fooSrc",
+    filename: "fooFileName",
+    filename_from_src: true,
+    sub_dir: "fooDir",
+    schema: "foo.dtd",
+}
+`,
+		ExpectedBazelTargets: []string{
+			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
+				"src":      `"fooSrc"`,
+				"filename": `"fooFileName"`,
+				"dir":      `"etc/fooDir"`,
+				"schema":   `"foo.dtd"`,
+			})}})
+}
+
+func TestXmlPrebuiltEtcFileNameFromSrcMultipleSrcs(t *testing.T) {
+	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
+		Description: "prebuilt_etc - filename_from_src is true but there are multiple srcs",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+prebuilt_etc_xml {
+    name: "foo",
+    filename_from_src: true,
+    arch: {
+        arm: {
+            src: "barSrc",
+        },
+        arm64: {
+            src: "bazSrc",
+        },
+    }
+}
+`,
+		ExpectedBazelTargets: []string{
+			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
+				"filename_from_src": `True`,
+				"dir":               `"etc"`,
+				"src": `select({
+        "//build/bazel/platforms/arch:arm": "barSrc",
+        "//build/bazel/platforms/arch:arm64": "bazSrc",
+        "//conditions:default": None,
+    })`,
+			})}})
+}
diff --git a/zip/cmd/BUILD.bazel b/zip/cmd/BUILD.bazel
new file mode 100644
index 0000000..e04a1e1
--- /dev/null
+++ b/zip/cmd/BUILD.bazel
@@ -0,0 +1,20 @@
+# 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.
+
+# TODO(b/194644518): Switch to the source version when Bazel can build go
+# binaries.
+alias(
+    name = "soong_zip",
+    actual = "//prebuilts/build-tools:linux-x86/bin/soong_zip",
+)