Merge "Remove build failure with USE_BAZEL_ANALYSIS usage"
diff --git a/OWNERS b/OWNERS
index 730db7a..e18eea1 100644
--- a/OWNERS
+++ b/OWNERS
@@ -14,6 +14,7 @@
 eakammer@google.com
 jobredeaux@google.com
 joeo@google.com
+juu@google.com
 lamontjones@google.com
 spandandas@google.com
 tradical@google.com
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 a39c368..9bba3c3 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -37,6 +37,7 @@
 
 var (
 	Bp2buildDefaultConfig = Bp2BuildConfig{
+		"art":                                   Bp2BuildDefaultTrue,
 		"art/libartbase":                        Bp2BuildDefaultTrueRecursively,
 		"art/libartpalette":                     Bp2BuildDefaultTrueRecursively,
 		"art/libdexfile":                        Bp2BuildDefaultTrueRecursively,
@@ -44,6 +45,9 @@
 		"art/runtime":                           Bp2BuildDefaultTrueRecursively,
 		"art/tools":                             Bp2BuildDefaultTrue,
 		"bionic":                                Bp2BuildDefaultTrueRecursively,
+		"bootable/recovery/minadbd":             Bp2BuildDefaultTrue,
+		"bootable/recovery/minui":               Bp2BuildDefaultTrue,
+		"bootable/recovery/recovery_utils":      Bp2BuildDefaultTrue,
 		"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
 
 		"build/bazel":                        Bp2BuildDefaultTrueRecursively,
@@ -54,6 +58,7 @@
 		"build/soong/cc/libbuildversion":     Bp2BuildDefaultTrue, // Skip tests subdir
 		"build/soong/cc/ndkstubgen":          Bp2BuildDefaultTrue,
 		"build/soong/cc/symbolfile":          Bp2BuildDefaultTrue,
+		"build/soong/licenses":               Bp2BuildDefaultTrue,
 		"build/soong/linkerconfig":           Bp2BuildDefaultTrueRecursively,
 		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
 
@@ -98,6 +103,7 @@
 		"external/aac":                           Bp2BuildDefaultTrueRecursively,
 		"external/arm-optimized-routines":        Bp2BuildDefaultTrueRecursively,
 		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
+		"external/auto":                          Bp2BuildDefaultTrue,
 		"external/auto/common":                   Bp2BuildDefaultTrueRecursively,
 		"external/auto/service":                  Bp2BuildDefaultTrueRecursively,
 		"external/boringssl":                     Bp2BuildDefaultTrueRecursively,
@@ -121,16 +127,18 @@
 		"external/icu/icu4j":                     Bp2BuildDefaultFalse, // java rules incomplete
 		"external/jacoco":                        Bp2BuildDefaultTrueRecursively,
 		"external/jarjar":                        Bp2BuildDefaultTrueRecursively,
-		"external/javassist":                     Bp2BuildDefaultTrueRecursively,
 		"external/javaparser":                    Bp2BuildDefaultTrueRecursively,
 		"external/javapoet":                      Bp2BuildDefaultTrueRecursively,
+		"external/javassist":                     Bp2BuildDefaultTrueRecursively,
 		"external/jemalloc_new":                  Bp2BuildDefaultTrueRecursively,
 		"external/jsoncpp":                       Bp2BuildDefaultTrueRecursively,
 		"external/junit":                         Bp2BuildDefaultTrueRecursively,
+		"external/libaom":                        Bp2BuildDefaultTrueRecursively,
 		"external/libavc":                        Bp2BuildDefaultTrueRecursively,
 		"external/libcap":                        Bp2BuildDefaultTrueRecursively,
 		"external/libcxx":                        Bp2BuildDefaultTrueRecursively,
 		"external/libcxxabi":                     Bp2BuildDefaultTrueRecursively,
+		"external/libdrm":                        Bp2BuildDefaultTrue,
 		"external/libevent":                      Bp2BuildDefaultTrueRecursively,
 		"external/libgav1":                       Bp2BuildDefaultTrueRecursively,
 		"external/libhevc":                       Bp2BuildDefaultTrueRecursively,
@@ -143,6 +151,7 @@
 		"external/lzma/C":                        Bp2BuildDefaultTrueRecursively,
 		"external/mdnsresponder":                 Bp2BuildDefaultTrueRecursively,
 		"external/minijail":                      Bp2BuildDefaultTrueRecursively,
+		"external/objenesis":                     Bp2BuildDefaultTrueRecursively,
 		"external/openscreen":                    Bp2BuildDefaultTrueRecursively,
 		"external/pcre":                          Bp2BuildDefaultTrueRecursively,
 		"external/protobuf":                      Bp2BuildDefaultTrueRecursively,
@@ -159,12 +168,16 @@
 
 		"frameworks/av":                                      Bp2BuildDefaultTrue,
 		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/codec2/components/aom":          Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/module/minijail":                Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
 		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
 		"frameworks/base/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
 		"frameworks/base/startop/apps/test":                  Bp2BuildDefaultTrue,
 		"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/tools/aapt2":                        Bp2BuildDefaultTrue,
 		"frameworks/native/libs/adbd_auth":                   Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/arect":                       Bp2BuildDefaultTrueRecursively,
 		"frameworks/native/libs/math":                        Bp2BuildDefaultTrueRecursively,
@@ -174,6 +187,7 @@
 		"frameworks/native/opengl/tests/testLatency":         Bp2BuildDefaultTrue,
 		"frameworks/native/opengl/tests/testPauseResume":     Bp2BuildDefaultTrue,
 		"frameworks/native/opengl/tests/testViewport":        Bp2BuildDefaultTrue,
+		"frameworks/native/services/batteryservice":          Bp2BuildDefaultTrue,
 		"frameworks/proto_logging/stats/stats_log_api_gen":   Bp2BuildDefaultTrueRecursively,
 
 		"hardware/interfaces":                          Bp2BuildDefaultTrue,
@@ -181,6 +195,7 @@
 		"hardware/interfaces/configstore/1.0":          Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/1.1":          Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/utils":        Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/aidl":  Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/2.0":   Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/3.0":   Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/4.0":   Bp2BuildDefaultTrue,
@@ -194,6 +209,14 @@
 		"hardware/interfaces/graphics/mapper/2.1":      Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/mapper/3.0":      Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/mapper/4.0":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/1.0":               Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/1.0/default":       Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/2.0":               Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/2.0/default":       Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/2.0/utils":         Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/health/2.1":               Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/aidl":              Bp2BuildDefaultTrue,
+		"hardware/interfaces/health/utils":             Bp2BuildDefaultTrueRecursively,
 		"hardware/interfaces/media/1.0":                Bp2BuildDefaultTrue,
 		"hardware/interfaces/media/bufferpool/2.0":     Bp2BuildDefaultTrue,
 		"hardware/interfaces/media/c2/1.0":             Bp2BuildDefaultTrue,
@@ -211,6 +234,7 @@
 		"packages/apps/DevCamera":                          Bp2BuildDefaultTrue,
 		"packages/apps/HTMLViewer":                         Bp2BuildDefaultTrue,
 		"packages/apps/Protips":                            Bp2BuildDefaultTrue,
+		"packages/apps/SafetyRegulatoryInfo":               Bp2BuildDefaultTrue,
 		"packages/apps/WallpaperPicker":                    Bp2BuildDefaultTrue,
 		"packages/modules/StatsD/lib/libstatssocket":       Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb":                             Bp2BuildDefaultTrue,
@@ -222,6 +246,7 @@
 		"packages/modules/adb/proto":                       Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb/tls":                         Bp2BuildDefaultTrueRecursively,
 		"packages/providers/MediaProvider/tools/dialogs":   Bp2BuildDefaultFalse, // TODO(b/242834374)
+		"packages/modules/NeuralNetworks/driver/cache":     Bp2BuildDefaultTrueRecursively,
 		"packages/screensavers/Basic":                      Bp2BuildDefaultTrue,
 		"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
 
@@ -231,6 +256,7 @@
 		"prebuilts/runtime/mainline/platform/sdk":  Bp2BuildDefaultTrueRecursively,
 		"prebuilts/sdk/current/extras/app-toolkit": Bp2BuildDefaultTrue,
 		"prebuilts/sdk/current/support":            Bp2BuildDefaultTrue,
+		"prebuilts/tools":                          Bp2BuildDefaultTrue,
 		"prebuilts/tools/common/m2":                Bp2BuildDefaultTrue,
 
 		"system/apex":                                            Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
@@ -240,6 +266,8 @@
 		"system/apex/tools":                                      Bp2BuildDefaultTrueRecursively,
 		"system/core/debuggerd":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/diagnose_usb":                               Bp2BuildDefaultTrueRecursively,
+		"system/core/healthd":                                    Bp2BuildDefaultTrue,
+		"system/core/healthd/testdata":                           Bp2BuildDefaultTrue,
 		"system/core/libasyncio":                                 Bp2BuildDefaultTrue,
 		"system/core/libcrypto_utils":                            Bp2BuildDefaultTrueRecursively,
 		"system/core/libcutils":                                  Bp2BuildDefaultTrueRecursively,
@@ -247,12 +275,14 @@
 		"system/core/libprocessgroup":                            Bp2BuildDefaultTrue,
 		"system/core/libprocessgroup/cgrouprc":                   Bp2BuildDefaultTrue,
 		"system/core/libprocessgroup/cgrouprc_format":            Bp2BuildDefaultTrue,
+		"system/core/libsuspend":                                 Bp2BuildDefaultTrue,
 		"system/core/libsystem":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/libsysutils":                                Bp2BuildDefaultTrueRecursively,
 		"system/core/libutils":                                   Bp2BuildDefaultTrueRecursively,
 		"system/core/libvndksupport":                             Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoparser":     Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoserializer": Bp2BuildDefaultTrueRecursively,
+		"system/incremental_delivery/incfs":                      Bp2BuildDefaultTrue,
 		"system/libartpalette":                                   Bp2BuildDefaultTrueRecursively,
 		"system/libbase":                                         Bp2BuildDefaultTrueRecursively,
 		"system/libfmq":                                          Bp2BuildDefaultTrue,
@@ -272,6 +302,7 @@
 		"system/libprocinfo":                                     Bp2BuildDefaultTrue,
 		"system/libziparchive":                                   Bp2BuildDefaultTrueRecursively,
 		"system/logging":                                         Bp2BuildDefaultTrueRecursively,
+		"system/media":                                           Bp2BuildDefaultTrue,
 		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
 		"system/media/audio_utils":                               Bp2BuildDefaultTrueRecursively,
 		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
@@ -280,10 +311,12 @@
 		"system/testing/gtest_extras":                            Bp2BuildDefaultTrueRecursively,
 		"system/timezone/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/timezone/output_data":                            Bp2BuildDefaultTrueRecursively,
-		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/tools/aidl/build/tests_bp2build":                 Bp2BuildDefaultTrue,
+		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/unwinding/libunwindstack":                        Bp2BuildDefaultTrueRecursively,
 
+		"frameworks/proto_logging/stats": Bp2BuildDefaultTrueRecursively,
+
 		"tools/apksig": Bp2BuildDefaultTrue,
 		"tools/platform-compat/java/android/compat":  Bp2BuildDefaultTrueRecursively,
 		"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
@@ -298,16 +331,21 @@
 		// 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
 		"external/bazelbuild-rules_android":/* recursive = */ true,
+		"external/bazelbuild-rules_license":/* recursive = */ true,
 		"external/bazelbuild-kotlin-rules":/* recursive = */ true,
 		"external/bazel-skylib":/* recursive = */ true,
 		"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,
 
@@ -327,21 +365,28 @@
 	}
 
 	Bp2buildModuleAlwaysConvertList = []string{
+		"libidmap2_policies",
+		"libSurfaceFlingerProp",
 		// cc mainline modules
 		"code_coverage.policy",
 		"code_coverage.policy.other",
 		"codec2_soft_exports",
+		"codecs_g711dec",
+		"com.android.media.swcodec",
 		"com.android.media.swcodec-androidManifest",
 		"com.android.media.swcodec-ld.config.txt",
+		"com.android.media.swcodec-mediaswcodec.32rc",
 		"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",
 		"flatbuffer_headers",
 		"gemmlowp_headers",
 		"gl_headers",
+		"libaidlcommonsupport",
 		"libandroid_runtime_lazy",
 		"libandroid_runtime_vm_headers",
 		"libaudioclient_aidl_conversion_util",
@@ -350,6 +395,7 @@
 		"libbinder_aidl",
 		"libbinder_headers",
 		"libbinder_headers_platform_shared",
+		"libbinderthreadstateutils",
 		"libbluetooth-types-header",
 		"libbufferhub_headers",
 		"libcodec2",
@@ -359,12 +405,17 @@
 		"libdvr_headers",
 		"libgsm",
 		"libgui_bufferqueue_sources",
+		"libgrallocusage",
+		"libgralloctypes",
+		"libnativewindow",
+		"libneuralnetworks",
+		"libgraphicsenv",
 		"libhardware",
 		"libhardware_headers",
-		"libincfs_headers",
 		"libnativeloader-headers",
 		"libnativewindow_headers",
 		"libneuralnetworks_headers",
+		"libneuralnetworks_packageinfo",
 		"libopus",
 		"libpdx_headers",
 		"libprocpartition",
@@ -372,15 +423,28 @@
 		"libandroidio",
 		"libandroidio_srcs",
 		"libserviceutils",
+		"libstagefright_amrnbenc",
+		"libstagefright_amrnbdec",
+		"libstagefright_amrwbdec",
+		"libstagefright_amrwbenc",
+		"libstagefright_amrnb_common",
 		"libstagefright_enc_common",
+		"libstagefright_flacdec",
+		"libstagefright_foundation",
 		"libstagefright_foundation_headers",
 		"libstagefright_headers",
+		"libstagefright_m4vh263dec",
+		"libstagefright_m4vh263enc",
+		"libstagefright_mp3dec",
+		"libstagefright_mp3dec_headers",
 		"libsurfaceflinger_headers",
 		"libsync",
 		"libtextclassifier_hash_headers",
 		"libtextclassifier_hash_static",
 		"libtflite_kernel_utils",
 		"libtinyxml2",
+		"libgui_aidl",
+		"libui",
 		"libui-types",
 		"libui_headers",
 		"libvorbisidec",
@@ -388,11 +452,29 @@
 		"media_plugin_headers",
 		"mediaswcodec.policy",
 		"mediaswcodec.xml",
+		"neuralnetworks_types",
+		"neuralnetworks_utils_hal_aidl",
+		"neuralnetworks_utils_hal_common",
+		"neuralnetworks_utils_hal_service",
+		"neuralnetworks_utils_hal_1_0",
+		"neuralnetworks_utils_hal_1_1",
+		"neuralnetworks_utils_hal_1_2",
+		"neuralnetworks_utils_hal_1_3",
+		"libneuralnetworks_common",
+		// packagemanager_aidl_interface is created implicitly in packagemanager_aidl module
+		"packagemanager_aidl_interface",
 		"philox_random",
 		"philox_random_headers",
 		"server_configurable_flags",
+		"statslog_neuralnetworks.cpp",
+		"statslog_neuralnetworks.h",
 		"tensorflow_headers",
 
+		"libgui_headers",
+		"libstagefright_bufferpool@2.0",
+		"libstagefright_bufferpool@2.0.1",
+		"libSurfaceFlingerProp",
+
 		// fastboot
 		"bootimg_headers",
 		"fastboot",
@@ -405,6 +487,10 @@
 		"libavb",
 		"avb_headers",
 
+		//external/libxml2
+		"xmllint",
+		"libxml2",
+
 		//external/fec
 		"libfec_rs",
 
@@ -455,16 +541,117 @@
 
 		//frameworks/native/cmds/cmd
 		"libcmd",
+
+		//system/core/fs_mgr/libdm
+		"libdm",
+
+		//system/core/fs_mgr/libfiemap
+		"libfiemap_headers",
+		"libfiemap_passthrough_srcs",
+		"libfiemap_srcs",
+
+		//system/gsid
+		"libgsi",
+		"libgsi_headers",
+
+		//system/core/libkeyutils
+		"libkeyutils",
+
+		//bootable/recovery/otautil
+		"libotautil",
+
+		//system/vold
+		"libvold_headers",
+
+		//system/extras/libfscrypt
+		"libfscrypt",
+
+		//system/core/fs_mgr
+		"libfstab",
+
+		//bootable/recovery/fuse_sideload
+		"libfusesideload",
+
+		//system/core/fs_mgr/libfs_avb
+		"libfs_avb",
+
+		//system/core/fs_mgr
+		"libfs_mgr",
+
+		"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",
+
+		"mediaswcodec",
+		"libmedia_headers",
+		"libmedia_codecserviceregistrant",
+		"libsfplugin_ccodec_utils",
+		"libcodec2_soft_aacenc",
+		"libcodec2_soft_amrnbdec",
+		"libcodec2_soft_amrnbenc",
+		"libcodec2_soft_amrwbdec",
+		"libcodec2_soft_amrwbenc",
+		"libcodec2_soft_hevcdec",
+		"libcodec2_soft_hevcenc",
+		"libcodec2_soft_g711alawdec",
+		"libcodec2_soft_g711mlawdec",
+		"libcodec2_soft_mpeg2dec",
+		"libcodec2_soft_h263dec",
+		"libcodec2_soft_h263enc",
+		"libcodec2_soft_mpeg4dec",
+		"libcodec2_soft_mpeg4enc",
+		"libcodec2_soft_mp3dec",
+		"libcodec2_soft_vorbisdec",
+		"libcodec2_soft_opusdec",
+		"libcodec2_soft_opusenc",
+		"libcodec2_soft_vp8dec",
+		"libcodec2_soft_vp9dec",
+		"libcodec2_soft_av1dec_gav1",
+		"libcodec2_soft_vp8enc",
+		"libcodec2_soft_vp9enc",
+		"libcodec2_soft_rawdec",
+		"libcodec2_soft_flacdec",
+		"libcodec2_soft_flacenc",
+		"libcodec2_soft_gsmdec",
+		"libcodec2_soft_avcdec",
+		"libcodec2_soft_avcenc",
+		"libcodec2_soft_aacdec",
+		"libcodec2_soft_common",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
+		"aidl_interface_headers",
+		"api_domain",
+		"license",
 		"linker_config",
 		"java_import",
 		"java_import_host",
+		"ndk_headers",
+		"ndk_library",
 		"sysprop_library",
-		"aidl_interface_headers",
+		"bpf",
 	}
 
+	// 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
@@ -502,32 +689,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
-
-		// proto support
-		"libstats_proto_host", // TODO(b/236055697): handle protos from other packages
+		// 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:
-		"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_zlib_headers",                                          // depends on soong_zip and zip2zip
-		"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
-		"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
@@ -543,8 +724,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
@@ -569,19 +750,29 @@
 		"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
-		"stats-log-api-gen",                         // depends on unconverted modules: libstats_proto_host
-		"statslog.cpp", "statslog.h", "statslog.rs", // depends on unconverted modules: stats-log-api-gen
-		"statslog_art.cpp", "statslog_art.h", "statslog_header.rs", // depends on unconverted modules: stats-log-api-gen
-		"test_fips",           // depends on unconverted modules: adb
-		"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",
 
+		// aidl files not created
+		"overlayable_policy_aidl_interface",
+
+		//prebuilts/tools/common/m2
+		// depends on //external/okio:okio-lib, which uses kotlin
+		"wire-runtime",
+
+		// depends on adbd_system_api_recovery, which is a unconverted `phony` module type
+		"minadbd",
+
+		// depends on android.hardware.health-V2.0-java
+		"android.hardware.health-translate-java",
+
 		// cc_test related.
 		// Failing host cc_tests
 		"memunreachable_unit_test",
@@ -606,6 +797,8 @@
 		"libnativebridge6-test-case",
 		"libnativebridge6prezygotefork",
 
+		"libandroidfw_tests", "aapt2_tests", // failing due to data path issues
+
 		// cc_test with unconverted deps, or are device-only (and not verified to pass yet)
 		"AMRWBEncTest",
 		"AmrnbDecoderTest",     // depends on unconverted modules: libaudioutils, libsndfile
@@ -663,7 +856,6 @@
 		"libBionicCtsGtestMain", // depends on unconverted modules: libgtest_isolated
 		"libBionicLoaderTests",  // depends on unconverted modules: libmeminfo
 		"libapexutil_tests",     // depends on unconverted modules: apex-info-list-tinyxml, libapexutil
-		"libavservices_minijail_unittest",
 		"libcutils_sockets_test",
 		"libexpectedutils_test",
 		"libhwbinder_latency",
@@ -1035,6 +1227,12 @@
 		"libtest_with_dependency_loop_b_tmp",
 		"libtest_with_dependency_loop_c",
 		"libtestshared",
+
+		// depends on unconverted libprotobuf-java-nano
+		"dnsresolverprotosnano",
+		"launcherprotosnano",
+		"datastallprotosnano",
+		"devicepolicyprotosnano",
 	}
 
 	Bp2buildCcLibraryStaticOnlyList = []string{}
@@ -1083,6 +1281,20 @@
 		"prebuilt_platform-robolectric-4.4-prebuilt",
 		"prebuilt_platform-robolectric-4.5.1-prebuilt",
 		"prebuilt_currysrc_org.eclipse",
+
+		// TODO(b/247782695 and/or b/242847534) Fix mixed build between unconverted gensrcs and converted filegroup
+		"libstats_atom_enum_protos",
+		"data_stall_event_proto",
+		"device_policy_proto",
+		"dns_resolver_proto",
+		"launcher_proto",
+		"network_stack_proto",
+		"srcs_bluetooth_protos",
+		"srcs_bluetooth_leaudio_protos",
+		"style_proto",
+		"tethering_proto",
+		"text_classifier_proto",
+		"libstats_atom_message_protos",
 	}
 
 	ProdMixedBuildsEnabledList = []string{
diff --git a/android/androidmk.go b/android/androidmk.go
index 006e43d..18e3e7a 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -366,7 +366,9 @@
 	// Collate the contributions this module makes to the dist.
 	distContributions := &distContributions{}
 
-	distContributions.licenseMetadataFile = amod.licenseMetadataFile
+	if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) {
+		distContributions.licenseMetadataFile = amod.licenseMetadataFile
+	}
 
 	// Iterate over this module's dist structs, merged from the dist and dists properties.
 	for _, dist := range amod.Dists() {
@@ -458,10 +460,12 @@
 		ret = append(ret, fmt.Sprintf(".PHONY: %s\n", d.goals))
 		// Create dist-for-goals calls for each of the copy instructions.
 		for _, c := range d.copies {
-			ret = append(
-				ret,
-				fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
-					c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
+			if distContributions.licenseMetadataFile != nil {
+				ret = append(
+					ret,
+					fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n",
+						c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String()))
+			}
 			ret = append(
 				ret,
 				fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest))
diff --git a/android/apex.go b/android/apex.go
index 00b7241..3c945ae 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -454,8 +454,6 @@
 	}
 	return InList(what, apex_available) ||
 		(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
-		(what == "com.android.btservices" && InList("com.android.bluetooth", apex_available)) || // TODO b/243054261
-		(what == "com.android.bluetooth" && InList("com.android.btservices", apex_available)) || // TODO b/243054261
 		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available))
 }
 
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/arch.go b/android/arch.go
index 9bc9d89..75ee922 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -147,10 +147,11 @@
 var (
 	archTypeList []ArchType
 
-	Arm    = newArch("arm", "lib32")
-	Arm64  = newArch("arm64", "lib64")
-	X86    = newArch("x86", "lib32")
-	X86_64 = newArch("x86_64", "lib64")
+	Arm     = newArch("arm", "lib32")
+	Arm64   = newArch("arm64", "lib64")
+	Riscv64 = newArch("riscv64", "lib64")
+	X86     = newArch("x86", "lib32")
+	X86_64  = newArch("x86_64", "lib64")
 
 	Common = ArchType{
 		Name: COMMON_VARIANT,
@@ -318,7 +319,7 @@
 	Windows = newOsType("windows", Host, true, X86, X86_64)
 	// Android is the OS for target devices that run all of Android, including the Linux kernel
 	// and the Bionic libc runtime.
-	Android = newOsType("android", Device, false, Arm, Arm64, X86, X86_64)
+	Android = newOsType("android", Device, false, Arm, Arm64, Riscv64, X86, X86_64)
 
 	// CommonOS is a pseudo OSType for a common OS variant, which is OsType agnostic and which
 	// has dependencies on all the OS variants.
diff --git a/android/arch_test.go b/android/arch_test.go
index 6814f8a..46c018a 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -596,6 +596,7 @@
 				arm64: {
 					a:  ["arm64"],
 				},
+				riscv64: { a: ["riscv64"] },
 				x86: { a:  ["x86"] },
 				x86_64: { a:  ["x86_64"] },
 			},
diff --git a/android/bazel.go b/android/bazel.go
index eb6aca4..dd1de7b 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -32,10 +32,13 @@
 	Bp2BuildTopLevel = "."
 )
 
-// Bp2buildAidlLibrary describes a filegroup module that are converted to aidl_library
-type Bp2buildAidlLibrary interface {
+// FileGroupAsLibrary describes a filegroup module that is converted to some library
+// such as aidl_library or proto_library.
+type FileGroupAsLibrary interface {
 	ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool
+	ShouldConvertToProtoLibrary(ctx BazelConversionPathContext) bool
 	GetAidlLibraryLabel(ctx BazelConversionPathContext) string
+	GetProtoLibraryLabel(ctx BazelConversionPathContext) string
 }
 
 type BazelConversionStatus struct {
@@ -443,8 +446,8 @@
 	if ok, directoryPath := bp2buildDefaultTrueRecursively(packagePath, allowlist.defaultConfig); ok {
 		if moduleNameAllowed {
 			ctx.ModuleErrorf("A module cannot be in a directory marked Bp2BuildDefaultTrue"+
-				" or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: '%s'",
-				directoryPath)
+				" or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: '%s'"+
+				" Module: '%s'", directoryPath, moduleName)
 			return false
 		}
 
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 3e490dd..e81086d 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -104,9 +104,16 @@
 	configKey   configKey
 }
 
+func makeCqueryKey(label string, cqueryRequest cqueryRequest, cfgKey configKey) cqueryKey {
+	if strings.HasPrefix(label, "//") {
+		// Normalize Bazel labels to specify main repository explicitly.
+		label = "@" + label
+	}
+	return cqueryKey{label, cqueryRequest, cfgKey}
+}
+
 func (c cqueryKey) String() string {
 	return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey)
-
 }
 
 // BazelContext is a context object useful for interacting with Bazel during
@@ -160,7 +167,8 @@
 }
 
 type bazelRunner interface {
-	issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) (string, string, error)
+	createBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
+	issueBazelCommand(bazelCmd *exec.Cmd) (output string, errorMessage string, error error)
 }
 
 type bazelPaths struct {
@@ -261,23 +269,24 @@
 var _ BazelContext = MockBazelContext{}
 
 func (bazelCtx *bazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
-	key := cqueryKey{label, requestType, cfgKey}
+	key := makeCqueryKey(label, requestType, cfgKey)
 	bazelCtx.requestMutex.Lock()
 	defer bazelCtx.requestMutex.Unlock()
 	bazelCtx.requests[key] = true
 }
 
 func (bazelCtx *bazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
-	key := cqueryKey{label, cquery.GetOutputFiles, cfgKey}
+	key := makeCqueryKey(label, cquery.GetOutputFiles, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		bazelOutput := strings.TrimSpace(rawString)
+
 		return cquery.GetOutputFiles.ParseResult(bazelOutput), nil
 	}
 	return nil, fmt.Errorf("no bazel response found for %v", key)
 }
 
 func (bazelCtx *bazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
-	key := cqueryKey{label, cquery.GetCcInfo, cfgKey}
+	key := makeCqueryKey(label, cquery.GetCcInfo, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		bazelOutput := strings.TrimSpace(rawString)
 		return cquery.GetCcInfo.ParseResult(bazelOutput)
@@ -286,7 +295,7 @@
 }
 
 func (bazelCtx *bazelContext) GetPythonBinary(label string, cfgKey configKey) (string, error) {
-	key := cqueryKey{label, cquery.GetPythonBinary, cfgKey}
+	key := makeCqueryKey(label, cquery.GetPythonBinary, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		bazelOutput := strings.TrimSpace(rawString)
 		return cquery.GetPythonBinary.ParseResult(bazelOutput), nil
@@ -295,7 +304,7 @@
 }
 
 func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) {
-	key := cqueryKey{label, cquery.GetApexInfo, cfgKey}
+	key := makeCqueryKey(label, cquery.GetApexInfo, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString)), nil
 	}
@@ -452,16 +461,30 @@
 
 type mockBazelRunner struct {
 	bazelCommandResults map[bazelCommand]string
-	commands            []bazelCommand
-	extraFlags          []string
+	// use *exec.Cmd as a key to get the bazelCommand, the map will be used in issueBazelCommand()
+	// Register createBazelCommand() invocations. Later, an
+	// issueBazelCommand() invocation can be mapped to the *exec.Cmd instance
+	// and then to the expected result via bazelCommandResults
+	tokens     map[*exec.Cmd]bazelCommand
+	commands   []bazelCommand
+	extraFlags []string
 }
 
-func (r *mockBazelRunner) issueBazelCommand(_ *bazelPaths, _ bazel.RunName,
-	command bazelCommand, extraFlags ...string) (string, string, error) {
+func (r *mockBazelRunner) createBazelCommand(paths *bazelPaths, runName bazel.RunName,
+	command bazelCommand, extraFlags ...string) *exec.Cmd {
 	r.commands = append(r.commands, command)
 	r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
-	if ret, ok := r.bazelCommandResults[command]; ok {
-		return ret, "", nil
+	cmd := &exec.Cmd{}
+	if r.tokens == nil {
+		r.tokens = make(map[*exec.Cmd]bazelCommand)
+	}
+	r.tokens[cmd] = command
+	return cmd
+}
+
+func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd) (string, string, error) {
+	if command, ok := r.tokens[bazelCmd]; ok {
+		return r.bazelCommandResults[command], "", nil
 	}
 	return "", "", nil
 }
@@ -472,8 +495,20 @@
 // Returns (stdout, stderr, error). The first and second return values are strings
 // containing the stdout and stderr of the run command, and an error is returned if
 // the invocation returned an error code.
-func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
-	extraFlags ...string) (string, string, error) {
+
+func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd) (string, string, error) {
+	stderr := &bytes.Buffer{}
+	bazelCmd.Stderr = stderr
+	if output, err := bazelCmd.Output(); err != nil {
+		return "", string(stderr.Bytes()),
+			fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr)
+	} else {
+		return string(output), string(stderr.Bytes()), nil
+	}
+}
+
+func (r *builtinBazelRunner) createBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
+	extraFlags ...string) *exec.Cmd {
 	cmdFlags := []string{
 		"--output_base=" + absolutePath(paths.outputBase),
 		command.command,
@@ -517,15 +552,14 @@
 		"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
 	}
 	bazelCmd.Env = append(os.Environ(), extraEnv...)
-	stderr := &bytes.Buffer{}
-	bazelCmd.Stderr = stderr
 
-	if output, err := bazelCmd.Output(); err != nil {
-		return "", string(stderr.Bytes()),
-			fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr)
-	} else {
-		return string(output), string(stderr.Bytes()), nil
-	}
+	return bazelCmd
+}
+
+func printableCqueryCommand(bazelCmd *exec.Cmd) string {
+	outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(bazelCmd.Args, "\" \"") + "\""
+	return outputString
+
 }
 
 func (context *bazelContext) mainBzlFileContents() []byte {
@@ -755,6 +789,10 @@
 def format(target):
   id_string = str(target.label) + "|" + get_arch(target)
 
+  # TODO(b/248106697): Remove once Bazel is updated to always normalize labels.
+  if id_string.startswith("//"):
+    id_string = "@" + id_string
+
   # Main switch section
   %s
   # This target was not requested via cquery, and thus must be a dependency
@@ -826,15 +864,16 @@
 
 	const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
 	cqueryCmd := bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
-	cqueryOutput, cqueryErr, err := context.issueBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
+	cqueryCommandWithFlag := context.createBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
 		"--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
+	cqueryOutput, cqueryErr, err := context.issueBazelCommand(cqueryCommandWithFlag)
 	if err != nil {
 		return err
 	}
-	if err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666); err != nil {
+	cqueryCommandPrint := fmt.Sprintf("cquery command line:\n  %s \n\n\n", printableCqueryCommand(cqueryCommandWithFlag))
+	if err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryCommandPrint+cqueryOutput), 0666); err != nil {
 		return err
 	}
-
 	cqueryResults := map[string]string{}
 	for _, outputLine := range strings.Split(cqueryOutput, "\n") {
 		if strings.Contains(outputLine, ">>") {
@@ -870,8 +909,8 @@
 		}
 	}
 	aqueryCmd := bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
-	if aqueryOutput, _, err := context.issueBazelCommand(context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
-		extraFlags...); err == nil {
+	if aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
+		extraFlags...)); err == nil {
 		context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput))
 	}
 	if err != nil {
@@ -882,7 +921,7 @@
 	// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
 	// but some of symlinks may be required to resolve source dependencies of the build.
 	buildCmd := bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
-	if _, _, err = context.issueBazelCommand(context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd); err != nil {
+	if _, _, err = context.issueBazelCommand(context.createBazelCommand(context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd)); err != nil {
 		return err
 	}
 
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index ec2541b..dc2261c 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -13,10 +13,10 @@
 var testConfig = TestConfig("out", nil, "", nil)
 
 func TestRequestResultsAfterInvokeBazel(t *testing.T) {
-	label := "//foo:bar"
+	label := "@//foo:bar"
 	cfg := configKey{"arm64_armv8-a", Android}
 	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
-		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
+		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
 	})
 	bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
 	err := bazelContext.InvokeBazel(testConfig)
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index bbdae96..9c50098 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
@@ -242,17 +248,37 @@
 		newPath.Label = path.Label
 		return newPath
 	}
-
-	newLabel := ""
+	if strings.HasPrefix(path.Label, "./") {
+		// Drop "./" for consistent handling of paths.
+		// Specifically, to not let "." be considered a package boundary.
+		// Say `inputPath` is `x/Android.bp` and that file has some module
+		// with `srcs=["y/a.c", "z/b.c"]`.
+		// And say the directory tree is:
+		//     x
+		//     ├── Android.bp
+		//     ├── y
+		//     │   ├── a.c
+		//     │   └── Android.bp
+		//     └── z
+		//         └── b.c
+		// Then bazel equivalent labels in srcs should be:
+		//   //x/y:a.c, x/z/b.c
+		// The above should still be the case if `x/Android.bp` had
+		//   srcs=["./y/a.c", "./z/b.c"]
+		// However, if we didn't strip "./", we'd get
+		//   //x/./y:a.c, //x/.:z/b.c
+		path.Label = strings.TrimPrefix(path.Label, "./")
+	}
 	pathComponents := strings.Split(path.Label, "/")
-	foundBlueprint := false
+	newLabel := ""
+	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 +288,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/bazel_paths_test.go b/android/bazel_paths_test.go
index b047511..450bf76 100644
--- a/android/bazel_paths_test.go
+++ b/android/bazel_paths_test.go
@@ -17,6 +17,10 @@
 import (
 	"path/filepath"
 	"testing"
+
+	"android/soong/bazel"
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
 )
 
 type TestBazelPathContext struct{}
@@ -29,7 +33,7 @@
 	return cfg
 }
 
-func (*TestBazelPathContext) AddNinjaFileDeps(deps ...string) {
+func (*TestBazelPathContext) AddNinjaFileDeps(...string) {
 	panic("Unimplemented")
 }
 
@@ -106,3 +110,74 @@
 		t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
 	}
 }
+
+type TestBazelConversionPathContext struct {
+	TestBazelConversionContext
+	moduleDir string
+	cfg       Config
+}
+
+func (ctx *TestBazelConversionPathContext) AddNinjaFileDeps(...string) {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) GlobWithDeps(string, []string) ([]string, error) {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) PropertyErrorf(string, string, ...interface{}) {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) GetDirectDep(string) (blueprint.Module, blueprint.DependencyTag) {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) ModuleFromName(string) (blueprint.Module, bool) {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) AddUnconvertedBp2buildDep(string) {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) AddMissingBp2buildDep(string) {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) Module() Module {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) Config() Config {
+	return ctx.cfg
+}
+
+func (ctx *TestBazelConversionPathContext) ModuleDir() string {
+	return ctx.moduleDir
+}
+
+func TestTransformSubpackagePath(t *testing.T) {
+	cfg := NullConfig("out", "out/soong")
+	cfg.fs = pathtools.MockFs(map[string][]byte{
+		"x/Android.bp":   nil,
+		"x/y/Android.bp": nil,
+	})
+
+	var ctx BazelConversionPathContext = &TestBazelConversionPathContext{
+		moduleDir: "x",
+		cfg:       cfg,
+	}
+	pairs := map[string]string{
+		"y/a.c":   "//x/y:a.c",
+		"./y/a.c": "//x/y:a.c",
+		"z/b.c":   "z/b.c",
+		"./z/b.c": "z/b.c",
+	}
+	for in, out := range pairs {
+		actual := transformSubpackagePath(ctx, bazel.Label{Label: in}).Label
+		if actual != out {
+			t.Errorf("expected:\n%v\nactual:\n%v", out, actual)
+		}
+	}
+}
diff --git a/android/bazel_test.go b/android/bazel_test.go
index b578cca..dbe6067 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -266,7 +266,7 @@
 		{
 			description:    "module allowlist and enabled directory",
 			shouldConvert:  false,
-			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir'"},
+			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"},
 			module: TestBazelModule{
 				TestModuleInfo: bazel.TestModuleInfo{
 					ModuleName: "foo",
@@ -287,7 +287,7 @@
 		{
 			description:    "module allowlist and enabled subdirectory",
 			shouldConvert:  false,
-			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir'"},
+			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"},
 			module: TestBazelModule{
 				TestModuleInfo: bazel.TestModuleInfo{
 					ModuleName: "foo",
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/filegroup.go b/android/filegroup.go
index e609f63..6b11172 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -33,6 +33,8 @@
 	ctx.RegisterModuleType("filegroup", FileGroupFactory)
 })
 
+var convertedProtoLibrarySuffix = "_bp2build_converted"
+
 // IsFilegroup checks that a module is a filegroup type
 func IsFilegroup(ctx bazel.OtherModuleContext, m blueprint.Module) bool {
 	return ctx.OtherModuleType(m) == "filegroup"
@@ -117,6 +119,24 @@
 
 		ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
 	} else {
+		if fg.ShouldConvertToProtoLibrary(ctx) {
+			// TODO(b/246997908): we can remove this tag if we could figure out a
+			// solution for this bug.
+			tags := []string{"manual"}
+			attrs := &ProtoAttrs{
+				Srcs:                srcs,
+				Strip_import_prefix: fg.properties.Path,
+				Tags:                tags,
+			}
+
+			ctx.CreateBazelTargetModule(
+				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
+				CommonAttributes{Name: fg.Name() + convertedProtoLibrarySuffix},
+				attrs)
+		}
+
+		// TODO(b/242847534): Still convert to a filegroup because other unconverted
+		// modules may depend on the filegroup
 		attrs := &bazelFilegroupAttributes{
 			Srcs: srcs,
 		}
@@ -150,14 +170,14 @@
 type fileGroup struct {
 	ModuleBase
 	BazelModuleBase
-	Bp2buildAidlLibrary
+	FileGroupAsLibrary
 	properties fileGroupProperties
 	srcs       Paths
 }
 
 var _ MixedBuildBuildable = (*fileGroup)(nil)
 var _ SourceFileProducer = (*fileGroup)(nil)
-var _ Bp2buildAidlLibrary = (*fileGroup)(nil)
+var _ FileGroupAsLibrary = (*fileGroup)(nil)
 
 // filegroup contains a list of files that are referenced by other modules
 // properties (such as "srcs") using the syntax ":<name>". filegroup are
@@ -243,11 +263,19 @@
 }
 
 func (fg *fileGroup) ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool {
+	return fg.shouldConvertToLibrary(ctx, ".aidl")
+}
+
+func (fg *fileGroup) ShouldConvertToProtoLibrary(ctx BazelConversionPathContext) bool {
+	return fg.shouldConvertToLibrary(ctx, ".proto")
+}
+
+func (fg *fileGroup) shouldConvertToLibrary(ctx BazelConversionPathContext, suffix string) bool {
 	if len(fg.properties.Srcs) == 0 || !fg.ShouldConvertWithBp2build(ctx) {
 		return false
 	}
 	for _, src := range fg.properties.Srcs {
-		if !strings.HasSuffix(src, ".aidl") {
+		if !strings.HasSuffix(src, suffix) {
 			return false
 		}
 	}
@@ -255,6 +283,14 @@
 }
 
 func (fg *fileGroup) GetAidlLibraryLabel(ctx BazelConversionPathContext) string {
+	return fg.getFileGroupAsLibraryLabel(ctx)
+}
+
+func (fg *fileGroup) GetProtoLibraryLabel(ctx BazelConversionPathContext) string {
+	return fg.getFileGroupAsLibraryLabel(ctx) + convertedProtoLibrarySuffix
+}
+
+func (fg *fileGroup) getFileGroupAsLibraryLabel(ctx BazelConversionPathContext) string {
 	if ctx.OtherModuleDir(fg.module) == ctx.ModuleDir() {
 		return ":" + fg.Name()
 	} else {
@@ -265,12 +301,19 @@
 // Given a name in srcs prop, check to see if the name references a filegroup
 // and the filegroup is converted to aidl_library
 func IsConvertedToAidlLibrary(ctx BazelConversionPathContext, name string) bool {
+	if fg, ok := ToFileGroupAsLibrary(ctx, name); ok {
+		return fg.ShouldConvertToAidlLibrary(ctx)
+	}
+	return false
+}
+
+func ToFileGroupAsLibrary(ctx BazelConversionPathContext, name string) (FileGroupAsLibrary, bool) {
 	if module, ok := ctx.ModuleFromName(name); ok {
 		if IsFilegroup(ctx, module) {
-			if fg, ok := module.(Bp2buildAidlLibrary); ok {
-				return fg.ShouldConvertToAidlLibrary(ctx)
+			if fg, ok := module.(FileGroupAsLibrary); ok {
+				return fg, true
 			}
 		}
 	}
-	return false
+	return nil, false
 }
diff --git a/android/gen_notice.go b/android/gen_notice.go
index 2eb6bec..008aac5 100644
--- a/android/gen_notice.go
+++ b/android/gen_notice.go
@@ -111,6 +111,9 @@
 }
 
 func (m *genNoticeModule) DepsMutator(ctx BottomUpMutatorContext) {
+	if ctx.ContainsProperty("licenses") {
+		ctx.PropertyErrorf("licenses", "not supported on \"gen_notice\" modules")
+	}
 	if proptools.Bool(m.properties.Html) && proptools.Bool(m.properties.Xml) {
 		ctx.ModuleErrorf("can be html or xml but not both")
 	}
@@ -195,6 +198,16 @@
 	return nil, fmt.Errorf("unrecognized tag %q", tag)
 }
 
+var _ AndroidMkEntriesProvider = (*genNoticeModule)(nil)
+
+// Implements AndroidMkEntriesProvider
+func (m *genNoticeModule) AndroidMkEntries() []AndroidMkEntries {
+	return []AndroidMkEntries{AndroidMkEntries{
+		Class:      "ETC",
+		OutputFile: OptionalPathForPath(m.output),
+	}}
+}
+
 // missingReferencesRule emits an ErrorRule for missing module references.
 func missingReferencesRule(ctx BuilderContext, m *genNoticeModule) {
 	if len(m.missing) < 1 {
diff --git a/android/gen_notice_test.go b/android/gen_notice_test.go
index b45ce4f..99d982b 100644
--- a/android/gen_notice_test.go
+++ b/android/gen_notice_test.go
@@ -12,6 +12,19 @@
 	expectedErrors []string
 }{
 	{
+		name: "gen_notice must not accept licenses property",
+		fs: map[string][]byte{
+			"top/Android.bp": []byte(`
+				gen_notice {
+					name: "top_license",
+					licenses: ["other_license"],
+				}`),
+		},
+		expectedErrors: []string{
+			`not supported on "gen_notice" modules`,
+		},
+	},
+	{
 		name: "bad gen_notice",
 		fs: map[string][]byte{
 			"top/Android.bp": []byte(`
diff --git a/android/license.go b/android/license.go
index ebee055..cde5e6e 100644
--- a/android/license.go
+++ b/android/license.go
@@ -15,7 +15,10 @@
 package android
 
 import (
+	"android/soong/bazel"
+	"fmt"
 	"github.com/google/blueprint"
+	"os"
 )
 
 type licenseKindDependencyTag struct {
@@ -48,14 +51,55 @@
 	Visibility []string
 }
 
+var _ Bazelable = &licenseModule{}
+
 type licenseModule struct {
 	ModuleBase
 	DefaultableModuleBase
 	SdkBase
+	BazelModuleBase
 
 	properties licenseProperties
 }
 
+type bazelLicenseAttributes struct {
+	License_kinds    []string
+	Copyright_notice *string
+	License_text     bazel.LabelAttribute
+	Package_name     *string
+	Visibility       []string
+}
+
+func (m *licenseModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
+	attrs := &bazelLicenseAttributes{
+		License_kinds:    m.properties.License_kinds,
+		Copyright_notice: m.properties.Copyright_notice,
+		Package_name:     m.properties.Package_name,
+		Visibility:       m.properties.Visibility,
+	}
+
+	// TODO(asmundak): Soong supports multiple license texts while Bazel's license
+	// rule does not. Have android_license create a genrule to concatenate multiple
+	// license texts.
+	if len(m.properties.License_text) > 1 && ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE") {
+		fmt.Fprintf(os.Stderr, "warning: using only the first license_text item from //%s:%s\n",
+			ctx.ModuleDir(), m.Name())
+	}
+	if len(m.properties.License_text) >= 1 {
+		attrs.License_text.SetValue(BazelLabelForModuleSrcSingle(ctx, m.properties.License_text[0]))
+	}
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "android_license",
+			Bzl_load_location: "//build/bazel/rules/license:license.bzl",
+		},
+		CommonAttributes{
+			Name: m.Name(),
+		},
+		attrs)
+}
+
 func (m *licenseModule) DepsMutator(ctx BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, licenseKindTag, m.properties.License_kinds...)
 }
@@ -78,7 +122,7 @@
 	module := &licenseModule{}
 
 	base := module.base()
-	module.AddProperties(&base.nameProperties, &module.properties)
+	module.AddProperties(&base.nameProperties, &module.properties, &base.commonProperties.BazelConversionStatus)
 
 	// The visibility property needs to be checked and parsed by the visibility module.
 	setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
@@ -86,6 +130,7 @@
 	InitSdkAwareModule(module)
 	initAndroidModuleBase(module)
 	InitDefaultableModule(module)
+	InitBazelModule(module)
 
 	return module
 }
diff --git a/android/license_kind.go b/android/license_kind.go
index 838dedd..24b91e4 100644
--- a/android/license_kind.go
+++ b/android/license_kind.go
@@ -14,6 +14,8 @@
 
 package android
 
+import "android/soong/bazel"
+
 func init() {
 	RegisterLicenseKindBuildComponents(InitRegistrationContext)
 }
@@ -32,13 +34,39 @@
 	Visibility []string
 }
 
+var _ Bazelable = &licenseKindModule{}
+
 type licenseKindModule struct {
 	ModuleBase
 	DefaultableModuleBase
+	BazelModuleBase
 
 	properties licenseKindProperties
 }
 
+type bazelLicenseKindAttributes struct {
+	Conditions []string
+	Url        string
+	Visibility []string
+}
+
+func (m *licenseKindModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
+	attrs := &bazelLicenseKindAttributes{
+		Conditions: m.properties.Conditions,
+		Url:        m.properties.Url,
+		Visibility: m.properties.Visibility,
+	}
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "license_kind",
+			Bzl_load_location: "@rules_license//rules:license_kind.bzl",
+		},
+		CommonAttributes{
+			Name: m.Name(),
+		},
+		attrs)
+}
+
 func (m *licenseKindModule) DepsMutator(ctx BottomUpMutatorContext) {
 	// Nothing to do.
 }
@@ -51,13 +79,14 @@
 	module := &licenseKindModule{}
 
 	base := module.base()
-	module.AddProperties(&base.nameProperties, &module.properties)
+	module.AddProperties(&base.nameProperties, &module.properties, &base.commonProperties.BazelConversionStatus)
 
 	// The visibility property needs to be checked and parsed by the visibility module.
 	setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
 
 	initAndroidModuleBase(module)
 	InitDefaultableModule(module)
+	InitBazelModule(module)
 
 	return module
 }
diff --git a/android/module.go b/android/module.go
index 5908233..a150e61 100644
--- a/android/module.go
+++ b/android/module.go
@@ -917,6 +917,10 @@
 	Name string
 	// Data mapped from: Required
 	Data bazel.LabelListAttribute
+
+	Tags bazel.StringListAttribute
+
+	Applicable_licenses bazel.LabelListAttribute
 }
 
 // constraintAttributes represents Bazel attributes pertaining to build constraints,
@@ -1169,7 +1173,9 @@
 	mod := ctx.Module().base()
 	// Assert passed-in attributes include Name
 	if len(attrs.Name) == 0 {
-		ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
+		if ctx.ModuleType() != "package" {
+			ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
+		}
 	}
 
 	depsToLabelList := func(deps []string) bazel.LabelListAttribute {
@@ -1227,22 +1233,19 @@
 		}
 	}
 
-	required := depsToLabelList(mod.commonProperties.Required)
+	attrs.Applicable_licenses = bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, mod.commonProperties.Licenses))
+
+	// 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] {
@@ -1520,7 +1523,7 @@
 	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.UnconvertedDeps)
 }
 
-// GetMissingBp2buildDeps eturns the list of module names that were not found in Android.bp files.
+// GetMissingBp2buildDeps returns the list of module names that were not found in Android.bp files.
 func (m *ModuleBase) GetMissingBp2buildDeps() []string {
 	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.MissingDeps)
 }
diff --git a/android/namespace.go b/android/namespace.go
index fc7bc29..a3ff761 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -166,10 +166,10 @@
 	return namespace
 }
 
-// A NamelessModule can never be looked up by name.  It must still implement Name(), but the return
-// value doesn't have to be unique.
-type NamelessModule interface {
-	Nameless()
+// A NamespacelessModule can never be looked up by name.  It must still implement Name(), and the name
+// still has to be unique.
+type NamespacelessModule interface {
+	Namespaceless()
 }
 
 func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blueprint.ModuleGroup, module blueprint.Module) (namespace blueprint.Namespace, errs []error) {
@@ -183,7 +183,7 @@
 		return nil, nil
 	}
 
-	if _, ok := module.(NamelessModule); ok {
+	if _, ok := module.(NamespacelessModule); ok {
 		return nil, nil
 	}
 
diff --git a/android/package.go b/android/package.go
index 878e4c4..2bf6521 100644
--- a/android/package.go
+++ b/android/package.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"android/soong/bazel"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -37,12 +38,33 @@
 	Default_applicable_licenses []string
 }
 
+type bazelPackageAttributes struct {
+	Default_visibility          []string
+	Default_applicable_licenses bazel.LabelListAttribute
+}
+
 type packageModule struct {
 	ModuleBase
+	BazelModuleBase
 
 	properties packageProperties
 }
 
+var _ Bazelable = &packageModule{}
+
+func (p *packageModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class: "package",
+		},
+		CommonAttributes{},
+		&bazelPackageAttributes{
+			Default_applicable_licenses: bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, p.properties.Default_applicable_licenses)),
+			// FIXME(asmundak): once b/221436821 is resolved
+			Default_visibility: []string{"//visibility:public"},
+		})
+}
+
 func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) {
 	// Nothing to do.
 }
@@ -59,7 +81,7 @@
 func PackageFactory() Module {
 	module := &packageModule{}
 
-	module.AddProperties(&module.properties)
+	module.AddProperties(&module.properties, &module.commonProperties.BazelConversionStatus)
 
 	// The name is the relative path from build root to the directory containing this
 	// module. Set that name at the earliest possible moment that information is available
@@ -76,5 +98,7 @@
 	// its checking and parsing phases so make it the primary licenses property.
 	setPrimaryLicensesProperty(module, "default_applicable_licenses", &module.properties.Default_applicable_licenses)
 
+	InitBazelModule(module)
+
 	return module
 }
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 4e4fa42..9b5c0e9 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -56,7 +56,9 @@
 var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag
 var _ ExcludeFromApexContentsTag = PrebuiltDepTag
 
-type PrebuiltProperties struct {
+// UserSuppliedPrebuiltProperties contains the prebuilt properties that can be specified in an
+// Android.bp file.
+type UserSuppliedPrebuiltProperties struct {
 	// When prefer is set to true the prebuilt will be used instead of any source module with
 	// a matching name.
 	Prefer *bool `android:"arch_variant"`
@@ -70,6 +72,16 @@
 	// If specified then the prefer property is ignored in favor of the value of the Soong config
 	// variable.
 	Use_source_config_var *ConfigVarProperties
+}
+
+// CopyUserSuppliedPropertiesFromPrebuilt copies the user supplied prebuilt properties from the
+// prebuilt properties.
+func (u *UserSuppliedPrebuiltProperties) CopyUserSuppliedPropertiesFromPrebuilt(p *Prebuilt) {
+	*u = p.properties.UserSuppliedPrebuiltProperties
+}
+
+type PrebuiltProperties struct {
+	UserSuppliedPrebuiltProperties
 
 	SourceExists bool `blueprint:"mutated"`
 	UsePrebuilt  bool `blueprint:"mutated"`
diff --git a/android/proto.go b/android/proto.go
index 25cecf4..3cac9a1 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -155,14 +155,16 @@
 
 // Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
 type Bp2buildProtoInfo struct {
-	Type *string
-	Name string
+	Type       *string
+	Name       string
+	Proto_libs bazel.LabelList
 }
 
-type protoAttrs struct {
+type ProtoAttrs struct {
 	Srcs                bazel.LabelListAttribute
 	Strip_import_prefix *string
 	Deps                bazel.LabelListAttribute
+	Tags                []string
 }
 
 // For each package in the include_dirs property a proto_library target should
@@ -179,44 +181,71 @@
 		return info, false
 	}
 
-	info.Name = m.Name() + "_proto"
-	attrs := protoAttrs{
-		Srcs: srcs,
-	}
+	var protoLibraries bazel.LabelList
+	var directProtoSrcs bazel.LabelList
 
-	for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
-		for _, rawProps := range configToProps {
-			var props *ProtoProperties
-			var ok bool
-			if props, ok = rawProps.(*ProtoProperties); !ok {
-				ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
-			}
-			if axis == bazel.NoConfigAxis {
-				info.Type = props.Proto.Type
-
-				if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
-					// an empty string indicates to strips the package path
-					path := ""
-					attrs.Strip_import_prefix = &path
-				}
-
-				for _, dir := range props.Proto.Include_dirs {
-					if dep, ok := includeDirsToProtoDeps[dir]; ok {
-						attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
-					} else {
-						ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
-					}
-				}
-			} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
-				ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
-			}
+	// For filegroups that should be converted to proto_library just collect the
+	// labels of converted proto_library targets.
+	for _, protoSrc := range srcs.Value.Includes {
+		src := protoSrc.OriginalModuleName
+		if fg, ok := ToFileGroupAsLibrary(ctx, src); ok &&
+			fg.ShouldConvertToProtoLibrary(ctx) {
+			protoLibraries.Add(&bazel.Label{
+				Label: fg.GetProtoLibraryLabel(ctx),
+			})
+		} else {
+			directProtoSrcs.Add(&protoSrc)
 		}
 	}
 
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-		CommonAttributes{Name: info.Name},
-		&attrs)
+	info.Name = m.Name() + "_proto"
+
+	if len(directProtoSrcs.Includes) > 0 {
+		attrs := ProtoAttrs{
+			Srcs: bazel.MakeLabelListAttribute(directProtoSrcs),
+		}
+		attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries))
+
+		for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
+			for _, rawProps := range configToProps {
+				var props *ProtoProperties
+				var ok bool
+				if props, ok = rawProps.(*ProtoProperties); !ok {
+					ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
+				}
+				if axis == bazel.NoConfigAxis {
+					info.Type = props.Proto.Type
+
+					if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
+						// an empty string indicates to strips the package path
+						path := ""
+						attrs.Strip_import_prefix = &path
+					}
+
+					for _, dir := range props.Proto.Include_dirs {
+						if dep, ok := includeDirsToProtoDeps[dir]; ok {
+							attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
+						} else {
+							ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
+						}
+					}
+				} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
+					ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
+				}
+			}
+		}
+
+		ctx.CreateBazelTargetModule(
+			bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
+			CommonAttributes{Name: info.Name},
+			&attrs)
+
+		protoLibraries.Add(&bazel.Label{
+			Label: ":" + info.Name,
+		})
+	}
+
+	info.Proto_libs = protoLibraries
 
 	return info, true
 }
diff --git a/android/sdk.go b/android/sdk.go
index a477cba..bd2f5d1 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -74,6 +74,26 @@
 	sdkAwareWithoutModule
 }
 
+// minApiLevelForSdkSnapshot provides access to the min_sdk_version for MinApiLevelForSdkSnapshot
+type minApiLevelForSdkSnapshot interface {
+	MinSdkVersion(ctx EarlyModuleContext) SdkSpec
+}
+
+// MinApiLevelForSdkSnapshot returns the ApiLevel of the min_sdk_version of the supplied module.
+//
+// If the module does not provide a min_sdk_version then it defaults to 1.
+func MinApiLevelForSdkSnapshot(ctx EarlyModuleContext, module Module) ApiLevel {
+	minApiLevel := NoneApiLevel
+	if m, ok := module.(minApiLevelForSdkSnapshot); ok {
+		minApiLevel = m.MinSdkVersion(ctx).ApiLevel
+	}
+	if minApiLevel == NoneApiLevel {
+		// The default min API level is 1.
+		minApiLevel = uncheckedFinalApiLevel(1)
+	}
+	return minApiLevel
+}
+
 // SdkRef refers to a version of an SDK
 type SdkRef struct {
 	Name    string
@@ -715,8 +735,13 @@
 	//   have common values. Those fields are cleared and the common value added to the common
 	//   properties.
 	//
-	//   A field annotated with a tag of `sdk:"keep"` will be treated as if it
-	//   was not capitalized, i.e. not optimized for common values.
+	//   A field annotated with a tag of `sdk:"ignore"` will be treated as if it
+	//   was not capitalized, i.e. ignored and not optimized for common values.
+	//
+	//   A field annotated with a tag of `sdk:"keep"` will not be cleared even if the value is common
+	//   across multiple structs. Common values will still be copied into the common property struct.
+	//   So, if the same value is placed in all structs populated from variants that value would be
+	//   copied into all common property structs and so be available in every instance.
 	//
 	//   A field annotated with a tag of `android:"arch_variant"` will be allowed to have
 	//   values that differ by arch, fields not tagged as such must have common values across
@@ -903,18 +928,18 @@
 	// the locations of any of their prebuilt files in the snapshot by os type to prevent them
 	// from colliding. See OsPrefix().
 	//
-	// This property is the same for all variants of a member and so would be optimized away
-	// if it was not explicitly kept.
-	Os_count int `sdk:"keep"`
+	// Ignore this property during optimization. This is needed because this property is the same for
+	// all variants of a member and so would be optimized away if it was not ignored.
+	Os_count int `sdk:"ignore"`
 
 	// The os type for which these properties refer.
 	//
 	// Provided to allow a member to differentiate between os types in the locations of their
 	// prebuilt files when it supports more than one os type.
 	//
-	// This property is the same for all os type specific variants of a member and so would be
-	// optimized away if it was not explicitly kept.
-	Os OsType `sdk:"keep"`
+	// Ignore this property during optimization. This is needed because this property is the same for
+	// all variants of a member and so would be optimized away if it was not ignored.
+	Os OsType `sdk:"ignore"`
 
 	// The setting to use for the compile_multilib property.
 	Compile_multilib string `android:"arch_variant"`
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index cd36ae0..c0f4523 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -172,7 +172,7 @@
 		"soong_config_module_type_import_" + fmt.Sprintf("%p", m)
 }
 
-func (*soongConfigModuleTypeImport) Nameless()                                 {}
+func (*soongConfigModuleTypeImport) Namespaceless()                            {}
 func (*soongConfigModuleTypeImport) GenerateAndroidBuildActions(ModuleContext) {}
 
 // Create dummy modules for soong_config_module_type and soong_config_*_variable
@@ -280,9 +280,9 @@
 }
 
 func (m *soongConfigModuleTypeModule) Name() string {
-	return m.properties.Name
+	return m.properties.Name + fmt.Sprintf("%p", m)
 }
-func (*soongConfigModuleTypeModule) Nameless()                                     {}
+func (*soongConfigModuleTypeModule) Namespaceless()                                {}
 func (*soongConfigModuleTypeModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
 
 type soongConfigStringVariableDummyModule struct {
@@ -315,15 +315,15 @@
 }
 
 func (m *soongConfigStringVariableDummyModule) Name() string {
-	return m.properties.Name
+	return m.properties.Name + fmt.Sprintf("%p", m)
 }
-func (*soongConfigStringVariableDummyModule) Nameless()                                     {}
+func (*soongConfigStringVariableDummyModule) Namespaceless()                                {}
 func (*soongConfigStringVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
 
 func (m *soongConfigBoolVariableDummyModule) Name() string {
-	return m.properties.Name
+	return m.properties.Name + fmt.Sprintf("%p", m)
 }
-func (*soongConfigBoolVariableDummyModule) Nameless()                                     {}
+func (*soongConfigBoolVariableDummyModule) Namespaceless()                                {}
 func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
 
 // importModuleTypes registers the module factories for a list of module types defined
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/apex/apex.go b/apex/apex.go
index 949809a..498c8c0 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2659,9 +2659,13 @@
 		}
 
 		// Certificate
-		if overridableProperties.Certificate != nil {
-			attrs.Certificate = bazel.LabelAttribute{}
-			attrs.Certificate.SetValue(android.BazelLabelForModuleDepSingle(ctx, *overridableProperties.Certificate))
+		if overridableProperties.Certificate == nil {
+			// delegated to the rule attr default
+			attrs.Certificate = nil
+		} else {
+			certificateName, certificate := java.ParseCertificateToAttribute(ctx, overridableProperties.Certificate)
+			attrs.Certificate_name = certificateName
+			attrs.Certificate = certificate
 		}
 
 		// Prebuilts
@@ -3054,36 +3058,6 @@
 	//
 	// Module separator
 	//
-	m["com.android.bluetooth"] = []string{
-		"bluetooth-protos-lite",
-		"internal_include_headers",
-		"libaudio-a2dp-hw-utils",
-		"libaudio-hearing-aid-hw-utils",
-		"libbluetooth",
-		"libbluetooth-types",
-		"libbluetooth-types-header",
-		"libbluetooth_gd",
-		"libbluetooth_headers",
-		"libbluetooth_jni",
-		"libbt-audio-hal-interface",
-		"libbt-bta",
-		"libbt-common",
-		"libbt-hci",
-		"libbt-platform-protos-lite",
-		"libbt-protos-lite",
-		"libbt-sbc-decoder",
-		"libbt-sbc-encoder",
-		"libbt-stack",
-		"libbt-utils",
-		"libbtcore",
-		"libbtdevice",
-		"libbte",
-		"libbtif",
-		"libchrome",
-	}
-	//
-	// Module separator
-	//
 	m["com.android.cellbroadcast"] = []string{"CellBroadcastApp", "CellBroadcastServiceModule"}
 	//
 	// Module separator
@@ -3365,7 +3339,8 @@
 	Android_manifest      bazel.LabelAttribute
 	File_contexts         bazel.LabelAttribute
 	Key                   bazel.LabelAttribute
-	Certificate           bazel.LabelAttribute
+	Certificate           *bazel.Label // used when the certificate prop is a module
+	Certificate_name      *string      // used when the certificate prop is a string
 	Min_sdk_version       *string
 	Updatable             bazel.BoolAttribute
 	Installable           bazel.BoolAttribute
@@ -3427,10 +3402,7 @@
 		keyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Key))
 	}
 
-	var certificateLabelAttribute bazel.LabelAttribute
-	if a.overridableProperties.Certificate != nil {
-		certificateLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Certificate))
-	}
+	certificateName, certificate := java.ParseCertificateToAttribute(ctx, a.overridableProperties.Certificate)
 
 	nativeSharedLibs := &convertedNativeSharedLibs{
 		Native_shared_libs_32: bazel.LabelListAttribute{},
@@ -3486,7 +3458,8 @@
 		File_contexts:         fileContextsLabelAttribute,
 		Min_sdk_version:       minSdkVersion,
 		Key:                   keyLabelAttribute,
-		Certificate:           certificateLabelAttribute,
+		Certificate:           certificate,
+		Certificate_name:      certificateName,
 		Updatable:             updatableAttribute,
 		Installable:           installableAttribute,
 		Native_shared_libs_32: nativeSharedLibs.Native_shared_libs_32,
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 1805291..e130fcc 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7235,12 +7235,18 @@
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
-	if len(copyCmds) != 3 {
-		t.Fatalf("Expected 3 commands, got %d in:\n%s", len(copyCmds), s)
+	if len(copyCmds) != 4 {
+		t.Fatalf("Expected 4 commands, got %d in:\n%s", len(copyCmds), s)
 	}
 	ensureMatches(t, copyCmds[0], "^rm -rf .*/app/AppSet@TEST.BUILD_ID$")
 	ensureMatches(t, copyCmds[1], "^mkdir -p .*/app/AppSet@TEST.BUILD_ID$")
-	ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet@TEST.BUILD_ID .*/AppSet.zip$")
+	ensureMatches(t, copyCmds[2], "^cp -f .*/app/AppSet@TEST.BUILD_ID/AppSet.apk$")
+	ensureMatches(t, copyCmds[3], "^unzip .*-d .*/app/AppSet@TEST.BUILD_ID .*/AppSet.zip$")
+
+	// Ensure that canned_fs_config has an entry for the app set zip file
+	generateFsRule := mod.Rule("generateFsConfig")
+	cmd := generateFsRule.RuleParams.Command
+	ensureContains(t, cmd, "AppSet.zip")
 }
 
 func TestAppSetBundlePrebuilt(t *testing.T) {
@@ -7271,6 +7277,28 @@
 	android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String())
 }
 
+func TestApexSetApksModuleAssignment(t *testing.T) {
+	ctx := testApex(t, `
+		apex_set {
+			name: "myapex",
+			set: ":myapex_apks_file",
+		}
+
+		filegroup {
+			name: "myapex_apks_file",
+			srcs: ["myapex.apks"],
+		}
+	`)
+
+	m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+
+	// Check that the extractor produces the correct apks file from the input module
+	extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.apks"
+	extractedApex := m.Output(extractorOutput)
+
+	android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings())
+}
+
 func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) {
 	t.Helper()
 
diff --git a/apex/builder.go b/apex/builder.go
index b95b3bd..ad8075b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -459,8 +459,13 @@
 			pathOnDevice := filepath.Join("/system", fi.path())
 			copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
 		} else {
+			// Copy the file into APEX
+			copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+
 			var installedPath android.InstallPath
 			if fi.class == appSet {
+				// In case of AppSet, we need to copy additional APKs as well. They
+				// are zipped. So we need to unzip them.
 				copyCommands = append(copyCommands,
 					fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
 						fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
@@ -469,7 +474,6 @@
 						fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs())
 				}
 			} else {
-				copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
 				if installSymbolFiles {
 					installedPath = ctx.InstallFile(pathWhenActivated.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
 				}
@@ -1086,8 +1090,11 @@
 				executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
 			}
 		} else if f.class == appSet {
+			// base APK
+			readOnlyPaths = append(readOnlyPaths, pathInApex)
+			// Additional APKs
 			appSetDirs = append(appSetDirs, f.installDir)
-			appSetFiles[f.installDir] = f.builtFile
+			appSetFiles[f.installDir] = f.module.(*java.AndroidAppSet).PackedAdditionalOutputs()
 		} else {
 			readOnlyPaths = append(readOnlyPaths, pathInApex)
 		}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 172a201..25ae5bf 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -840,17 +840,17 @@
 
 type ApexExtractorProperties struct {
 	// the .apks file path that contains prebuilt apex files to be extracted.
-	Set *string
+	Set *string `android:"path"`
 
 	Sanitized struct {
 		None struct {
-			Set *string
+			Set *string `android:"path"`
 		}
 		Address struct {
-			Set *string
+			Set *string `android:"path"`
 		}
 		Hwaddress struct {
-			Set *string
+			Set *string `android:"path"`
 		}
 	}
 
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 7ff202b..a93aa00 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -23,10 +23,11 @@
 
 const (
 	// ArchType names in arch.go
-	archArm    = "arm"
-	archArm64  = "arm64"
-	archX86    = "x86"
-	archX86_64 = "x86_64"
+	archArm     = "arm"
+	archArm64   = "arm64"
+	archRiscv64 = "riscv64"
+	archX86     = "x86"
+	archX86_64  = "x86_64"
 
 	// OsType names in arch.go
 	OsAndroid     = "android"
@@ -39,6 +40,7 @@
 	// Targets in arch.go
 	osArchAndroidArm        = "android_arm"
 	osArchAndroidArm64      = "android_arm64"
+	osArchAndroidRiscv64    = "android_riscv64"
 	osArchAndroidX86        = "android_x86"
 	osArchAndroidX86_64     = "android_x86_64"
 	osArchDarwinArm64       = "darwin_arm64"
@@ -69,6 +71,9 @@
 
 	AndroidAndInApex  = "android-in_apex"
 	AndroidAndNonApex = "android-non_apex"
+
+	InApex  = "in_apex"
+	NonApex = "non_apex"
 )
 
 func PowerSetWithoutEmptySet[T any](items []T) [][]T {
@@ -96,6 +101,7 @@
 		"arm64": {
 			"dotprod",
 		},
+		"riscv64": {},
 		"x86": {
 			"ssse3",
 			"sse4",
@@ -161,6 +167,7 @@
 	platformOsArchMap = map[string]string{
 		osArchAndroidArm:           "//build/bazel/platforms/os_arch:android_arm",
 		osArchAndroidArm64:         "//build/bazel/platforms/os_arch:android_arm64",
+		osArchAndroidRiscv64:       "//build/bazel/platforms/os_arch:android_riscv64",
 		osArchAndroidX86:           "//build/bazel/platforms/os_arch:android_x86",
 		osArchAndroidX86_64:        "//build/bazel/platforms/os_arch:android_x86_64",
 		osArchDarwinArm64:          "//build/bazel/platforms/os_arch:darwin_arm64",
@@ -184,7 +191,7 @@
 	// TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
 	// in a cyclic dependency.
 	osToArchMap = map[string][]string{
-		OsAndroid:     {archArm, archArm64, archX86, archX86_64},
+		OsAndroid:     {archArm, archArm64, archRiscv64, archX86, archX86_64},
 		osLinux:       {archX86, archX86_64},
 		osLinuxMusl:   {archX86, archX86_64},
 		osDarwin:      {archArm64, archX86_64},
@@ -198,6 +205,12 @@
 		AndroidAndNonApex:          "//build/bazel/rules/apex:android-non_apex",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
 	}
+
+	inApexMap = map[string]string{
+		InApex:                     "//build/bazel/rules/apex:in_apex",
+		NonApex:                    "//build/bazel/rules/apex:non_apex",
+		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
+	}
 )
 
 // basic configuration types
@@ -210,6 +223,7 @@
 	osArch
 	productVariables
 	osAndInApex
+	inApex
 )
 
 func osArchString(os string, arch string) string {
@@ -224,6 +238,7 @@
 		osArch:           "arch_os",
 		productVariables: "product_variables",
 		osAndInApex:      "os_in_apex",
+		inApex:           "in_apex",
 	}[ct]
 }
 
@@ -251,6 +266,10 @@
 		if _, ok := osAndInApexMap[config]; !ok {
 			panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
 		}
+	case inApex:
+		if _, ok := inApexMap[config]; !ok {
+			panic(fmt.Errorf("Unknown in_apex config: %s", config))
+		}
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
 	}
@@ -276,6 +295,8 @@
 		return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
 	case osAndInApex:
 		return osAndInApexMap[config]
+	case inApex:
+		return inApexMap[config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
 	}
@@ -292,6 +313,8 @@
 	OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
 	// An axis for os+in_apex-specific configurations
 	OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
+	// An axis for in_apex-specific configurations
+	InApexAxis = ConfigurationAxis{configurationType: inApex}
 )
 
 // ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index cf8e9f7..e35b531 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -158,63 +158,33 @@
   # 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)
+	var ccInfo CcInfo
+	decoder := json.NewDecoder(strings.NewReader(rawString))
+	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
+	err := decoder.Decode(&ccInfo)
+	if err != nil {
+		return ccInfo, fmt.Errorf("error parsing CcInfo result. %s RAW STRING: %s", err, rawString)
 	}
-	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
+	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/bazel/properties.go b/bazel/properties.go
index 11f6247..c329e41 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -720,7 +720,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, inApex:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -736,7 +736,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, inApex:
 		return lla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 3d9fc5a..7c9af1a 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -63,8 +63,11 @@
         "java_library_host_conversion_test.go",
         "java_plugin_conversion_test.go",
         "java_proto_conversion_test.go",
+        "license_conversion_test.go",
+        "license_kind_conversion_test.go",
         "linker_config_conversion_test.go",
         "ndk_headers_conversion_test.go",
+        "package_conversion_test.go",
         "performance_test.go",
         "prebuilt_etc_conversion_test.go",
         "python_binary_conversion_test.go",
diff --git a/bp2build/androidbp_to_build_templates.go b/bp2build/androidbp_to_build_templates.go
index 5fed4fa..9b21c32 100644
--- a/bp2build/androidbp_to_build_templates.go
+++ b/bp2build/androidbp_to_build_templates.go
@@ -23,7 +23,7 @@
 
 	// A macro call in the BUILD file representing a Soong module, with space
 	// for expanding more attributes.
-	soongModuleTarget = `soong_module(
+	soongModuleTargetTemplate = `soong_module(
     name = "%s",
     soong_module_name = "%s",
     soong_module_type = "%s",
@@ -31,10 +31,13 @@
     soong_module_deps = %s,
 %s)`
 
-	bazelTarget = `%s(
+	ruleTargetTemplate = `%s(
     name = "%s",
 %s)`
 
+	unnamedRuleTargetTemplate = `%s(
+%s)`
+
 	// A simple provider to mark and differentiate Soong module rule shims from
 	// regular Bazel rules. Every Soong module rule shim returns a
 	// SoongModuleInfo provider, and can only depend on rules returning
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index b0a2966..233fce4 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -120,7 +120,7 @@
 	file_contexts: ":com.android.apogee-file_contexts",
 	min_sdk_version: "29",
 	key: "com.android.apogee.key",
-	certificate: "com.android.apogee.certificate",
+	certificate: ":com.android.apogee.certificate",
 	updatable: false,
 	installable: false,
 	compressible: false,
@@ -582,7 +582,7 @@
 	file_contexts: ":com.android.apogee-file_contexts",
 	min_sdk_version: "29",
 	key: "com.android.apogee.key",
-	certificate: "com.android.apogee.certificate",
+	certificate: ":com.android.apogee.certificate",
 	updatable: false,
 	installable: false,
 	compressible: false,
@@ -618,7 +618,7 @@
 	name: "com.google.android.apogee",
 	base: ":com.android.apogee",
 	key: "com.google.android.apogee.key",
-	certificate: "com.google.android.apogee.certificate",
+	certificate: ":com.google.android.apogee.certificate",
 	prebuilts: [],
 	compressible: true,
 }
@@ -1016,3 +1016,193 @@
 			}),
 		}})
 }
+
+func TestBp2BuildOverrideApex_CertificateNil(t *testing.T) {
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - don't set default certificate",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
+android_app_certificate {
+	name: "com.android.apogee.certificate",
+	certificate: "com.android.apogee",
+	bazel_module: { bp2build_available: false },
+}
+
+filegroup {
+	name: "com.android.apogee-file_contexts",
+	srcs: [
+		"com.android.apogee-file_contexts",
+	],
+	bazel_module: { bp2build_available: false },
+}
+
+apex {
+	name: "com.android.apogee",
+	manifest: "apogee_manifest.json",
+	file_contexts: ":com.android.apogee-file_contexts",
+	certificate: ":com.android.apogee.certificate",
+	bazel_module: { bp2build_available: false },
+}
+
+override_apex {
+	name: "com.google.android.apogee",
+	base: ":com.android.apogee",
+	// certificate is deliberately omitted, and not converted to bazel,
+	// because the overridden apex shouldn't be using the base apex's cert.
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+				"file_contexts": `":com.android.apogee-file_contexts"`,
+				"manifest":      `"apogee_manifest.json"`,
+			}),
+		}})
+}
+
+func TestApexCertificateIsModule(t *testing.T) {
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - certificate is module",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
+android_app_certificate {
+	name: "com.android.apogee.certificate",
+	certificate: "com.android.apogee",
+	bazel_module: { bp2build_available: false },
+}
+
+apex {
+	name: "com.android.apogee",
+	manifest: "apogee_manifest.json",
+	file_contexts: ":com.android.apogee-file_contexts",
+	certificate: ":com.android.apogee.certificate",
+}
+` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
+				"certificate":   `":com.android.apogee.certificate"`,
+				"file_contexts": `":com.android.apogee-file_contexts"`,
+				"manifest":      `"apogee_manifest.json"`,
+			}),
+		}})
+}
+
+func TestApexCertificateIsSrc(t *testing.T) {
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - certificate is src",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
+apex {
+	name: "com.android.apogee",
+	manifest: "apogee_manifest.json",
+	file_contexts: ":com.android.apogee-file_contexts",
+	certificate: "com.android.apogee.certificate",
+}
+` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
+				"certificate_name": `"com.android.apogee.certificate"`,
+				"file_contexts":    `":com.android.apogee-file_contexts"`,
+				"manifest":         `"apogee_manifest.json"`,
+			}),
+		}})
+}
+
+func TestBp2BuildOverrideApex_CertificateIsModule(t *testing.T) {
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - certificate is module",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
+android_app_certificate {
+	name: "com.android.apogee.certificate",
+	certificate: "com.android.apogee",
+	bazel_module: { bp2build_available: false },
+}
+
+filegroup {
+	name: "com.android.apogee-file_contexts",
+	srcs: [
+		"com.android.apogee-file_contexts",
+	],
+	bazel_module: { bp2build_available: false },
+}
+
+apex {
+	name: "com.android.apogee",
+	manifest: "apogee_manifest.json",
+	file_contexts: ":com.android.apogee-file_contexts",
+	certificate: ":com.android.apogee.certificate",
+	bazel_module: { bp2build_available: false },
+}
+
+android_app_certificate {
+	name: "com.google.android.apogee.certificate",
+	certificate: "com.google.android.apogee",
+	bazel_module: { bp2build_available: false },
+}
+
+override_apex {
+	name: "com.google.android.apogee",
+	base: ":com.android.apogee",
+	certificate: ":com.google.android.apogee.certificate",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+				"file_contexts": `":com.android.apogee-file_contexts"`,
+				"certificate":   `":com.google.android.apogee.certificate"`,
+				"manifest":      `"apogee_manifest.json"`,
+			}),
+		}})
+}
+
+func TestBp2BuildOverrideApex_CertificateIsSrc(t *testing.T) {
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - certificate is src",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
+android_app_certificate {
+	name: "com.android.apogee.certificate",
+	certificate: "com.android.apogee",
+	bazel_module: { bp2build_available: false },
+}
+
+filegroup {
+	name: "com.android.apogee-file_contexts",
+	srcs: [
+		"com.android.apogee-file_contexts",
+	],
+	bazel_module: { bp2build_available: false },
+}
+
+apex {
+	name: "com.android.apogee",
+	manifest: "apogee_manifest.json",
+	file_contexts: ":com.android.apogee-file_contexts",
+	certificate: ":com.android.apogee.certificate",
+	bazel_module: { bp2build_available: false },
+}
+
+override_apex {
+	name: "com.google.android.apogee",
+	base: ":com.android.apogee",
+	certificate: "com.google.android.apogee.certificate",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
+				"file_contexts":    `":com.android.apogee-file_contexts"`,
+				"certificate_name": `"com.google.android.apogee.certificate"`,
+				"manifest":         `"apogee_manifest.json"`,
+			}),
+		}})
+}
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/bpf_conversion_test.go b/bp2build/bpf_conversion_test.go
new file mode 100644
index 0000000..1259f9e
--- /dev/null
+++ b/bp2build/bpf_conversion_test.go
@@ -0,0 +1,65 @@
+// 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 (
+	"android/soong/android"
+	"android/soong/bpf"
+
+	"testing"
+)
+
+func runBpfTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "bpf"
+	(&tc).ModuleTypeUnderTestFactory = bpf.BpfFactory
+	RunBp2BuildTestCase(t, registerBpfModuleTypes, tc)
+}
+
+func registerBpfModuleTypes(ctx android.RegistrationContext) {}
+
+func TestBpfSupportedAttrs(t *testing.T) {
+	runBpfTestCase(t, Bp2buildTestCase{
+		Description: "Bpf module only converts supported attributes",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+bpf {
+    name: "bpfTestOut.o",
+    srcs: ["bpfTestSrcOne.c",
+           "bpfTestSrcTwo.c"],
+    btf: true,
+    cflags: ["-bpfCflagOne",
+             "-bpfCflagTwo"],
+    include_dirs: ["ia/ib/ic"],
+    sub_dir: "sa/ab",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("bpf", "bpfTestOut.o", AttrNameToString{
+				"absolute_includes": `["ia/ib/ic"]`,
+				"btf":               `True`,
+				"copts": `[
+        "-bpfCflagOne",
+        "-bpfCflagTwo",
+    ]`,
+				"srcs": `[
+        "bpfTestSrcOne.c",
+        "bpfTestSrcTwo.c",
+    ]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index ca8185e..36c3a48 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -64,7 +64,16 @@
 // BazelTargets is a typedef for a slice of BazelTarget objects.
 type BazelTargets []BazelTarget
 
-// sort a list of BazelTargets in-place by name
+func (targets BazelTargets) packageRule() *BazelTarget {
+	for _, target := range targets {
+		if target.ruleClass == "package" {
+			return &target
+		}
+	}
+	return nil
+}
+
+// sort a list of BazelTargets in-place, by name, and by generated/handcrafted types.
 func (targets BazelTargets) sort() {
 	sort.Slice(targets, func(i, j int) bool {
 		return targets[i].name < targets[j].name
@@ -77,7 +86,9 @@
 func (targets BazelTargets) String() string {
 	var res string
 	for i, target := range targets {
-		res += target.content
+		if target.ruleClass != "package" {
+			res += target.content
+		}
 		if i != len(targets)-1 {
 			res += "\n\n"
 		}
@@ -231,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),
 	}
@@ -261,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
 					}
@@ -282,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
 					}
@@ -337,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(["**/*"]))`,
@@ -391,18 +405,19 @@
 	// Return the Bazel target with rule class and attributes, ready to be
 	// code-generated.
 	attributes := propsToAttributes(props.Attrs)
+	var content string
 	targetName := m.TargetName()
+	if targetName != "" {
+		content = fmt.Sprintf(ruleTargetTemplate, ruleClass, targetName, attributes)
+	} else {
+		content = fmt.Sprintf(unnamedRuleTargetTemplate, ruleClass, attributes)
+	}
 	return BazelTarget{
 		name:            targetName,
 		packageName:     m.TargetPackage(),
 		ruleClass:       ruleClass,
 		bzlLoadLocation: bzlLoadLocation,
-		content: fmt.Sprintf(
-			bazelTarget,
-			ruleClass,
-			targetName,
-			attributes,
-		),
+		content:         content,
 	}, nil
 }
 
@@ -436,7 +451,7 @@
 	return BazelTarget{
 		name: targetName,
 		content: fmt.Sprintf(
-			soongModuleTarget,
+			soongModuleTargetTemplate,
 			targetName,
 			ctx.ModuleName(m),
 			canonicalizeModuleType(ctx.ModuleType(m)),
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index dd28c3c..c1fb800 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -369,6 +369,7 @@
       x86_64:  { arch_paths: ["x86_64.txt"] },
       arm:  { arch_paths: ["arm.txt"] },
       arm64:  { arch_paths: ["arm64.txt"] },
+      riscv64: { arch_paths: ["riscv64.txt"] },
     },
     target: {
       linux: { arch_paths: ["linux.txt"] },
@@ -401,6 +402,10 @@
             "arm64.txt",
             "lib64.txt",
         ],
+        "//build/bazel/platforms/arch:riscv64": [
+            "riscv64.txt",
+            "lib64.txt",
+        ],
         "//build/bazel/platforms/arch:x86": [
             "x86.txt",
             "lib32.txt",
@@ -971,6 +976,24 @@
 			},
 		},
 		{
+			Description:                "filegroup with dot-slash-prefixed srcs",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
+    name: "fg_foo",
+    srcs: ["./a", "./b"],
+    bazel_module: { bp2build_available: true },
+}`,
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+					"srcs": `[
+        "a",
+        "b",
+    ]`,
+				}),
+			},
+		},
+		{
 			Description:                "filegroup with excludes srcs",
 			ModuleTypeUnderTest:        "filegroup",
 			ModuleTypeUnderTestFactory: android.FileGroupFactory,
@@ -987,57 +1010,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,
@@ -1086,6 +1058,29 @@
 }`,
 			},
 		},
+		{
+			Description:                "depends_on_other_missing_module_error",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			UnconvertedDepsMode:        errorModulesUnconvertedDeps,
+			Blueprint: `filegroup {
+    name: "foobar",
+    srcs: [
+        "c",
+        "//other:foo",
+        "//other:goo",
+    ],
+    bazel_module: { bp2build_available: true },
+}`,
+			ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on missing modules: //other:goo`),
+			Filesystem: map[string]string{"other/Android.bp": `filegroup {
+    name: "foo",
+    srcs: ["a"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+			},
+		},
 	}
 
 	for _, testCase := range testCases {
@@ -1095,8 +1090,6 @@
 	}
 }
 
-type bp2buildMutator = func(android.TopDownMutatorContext)
-
 func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) {
 	testCases := []struct {
 		moduleTypeUnderTest        string
@@ -1429,6 +1422,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 +1731,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,
@@ -1597,3 +1826,30 @@
 		})
 	}
 }
+
+func TestLicensesAttrConversion(t *testing.T) {
+	RunBp2BuildTestCase(t,
+		func(ctx android.RegistrationContext) {
+			ctx.RegisterModuleType("license", android.LicenseFactory)
+		},
+		Bp2buildTestCase{
+			Description:                "Test that licenses: attribute is converted",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `
+license {
+    name: "my_license",
+}
+filegroup {
+    name: "my_filegroup",
+    licenses: ["my_license"],
+}
+`,
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "my_filegroup", AttrNameToString{
+					"applicable_licenses": `[":my_license"]`,
+				}),
+				MakeBazelTargetNoRestrictions("android_license", "my_license", AttrNameToString{}),
+			},
+		})
+}
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 67d4a1c..c23779e 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -45,6 +45,7 @@
 
 type ccBinaryBp2buildTestCase struct {
 	description string
+	filesystem  map[string]string
 	blueprint   string
 	targets     []testBazelTarget
 }
@@ -79,6 +80,7 @@
 			ModuleTypeUnderTestFactory: cc.BinaryFactory,
 			Description:                description,
 			Blueprint:                  binaryReplacer.Replace(testCase.blueprint),
+			Filesystem:                 testCase.filesystem,
 		})
 	})
 }
@@ -94,6 +96,7 @@
 			ModuleTypeUnderTestFactory: cc.BinaryHostFactory,
 			Description:                description,
 			Blueprint:                  hostBinaryReplacer.Replace(testCase.blueprint),
+			Filesystem:                 testCase.filesystem,
 		})
 	})
 }
@@ -101,6 +104,9 @@
 func TestBasicCcBinary(t *testing.T) {
 	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
 		description: "basic -- properties -> attrs with little/no transformation",
+		filesystem: map[string]string{
+			soongCcVersionLibBpPath: soongCcVersionLibBp,
+		},
 		blueprint: `
 {rule_name} {
     name: "foo",
@@ -146,9 +152,10 @@
         "keep_symbols_list": ["symbol"],
         "none": True,
     }`,
-				"sdk_version":     `"current"`,
-				"min_sdk_version": `"29"`,
-				"use_version_lib": `True`,
+				"sdk_version":        `"current"`,
+				"min_sdk_version":    `"29"`,
+				"use_version_lib":    `True`,
+				"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
 			},
 			},
 		},
@@ -669,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 880ae75..1b8e9b4 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -27,7 +27,16 @@
 	soongCcLibraryPreamble = `
 cc_defaults {
     name: "linux_bionic_supported",
-}`
+}
+`
+
+	soongCcVersionLibBpPath = "build/soong/cc/libbuildversion/Android.bp"
+	soongCcVersionLibBp     = `
+cc_library_static {
+	name: "libbuildversion",
+	bazel_module: { bp2build_available: false },
+}
+`
 
 	soongCcProtoLibraries = `
 cc_library {
@@ -62,9 +71,10 @@
 		ModuleTypeUnderTest:        "cc_library",
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
 		Filesystem: map[string]string{
-			"android.cpp": "",
-			"bionic.cpp":  "",
-			"darwin.cpp":  "",
+			soongCcVersionLibBpPath: soongCcVersionLibBp,
+			"android.cpp":           "",
+			"bionic.cpp":            "",
+			"darwin.cpp":            "",
 			// Refer to cc.headerExts for the supported header extensions in Soong.
 			"header.h":         "",
 			"header.hh":        "",
@@ -143,9 +153,10 @@
         "//build/bazel/platforms/os:linux_bionic": ["bionic.cpp"],
         "//conditions:default": [],
     })`,
-			"sdk_version":     `"current"`,
-			"min_sdk_version": `"29"`,
-			"use_version_lib": `True`,
+			"sdk_version":                       `"current"`,
+			"min_sdk_version":                   `"29"`,
+			"use_version_lib":                   `True`,
+			"implementation_whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
 		}),
 	})
 }
@@ -1337,6 +1348,7 @@
 		"strip":                    true,
 		"inject_bssl_hash":         true,
 		"has_stubs":                true,
+		"use_version_lib":          true,
 	}
 
 	sharedAttrs := AttrNameToString{}
@@ -1355,26 +1367,6 @@
 	return []string{staticTarget, sharedTarget}
 }
 
-func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
-	if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
-		return ""
-	}
-	STUB_SUITE_ATTRS := map[string]string{
-		"stubs_symbol_file": "symbol_file",
-		"stubs_versions":    "versions",
-		"soname":            "soname",
-		"source_library":    "source_library",
-	}
-
-	stubSuiteAttrs := AttrNameToString{}
-	for key, _ := range attrs {
-		if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
-			stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
-		}
-	}
-	return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
-}
-
 func TestCCLibraryNoLibCrtFalse(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
 		ModuleTypeUnderTest:        "cc_library",
@@ -2078,7 +2070,8 @@
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
 			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
+				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
 		},
 	})
@@ -2104,7 +2097,8 @@
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
 			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
+				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
 		},
 	})
@@ -2129,7 +2123,8 @@
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
 			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
+				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
 		},
 	})
@@ -2156,7 +2151,8 @@
 				"implementation_whole_archive_deps": `[":foo_cc_proto"]`,
 				"deps":                              `[":libprotobuf-cpp-full"]`,
 			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps": `[":libprotobuf-cpp-full"]`,
+				"dynamic_deps":                      `[":libprotobuf-cpp-full"]`,
+				"implementation_whole_archive_deps": `[":foo_cc_proto"]`,
 			}),
 		},
 	})
@@ -2183,7 +2179,8 @@
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
 			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
+				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
 		},
 	})
@@ -2239,7 +2236,8 @@
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
+				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
+				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
 		},
 	})
@@ -2261,6 +2259,134 @@
 	})
 }
 
+func TestCcLibraryConvertedProtoFilegroups(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `
+filegroup {
+	name: "a_fg_proto",
+	srcs: ["a_fg.proto"],
+}
+
+cc_library {
+	name: "a",
+	srcs: [
+    ":a_fg_proto",
+    "a.proto",
+  ],
+	proto: {
+		export_proto_headers: true,
+	},
+	include_build_directory: false,
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("proto_library", "a_proto", AttrNameToString{
+				"deps": `[":a_fg_proto_bp2build_converted"]`,
+				"srcs": `["a.proto"]`,
+			}), MakeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
+				"deps": `[
+        ":a_fg_proto_bp2build_converted",
+        ":a_proto",
+    ]`,
+			}), MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
+				"deps":               `[":libprotobuf-cpp-lite"]`,
+				"whole_archive_deps": `[":a_cc_proto_lite"]`,
+			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
+				"whole_archive_deps": `[":a_cc_proto_lite"]`,
+			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{
+				"srcs": `["a_fg.proto"]`,
+				"tags": `["manual"]`,
+			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
+				"srcs": `["a_fg.proto"]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryConvertedProtoFilegroupsNoProtoFiles(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `
+filegroup {
+	name: "a_fg_proto",
+	srcs: ["a_fg.proto"],
+}
+
+cc_library {
+	name: "a",
+	srcs: [
+    ":a_fg_proto",
+  ],
+	proto: {
+		export_proto_headers: true,
+	},
+	include_build_directory: false,
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
+				"deps": `[":a_fg_proto_bp2build_converted"]`,
+			}), MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
+				"deps":               `[":libprotobuf-cpp-lite"]`,
+				"whole_archive_deps": `[":a_cc_proto_lite"]`,
+			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
+				"whole_archive_deps": `[":a_cc_proto_lite"]`,
+			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{
+				"srcs": `["a_fg.proto"]`,
+				"tags": `["manual"]`,
+			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
+				"srcs": `["a_fg.proto"]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryExternalConvertedProtoFilegroups(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"path/to/A/Android.bp": `
+filegroup {
+	name: "a_fg_proto",
+	srcs: ["a_fg.proto"],
+}`,
+		},
+		Blueprint: soongCcProtoPreamble + `
+cc_library {
+	name: "a",
+	srcs: [
+    ":a_fg_proto",
+    "a.proto",
+  ],
+	proto: {
+		export_proto_headers: true,
+	},
+	include_build_directory: false,
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("proto_library", "a_proto", AttrNameToString{
+				"deps": `["//path/to/A:a_fg_proto_bp2build_converted"]`,
+				"srcs": `["a.proto"]`,
+			}), MakeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
+				"deps": `[
+        "//path/to/A:a_fg_proto_bp2build_converted",
+        ":a_proto",
+    ]`,
+			}), MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
+				"deps":               `[":libprotobuf-cpp-lite"]`,
+				"whole_archive_deps": `[":a_cc_proto_lite"]`,
+			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
+				"whole_archive_deps": `[":a_cc_proto_lite"]`,
+			}),
+		},
+	})
+}
+
 func TestCcLibraryProtoFilegroups(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
 		ModuleTypeUnderTest:        "cc_library",
@@ -2556,6 +2682,40 @@
 	)
 }
 
+func TestCcLibraryStubsAcrossConfigsDuplicatesRemoved(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "stub target generation of the same lib across configs should not result in duplicates",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"bar.map.txt": "",
+		},
+		Blueprint: `
+cc_library {
+	name: "barlib",
+	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
+	bazel_module: { bp2build_available: false },
+}
+cc_library {
+	name: "foolib",
+	shared_libs: ["barlib"],
+	target: {
+		android: {
+			shared_libs: ["barlib"],
+		},
+	},
+	bazel_module: { bp2build_available: true },
+}`,
+		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
+			"implementation_dynamic_deps": `select({
+        "//build/bazel/rules/apex:android-in_apex": [":barlib_stub_libs_current"],
+        "//conditions:default": [":barlib"],
+    })`,
+			"local_includes": `["."]`,
+		}),
+	})
+}
+
 func TestCcLibraryEscapeLdflags(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
 		ModuleTypeUnderTest:        "cc_library",
@@ -2792,10 +2952,9 @@
 				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
 				"local_includes":                    `["."]`,
 			}),
-			// TODO(b/239311679) Add implementation_whole_archive_deps to cc_library_shared
-			// for bp2build to be fully correct. This fallback is affecting proto as well.
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes": `["."]`,
+				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
+				"local_includes":                    `["."]`,
 			}),
 		},
 	})
@@ -2829,10 +2988,9 @@
 				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
 				"local_includes":                    `["."]`,
 			}),
-			// TODO(b/239311679) Add implementation_whole_archive_deps to cc_library_shared
-			// for bp2build to be fully correct. This fallback is affecting proto as well.
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes": `["."]`,
+				"local_includes":                    `["."]`,
+				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
 			}),
 		},
 	})
@@ -2871,3 +3029,222 @@
 		},
 	})
 }
+
+func TestCcLibraryWithTargetApex(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with target.apex",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+    name: "foo",
+	shared_libs: ["bar", "baz"],
+	static_libs: ["baz", "buh"],
+	target: {
+        apex: {
+            exclude_shared_libs: ["bar"],
+            exclude_static_libs: ["buh"],
+        }
+    }
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+        "//build/bazel/rules/apex:non_apex": [":buh__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [],
+    })`,
+				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+        "//build/bazel/rules/apex:non_apex": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+        "//build/bazel/rules/apex:non_apex": [":buh__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [],
+    })`,
+				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+        "//build/bazel/rules/apex:non_apex": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryWithTargetApexAndExportLibHeaders(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with target.apex and export_shared|static_lib_headers",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+    name: "foo",
+	shared_libs: ["bar", "baz"],
+    static_libs: ["abc"],
+    export_shared_lib_headers: ["baz"],
+    export_static_lib_headers: ["abc"],
+	target: {
+        apex: {
+            exclude_shared_libs: ["baz", "bar"],
+            exclude_static_libs: ["abc"],
+        }
+    }
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"implementation_dynamic_deps": `select({
+        "//build/bazel/rules/apex:non_apex": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [],
+    })`,
+				"dynamic_deps": `select({
+        "//build/bazel/rules/apex:non_apex": [":baz__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [],
+    })`,
+				"deps": `select({
+        "//build/bazel/rules/apex:non_apex": [":abc__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+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 4d8e59b..6253de6 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -338,22 +338,30 @@
 	})
 }
 
-func TestCcLibrarySharedVersionScript(t *testing.T) {
+func TestCcLibrarySharedVersionScriptAndDynamicList(t *testing.T) {
 	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared version script",
+		Description: "cc_library_shared version script and dynamic list",
 		Filesystem: map[string]string{
 			"version_script": "",
+			"dynamic.list":   "",
 		},
 		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
     name: "foo_shared",
     version_script: "version_script",
+    dynamic_list: "dynamic.list",
     include_build_directory: false,
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"additional_linker_inputs": `["version_script"]`,
-				"linkopts":                 `["-Wl,--version-script,$(location version_script)"]`,
+				"additional_linker_inputs": `[
+        "version_script",
+        "dynamic.list",
+    ]`,
+				"linkopts": `[
+        "-Wl,--version-script,$(location version_script)",
+        "-Wl,--dynamic-list,$(location dynamic.list)",
+    ]`,
 			}),
 		},
 	})
@@ -454,6 +462,9 @@
 
 func TestCcLibrarySharedUseVersionLib(t *testing.T) {
 	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
+			soongCcVersionLibBpPath: soongCcVersionLibBp,
+		},
 		Blueprint: soongCcProtoPreamble + `cc_library_shared {
         name: "foo",
         use_version_lib: true,
@@ -461,7 +472,8 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"use_version_lib": "True",
+				"use_version_lib":                   "True",
+				"implementation_whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
 			}),
 		},
 	})
@@ -484,12 +496,21 @@
 `,
 		},
 		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: []string{MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-			"has_stubs": `True`,
+		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) {
@@ -714,3 +735,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 0637ba2..b47d1f1 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -836,6 +836,10 @@
             "not-for-lib32.c",
             "for-lib64.c",
         ],
+        "//build/bazel/platforms/arch:riscv64": [
+            "not-for-lib32.c",
+            "for-lib64.c",
+        ],
         "//build/bazel/platforms/arch:x86": [
             "not-for-lib64.c",
             "for-lib32.c",
@@ -867,6 +871,7 @@
 			"for-lib64.c":          "",
 			"not-for-arm.c":        "",
 			"not-for-arm64.c":      "",
+			"not-for-riscv64.c":    "",
 			"not-for-x86.c":        "",
 			"not-for-x86_64.c":     "",
 			"not-for-lib32.c":      "",
@@ -881,6 +886,7 @@
    arch: {
        arm: { srcs: ["for-arm.c"], exclude_srcs: ["not-for-arm.c"] },
        arm64: { srcs: ["for-arm64.c"], exclude_srcs: ["not-for-arm64.c"] },
+       riscv64: { srcs: ["for-riscv64.c"], exclude_srcs: ["not-for-riscv64.c"] },
        x86: { srcs: ["for-x86.c"], exclude_srcs: ["not-for-x86.c"] },
        x86_64: { srcs: ["for-x86_64.c"], exclude_srcs: ["not-for-x86_64.c"] },
    },
@@ -896,6 +902,7 @@
         "//build/bazel/platforms/arch:arm": [
             "not-for-arm64.c",
             "not-for-lib64.c",
+            "not-for-riscv64.c",
             "not-for-x86.c",
             "not-for-x86_64.c",
             "for-arm.c",
@@ -904,15 +911,26 @@
         "//build/bazel/platforms/arch:arm64": [
             "not-for-arm.c",
             "not-for-lib32.c",
+            "not-for-riscv64.c",
             "not-for-x86.c",
             "not-for-x86_64.c",
             "for-arm64.c",
             "for-lib64.c",
         ],
+        "//build/bazel/platforms/arch:riscv64": [
+            "not-for-arm.c",
+            "not-for-arm64.c",
+            "not-for-lib32.c",
+            "not-for-x86.c",
+            "not-for-x86_64.c",
+            "for-riscv64.c",
+            "for-lib64.c",
+        ],
         "//build/bazel/platforms/arch:x86": [
             "not-for-arm.c",
             "not-for-arm64.c",
             "not-for-lib64.c",
+            "not-for-riscv64.c",
             "not-for-x86_64.c",
             "for-x86.c",
             "for-lib32.c",
@@ -921,6 +939,7 @@
             "not-for-arm.c",
             "not-for-arm64.c",
             "not-for-lib32.c",
+            "not-for-riscv64.c",
             "not-for-x86.c",
             "for-x86_64.c",
             "for-lib64.c",
@@ -930,6 +949,7 @@
             "not-for-arm64.c",
             "not-for-lib32.c",
             "not-for-lib64.c",
+            "not-for-riscv64.c",
             "not-for-x86.c",
             "not-for-x86_64.c",
         ],
@@ -1392,6 +1412,16 @@
 		Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
 		Blueprint: soongCcLibraryStaticPreamble +
 			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
+
+cc_library {
+    name: "libm",
+    stubs: {
+        symbol_file: "libm.map.txt",
+        versions: ["current"],
+    },
+    bazel_module: { bp2build_available: false },
+}
+
 cc_library_static {
     name: "used_in_bionic_oses",
     target: {
@@ -1414,7 +1444,20 @@
 cc_library_static {
     name: "keep_for_empty_system_shared_libs",
     shared_libs: ["libc"],
-		system_shared_libs: [],
+    system_shared_libs: [],
+    include_build_directory: false,
+}
+
+cc_library_static {
+    name: "used_with_stubs",
+    shared_libs: ["libm"],
+    include_build_directory: false,
+}
+
+cc_library_static {
+    name: "keep_with_stubs",
+    shared_libs: ["libm"],
+    system_shared_libs: [],
     include_build_directory: false,
 }
 `,
@@ -1424,7 +1467,15 @@
 				"implementation_dynamic_deps": `[":libc"]`,
 				"system_dynamic_deps":         `[]`,
 			}),
+			MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{
+				"implementation_dynamic_deps": `select({
+        "//build/bazel/rules/apex:android-in_apex": [":libm_stub_libs_current"],
+        "//conditions:default": [":libm"],
+    })`,
+				"system_dynamic_deps": `[]`,
+			}),
 			MakeBazelTarget("cc_library_static", "used_in_bionic_oses", AttrNameToString{}),
+			MakeBazelTarget("cc_library_static", "used_with_stubs", AttrNameToString{}),
 		},
 	})
 }
@@ -1454,14 +1505,37 @@
 
 func TestCcLibraryStaticUseVersionLib(t *testing.T) {
 	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
+			soongCcVersionLibBpPath: soongCcVersionLibBp,
+		},
 		Blueprint: soongCcProtoPreamble + `cc_library_static {
 	name: "foo",
 	use_version_lib: true,
+	static_libs: ["libbuildversion"],
 	include_build_directory: false,
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"use_version_lib": "True",
+				"implementation_whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryStaticUseVersionLibHasDep(t *testing.T) {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
+			soongCcVersionLibBpPath: soongCcVersionLibBp,
+		},
+		Blueprint: soongCcProtoPreamble + `cc_library_static {
+	name: "foo",
+	use_version_lib: true,
+	whole_static_libs: ["libbuildversion"],
+	include_build_directory: false,
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
 			}),
 		},
 	})
@@ -1575,3 +1649,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/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 9b7748f..8c2d30d 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -148,3 +148,27 @@
 		},
 	})
 }
+
+func TestCcTest_TestOptions_Tags(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "cc test with test_options.tags converted to tags",
+		blueprint: `
+cc_test {
+    name: "mytest",
+    host_supported: true,
+    srcs: ["test.cpp"],
+    test_options: { tags: ["no-remote"] },
+}
+`,
+		targets: []testBazelTarget{
+			{"cc_test", "mytest", AttrNameToString{
+				"tags":           `["no-remote"]`,
+				"local_includes": `["."]`,
+				"srcs":           `["test.cpp"]`,
+				"gtest":          "True",
+				"isolated":       "True",
+			},
+			},
+		},
+	})
+}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 731b17e..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()))
@@ -96,10 +102,14 @@
 # This file was automatically generated by bp2build for the Bazel migration project.
 # Feel free to edit or test it, but do *not* check it into your version control system.
 `
-
-			// Hardcode the default visibility.
-			content += "package(default_visibility = [\"//visibility:public\"])\n"
 			content += targets.LoadStatements()
+			content += "\n\n"
+			// Get package rule from the handcrafted BUILD file, otherwise emit the default one.
+			prText := "package(default_visibility = [\"//visibility:public\"])\n"
+			if pr := targets.packageRule(); pr != nil {
+				prText = pr.content
+			}
+			content += prText
 		} else if mode == QueryView {
 			content = soongModuleLoad
 		}
@@ -160,7 +170,7 @@
 		// internal to Soong only, and these fields do not have PkgPath.
 		return true
 	}
-	// fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
+	// fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc.
 	// but cannot be set in a .bp file
 	if proptools.HasTag(field, "blueprint", "mutated") {
 		return true
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/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index de09a17..e978fb3 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -15,10 +15,10 @@
 package bp2build
 
 import (
-	"android/soong/android"
 	"fmt"
-
 	"testing"
+
+	"android/soong/android"
 )
 
 func runFilegroupTestCase(t *testing.T, tc Bp2buildTestCase) {
@@ -121,3 +121,44 @@
     ]`}),
 		}})
 }
+
+func TestFilegroupWithProtoSrcs(t *testing.T) {
+	runFilegroupTestCase(t, Bp2buildTestCase{
+		Description: "filegroup with proto and non-proto srcs",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+filegroup {
+		name: "foo",
+		srcs: ["proto/foo.proto"],
+		path: "proto",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("proto_library", "foo_bp2build_converted", AttrNameToString{
+				"srcs":                `["proto/foo.proto"]`,
+				"strip_import_prefix": `"proto"`,
+				"tags":                `["manual"]`}),
+			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
+				"srcs": `["proto/foo.proto"]`}),
+		}})
+}
+
+func TestFilegroupWithProtoAndNonProtoSrcs(t *testing.T) {
+	runFilegroupTestCase(t, Bp2buildTestCase{
+		Description: "filegroup with proto and non-proto srcs",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+filegroup {
+    name: "foo",
+    srcs: [
+		"foo.proto",
+		"buf.cpp",
+	],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
+				"srcs": `[
+        "foo.proto",
+        "buf.cpp",
+    ]`}),
+		}})
+}
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/license_conversion_test.go b/bp2build/license_conversion_test.go
new file mode 100644
index 0000000..ea6b27a
--- /dev/null
+++ b/bp2build/license_conversion_test.go
@@ -0,0 +1,81 @@
+// 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 (
+	"android/soong/android"
+	"testing"
+)
+
+func registerLicenseModuleTypes(_ android.RegistrationContext) {}
+
+func TestLicenseBp2Build(t *testing.T) {
+	tests := []struct {
+		description string
+		module      string
+		expected    ExpectedRuleTarget
+	}{
+		{
+			description: "license kind and text notice",
+			module: `
+license {
+    name: "my_license",
+    license_kinds: [ "SPDX-license-identifier-Apache-2.0"],
+    license_text: [ "NOTICE"],
+}`,
+			expected: ExpectedRuleTarget{
+				"android_license",
+				"my_license",
+				AttrNameToString{
+					"license_kinds": `["SPDX-license-identifier-Apache-2.0"]`,
+					"license_text":  `"NOTICE"`,
+				},
+				android.HostAndDeviceDefault,
+			},
+		},
+		{
+			description: "visibility, package_name, copyright_notice",
+			module: `
+license {
+	name: "my_license",
+    package_name: "my_package",
+    visibility: [":__subpackages__"],
+    copyright_notice: "Copyright © 2022",
+}`,
+			expected: ExpectedRuleTarget{
+				"android_license",
+				"my_license",
+				AttrNameToString{
+					"copyright_notice": `"Copyright © 2022"`,
+					"package_name":     `"my_package"`,
+					"visibility":       `[":__subpackages__"]`,
+				},
+				android.HostAndDeviceDefault,
+			},
+		},
+	}
+
+	for _, test := range tests {
+		RunBp2BuildTestCase(t,
+			registerLicenseModuleTypes,
+			Bp2buildTestCase{
+				Description:                test.description,
+				ModuleTypeUnderTest:        "license",
+				ModuleTypeUnderTestFactory: android.LicenseFactory,
+				Blueprint:                  test.module,
+				ExpectedBazelTargets:       []string{test.expected.String()},
+			})
+	}
+}
diff --git a/bp2build/license_kind_conversion_test.go b/bp2build/license_kind_conversion_test.go
new file mode 100644
index 0000000..eda116c
--- /dev/null
+++ b/bp2build/license_kind_conversion_test.go
@@ -0,0 +1,69 @@
+// 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 (
+	"android/soong/android"
+	"testing"
+)
+
+func registerLicenseKindModuleTypes(_ android.RegistrationContext) {}
+
+func TestLicenseKindBp2Build(t *testing.T) {
+	tests := []struct {
+		description string
+		module      string
+		expected    ExpectedRuleTarget
+	}{
+		{
+			description: "license_kind",
+			module: `
+license_kind {
+    name: "my_license",
+    conditions: [
+        "by_exception_only",
+        "not_allowed",
+    ],
+    url: "https://spdx.org/licenses/0BSD",
+    visibility: ["//visibility:public"],
+}`,
+			expected: ExpectedRuleTarget{
+				"license_kind",
+				"my_license",
+				AttrNameToString{
+					"conditions": `[
+        "by_exception_only",
+        "not_allowed",
+    ]`,
+					"url":        `"https://spdx.org/licenses/0BSD"`,
+					"visibility": `["//visibility:public"]`,
+				},
+				android.HostAndDeviceDefault,
+			},
+		},
+	}
+
+	for _, test := range tests {
+		RunBp2BuildTestCase(t,
+			registerLicenseKindModuleTypes,
+			Bp2buildTestCase{
+				Description:                test.description,
+				ModuleTypeUnderTest:        "license_kind",
+				ModuleTypeUnderTestFactory: android.LicenseKindFactory,
+				Blueprint:                  test.module,
+				ExpectedBazelTargets:       []string{test.expected.String()},
+			})
+	}
+}
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/package_conversion_test.go b/bp2build/package_conversion_test.go
new file mode 100644
index 0000000..3704b2d
--- /dev/null
+++ b/bp2build/package_conversion_test.go
@@ -0,0 +1,85 @@
+// 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 (
+	"android/soong/android"
+	"android/soong/genrule"
+	"testing"
+)
+
+func registerDependentModules(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("license", android.LicenseFactory)
+	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
+}
+
+func TestPackage(t *testing.T) {
+	tests := []struct {
+		description string
+		modules     string
+		expected    []ExpectedRuleTarget
+	}{
+		{
+			description: "with default applicable licenses",
+			modules: `
+license {
+  name: "my_license",
+  visibility: [":__subpackages__"],
+  license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+  license_text: ["NOTICE"],
+}
+
+package {
+  default_applicable_licenses: ["my_license"],
+}
+`,
+			expected: []ExpectedRuleTarget{
+				{
+					"package",
+					"",
+					AttrNameToString{
+						"default_applicable_licenses": `[":my_license"]`,
+						"default_visibility":          `["//visibility:public"]`,
+					},
+					android.HostAndDeviceDefault,
+				},
+				{
+					"android_license",
+					"my_license",
+					AttrNameToString{
+						"license_kinds": `["SPDX-license-identifier-Apache-2.0"]`,
+						"license_text":  `"NOTICE"`,
+						"visibility":    `[":__subpackages__"]`,
+					},
+					android.HostAndDeviceDefault,
+				},
+			},
+		},
+	}
+	for _, test := range tests {
+		expected := make([]string, 0, len(test.expected))
+		for _, e := range test.expected {
+			expected = append(expected, e.String())
+		}
+		RunBp2BuildTestCase(t, registerDependentModules,
+			Bp2buildTestCase{
+				Description:                test.description,
+				ModuleTypeUnderTest:        "package",
+				ModuleTypeUnderTestFactory: android.PackageFactory,
+				Blueprint:                  test.modules,
+				ExpectedBazelTargets:       expected,
+			})
+	}
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index ac1268c..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()
 
@@ -141,7 +151,7 @@
 		android.FailIfErrored(t, errs)
 	}
 	if actualCount, expectedCount := len(bazelTargets), len(tc.ExpectedBazelTargets); actualCount != expectedCount {
-		t.Errorf("%s: Expected %d bazel target (%s), got `%d`` (%s)",
+		t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
 			tc.Description, expectedCount, tc.ExpectedBazelTargets, actualCount, bazelTargets)
 	} else {
 		for i, target := range bazelTargets {
@@ -429,7 +439,9 @@
 	}
 
 	attrStrings := make([]string, 0, len(attrs)+1)
-	attrStrings = append(attrStrings, fmt.Sprintf(`    name = "%s",`, name))
+	if name != "" {
+		attrStrings = append(attrStrings, fmt.Sprintf(`    name = "%s",`, name))
+	}
 	for _, k := range android.SortedStringKeys(attrs) {
 		attrStrings = append(attrStrings, fmt.Sprintf("    %s = %s,", k, attrs[k]))
 	}
@@ -450,3 +462,34 @@
 func MakeBazelTarget(typ, name string, attrs AttrNameToString) string {
 	return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
 }
+
+type ExpectedRuleTarget struct {
+	Rule  string
+	Name  string
+	Attrs AttrNameToString
+	Hod   android.HostOrDeviceSupported
+}
+
+func (ebr ExpectedRuleTarget) String() string {
+	return makeBazelTargetHostOrDevice(ebr.Rule, ebr.Name, ebr.Attrs, ebr.Hod)
+}
+
+func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
+	if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
+		return ""
+	}
+	STUB_SUITE_ATTRS := map[string]string{
+		"stubs_symbol_file": "symbol_file",
+		"stubs_versions":    "versions",
+		"soname":            "soname",
+		"source_library":    "source_library",
+	}
+
+	stubSuiteAttrs := AttrNameToString{}
+	for key, _ := range attrs {
+		if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
+			stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
+		}
+	}
+	return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
+}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index e89cc4e..dbbce50 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -21,6 +21,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/bazel"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -93,6 +94,7 @@
 
 type bpf struct {
 	android.ModuleBase
+	android.BazelModuleBase
 
 	properties BpfProperties
 
@@ -260,5 +262,39 @@
 	module.AddProperties(&module.properties)
 
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitBazelModule(module)
 	return module
 }
+
+type bazelBpfAttributes struct {
+	Srcs              bazel.LabelListAttribute
+	Copts             bazel.StringListAttribute
+	Absolute_includes bazel.StringListAttribute
+	Btf               *bool
+	// TODO(b/249528391): Add support for sub_dir
+}
+
+// bpf bp2build converter
+func (b *bpf) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	if ctx.ModuleType() != "bpf" {
+		return
+	}
+
+	srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, b.properties.Srcs))
+	copts := bazel.MakeStringListAttribute(b.properties.Cflags)
+	absolute_includes := bazel.MakeStringListAttribute(b.properties.Include_dirs)
+	btf := b.properties.Btf
+
+	attrs := bazelBpfAttributes{
+		Srcs:              srcs,
+		Copts:             copts,
+		Absolute_includes: absolute_includes,
+		Btf:               btf,
+	}
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "bpf",
+		Bzl_load_location: "//build/bazel/rules/bpf:bpf.bzl",
+	}
+
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: b.Name()}, &attrs)
+}
diff --git a/build_test.bash b/build_test.bash
index 8b91e2c..6f0fba7 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -59,7 +59,7 @@
 
 echo
 echo "Running Bazel smoke test..."
-STANDALONE_BAZEL=true "${TOP}/tools/bazel" --batch --max_idle_secs=1 info
+STANDALONE_BAZEL=true "${TOP}/tools/bazel" --batch --max_idle_secs=1 help
 
 echo
 echo "Running Soong test..."
diff --git a/cc/Android.bp b/cc/Android.bp
index 1ead99b..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",
@@ -98,6 +99,7 @@
         "library_headers_test.go",
         "library_stub_test.go",
         "library_test.go",
+        "lto_test.go",
         "ndk_test.go",
         "object_test.go",
         "prebuilt_test.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index a2e0a31..83368a3 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -28,14 +28,17 @@
 )
 
 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"
 )
 
 // staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
@@ -77,10 +80,10 @@
 			if !exists || !android.IsFilegroup(otherModuleCtx, m) {
 				return labelStr, false
 			}
-			// If the filegroup is already converted to aidl_library, skip creating
-			// _c_srcs, _as_srcs, _cpp_srcs filegroups
-			fg, _ := m.(android.Bp2buildAidlLibrary)
-			if fg.ShouldConvertToAidlLibrary(ctx) {
+			// If the filegroup is already converted to aidl_library or proto_library,
+			// skip creating _c_srcs, _as_srcs, _cpp_srcs filegroups
+			fg, _ := m.(android.FileGroupAsLibrary)
+			if fg.ShouldConvertToAidlLibrary(ctx) || fg.ShouldConvertToProtoLibrary(ctx) {
 				return labelStr, false
 			}
 			return labelStr + suffix, true
@@ -102,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)
@@ -318,6 +322,9 @@
 	llSrcs  bazel.LabelListAttribute
 	lexopts bazel.StringListAttribute
 
+	// Sysprop sources
+	syspropSrcs bazel.LabelListAttribute
+
 	hdrs bazel.LabelListAttribute
 
 	rtti bazel.BoolAttribute
@@ -480,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()
@@ -504,19 +512,6 @@
 	return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs
 }
 
-// Given a name in srcs prop, check to see if the name references a filegroup
-// and the filegroup is converted to aidl_library
-func isConvertedToAidlLibrary(ctx android.BazelConversionPathContext, name string) bool {
-	if module, ok := ctx.ModuleFromName(name); ok {
-		if android.IsFilegroup(ctx, module) {
-			if fg, ok := module.(android.Bp2buildAidlLibrary); ok {
-				return fg.ShouldConvertToAidlLibrary(ctx)
-			}
-		}
-	}
-	return false
-}
-
 func bp2buildStdVal(std *string, prefix string, useGnu bool) *string {
 	defaultVal := prefix + "_std_default"
 	// If c{,pp}std properties are not specified, don't generate them in the BUILD file.
@@ -730,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) {
@@ -745,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()
 
@@ -757,78 +756,69 @@
 	}
 }
 
-func bp2buildAidlLibraries(
-	ctx android.Bp2buildMutatorContext,
-	m *Module,
-	aidlSrcs bazel.LabelListAttribute,
-) bazel.LabelList {
-	var aidlLibraries bazel.LabelList
-	var directAidlSrcs bazel.LabelList
-
-	// Make a list of labels that correspond to filegroups that are already converted to aidl_library
-	for _, aidlSrc := range aidlSrcs.Value.Includes {
-		src := aidlSrc.OriginalModuleName
-		if isConvertedToAidlLibrary(ctx, src) {
-			module, _ := ctx.ModuleFromName(src)
-			fg, _ := module.(android.Bp2buildAidlLibrary)
-			aidlLibraries.Add(&bazel.Label{
-				Label: fg.GetAidlLibraryLabel(ctx),
-			})
-		} else {
-			directAidlSrcs.Add(&aidlSrc)
-		}
-	}
-
-	if len(directAidlSrcs.Includes) > 0 {
-		aidlLibraryLabel := m.Name() + "_aidl_library"
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "aidl_library",
-				Bzl_load_location: "//build/bazel/rules/aidl:library.bzl",
-			},
-			android.CommonAttributes{Name: aidlLibraryLabel},
-			&aidlLibraryAttributes{
-				Srcs: bazel.MakeLabelListAttribute(directAidlSrcs),
-			},
-		)
-		aidlLibraries.Add(&bazel.Label{
-			Label: ":" + aidlLibraryLabel,
-		})
-	}
-	return aidlLibraries
-}
-
 func bp2buildCcAidlLibrary(
 	ctx android.Bp2buildMutatorContext,
 	m *Module,
-	aidlSrcs bazel.LabelListAttribute,
+	aidlLabelList bazel.LabelListAttribute,
+	linkerAttrs linkerAttributes,
 ) *bazel.LabelAttribute {
-	suffix := "_cc_aidl_library"
-	ccAidlLibrarylabel := m.Name() + suffix
+	if !aidlLabelList.IsEmpty() {
+		aidlLibs, aidlSrcs := aidlLabelList.Partition(func(src bazel.Label) bool {
+			if fg, ok := android.ToFileGroupAsLibrary(ctx, src.OriginalModuleName); ok &&
+				fg.ShouldConvertToAidlLibrary(ctx) {
+				return true
+			}
+			return false
+		})
 
-	aidlLibraries := bp2buildAidlLibraries(ctx, m, aidlSrcs)
+		if !aidlSrcs.IsEmpty() {
+			aidlLibName := m.Name() + "_aidl_library"
+			ctx.CreateBazelTargetModule(
+				bazel.BazelTargetModuleProperties{
+					Rule_class:        "aidl_library",
+					Bzl_load_location: "//build/bazel/rules/aidl:library.bzl",
+				},
+				android.CommonAttributes{Name: aidlLibName},
+				&aidlLibraryAttributes{
+					Srcs: aidlSrcs,
+				},
+			)
+			aidlLibs.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + aidlLibName}})
+		}
 
-	if aidlLibraries.IsEmpty() {
-		return nil
+		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",
+					Bzl_load_location: "//build/bazel/rules/cc:cc_aidl_library.bzl",
+				},
+				android.CommonAttributes{Name: ccAidlLibrarylabel},
+				&ccAidlLibraryAttributes{
+					Deps:                        aidlLibs,
+					Implementation_dynamic_deps: implementationDynamicDeps,
+				},
+			)
+			label := &bazel.LabelAttribute{
+				Value: &bazel.Label{
+					Label: ":" + ccAidlLibrarylabel,
+				},
+			}
+			return label
+		}
 	}
 
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_aidl_library",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_aidl_library.bzl",
-		},
-		android.CommonAttributes{Name: ccAidlLibrarylabel},
-		&ccAidlLibraryAttributes{
-			Deps: bazel.MakeLabelListAttribute(aidlLibraries),
-		},
-	)
-
-	label := &bazel.LabelAttribute{
-		Value: &bazel.Label{
-			Label: ":" + ccAidlLibrarylabel,
-		},
-	}
-	return label
+	return nil
 }
 
 func bp2BuildParseSdkAttributes(module *Module) sdkAttributes {
@@ -870,19 +860,77 @@
 
 var (
 	soongSystemSharedLibs = []string{"libc", "libm", "libdl"}
+	versionLib            = "libbuildversion"
 )
 
+// resolveTargetApex re-adds the shared and static libs in target.apex.exclude_shared|static_libs props to non-apex variant
+// since all libs are already excluded by default
+func (la *linkerAttributes) resolveTargetApexProp(ctx android.BazelConversionPathContext, isBinary bool, props *BaseLinkerProperties) {
+	sharedLibsForNonApex := maybePartitionExportedAndImplementationsDeps(
+		ctx,
+		true,
+		props.Target.Apex.Exclude_shared_libs,
+		props.Export_shared_lib_headers,
+		bazelLabelForSharedDeps,
+	)
+	dynamicDeps := la.dynamicDeps.SelectValue(bazel.InApexAxis, bazel.NonApex)
+	implDynamicDeps := la.implementationDynamicDeps.SelectValue(bazel.InApexAxis, bazel.NonApex)
+	(&dynamicDeps).Append(sharedLibsForNonApex.export)
+	(&implDynamicDeps).Append(sharedLibsForNonApex.implementation)
+	la.dynamicDeps.SetSelectValue(bazel.InApexAxis, bazel.NonApex, dynamicDeps)
+	la.implementationDynamicDeps.SetSelectValue(bazel.InApexAxis, bazel.NonApex, implDynamicDeps)
+
+	staticLibsForNonApex := maybePartitionExportedAndImplementationsDeps(
+		ctx,
+		!isBinary,
+		props.Target.Apex.Exclude_static_libs,
+		props.Export_static_lib_headers,
+		bazelLabelForSharedDeps,
+	)
+	deps := la.deps.SelectValue(bazel.InApexAxis, bazel.NonApex)
+	implDeps := la.implementationDeps.SelectValue(bazel.InApexAxis, bazel.NonApex)
+	(&deps).Append(staticLibsForNonApex.export)
+	(&implDeps).Append(staticLibsForNonApex.implementation)
+	la.deps.SetSelectValue(bazel.InApexAxis, bazel.NonApex, deps)
+	la.implementationDeps.SetSelectValue(bazel.InApexAxis, bazel.NonApex, implDeps)
+}
+
 func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, isBinary bool, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
 	// Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module
 	var axisFeatures []string
 
 	wholeStaticLibs := android.FirstUniqueStrings(props.Whole_static_libs)
-	la.wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, props.Exclude_static_libs))
+	staticLibs := android.FirstUniqueStrings(android.RemoveListFromList(props.Static_libs, wholeStaticLibs))
+	if axis == bazel.NoConfigAxis {
+		la.useVersionLib.SetSelectValue(axis, config, props.Use_version_lib)
+		if proptools.Bool(props.Use_version_lib) {
+			versionLibAlreadyInDeps := android.InList(versionLib, wholeStaticLibs)
+			// remove from static libs so there is no duplicate dependency
+			_, staticLibs = android.RemoveFromList(versionLib, staticLibs)
+			// only add the dep if it is not in progress
+			if !versionLibAlreadyInDeps {
+				if isBinary {
+					wholeStaticLibs = append(wholeStaticLibs, versionLib)
+				} else {
+					la.implementationWholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, []string{versionLib}, props.Exclude_static_libs))
+				}
+			}
+		}
+	}
+
 	// Excludes to parallel Soong:
 	// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0
-	staticLibs := android.FirstUniqueStrings(android.RemoveListFromList(props.Static_libs, wholeStaticLibs))
+	la.wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, props.Exclude_static_libs))
 
-	staticDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, staticLibs, props.Exclude_static_libs, props.Export_static_lib_headers, bazelLabelForStaticDepsExcludes)
+	staticDeps := maybePartitionExportedAndImplementationsDepsExcludes(
+		ctx,
+		!isBinary,
+		staticLibs,
+		// Exclude static libs in Exclude_static_libs and Target.Apex.Exclude_static_libs props
+		append(props.Exclude_static_libs, props.Target.Apex.Exclude_static_libs...),
+		props.Export_static_lib_headers,
+		bazelLabelForStaticDepsExcludes,
+	)
 
 	headerLibs := android.FirstUniqueStrings(props.Header_libs)
 	hDeps := maybePartitionExportedAndImplementationsDeps(ctx, !isBinary, headerLibs, props.Export_header_lib_headers, bazelLabelForHeaderDeps)
@@ -914,9 +962,19 @@
 		la.usedSystemDynamicDepAsDynamicDep[el] = true
 	}
 
-	sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, sharedLibs, props.Exclude_shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDepsExcludes)
+	sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes(
+		ctx,
+		!isBinary,
+		sharedLibs,
+		// Exclude shared libs in Exclude_shared_libs and Target.Apex.Exclude_shared_libs props
+		append(props.Exclude_shared_libs, props.Target.Apex.Exclude_shared_libs...),
+		props.Export_shared_lib_headers,
+		bazelLabelForSharedDepsExcludes,
+	)
 	la.dynamicDeps.SetSelectValue(axis, config, sharedDeps.export)
 	la.implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation)
+	la.resolveTargetApexProp(ctx, isBinary, props)
+
 	if axis == bazel.NoConfigAxis || (axis == bazel.OsConfigurationAxis && config == bazel.OsAndroid) {
 		// If a dependency in la.implementationDynamicDeps has stubs, its stub variant should be
 		// used when the dependency is linked in a APEX. The dependencies in NoConfigAxis and
@@ -935,7 +993,7 @@
 
 			stubLibLabels := []bazel.Label{}
 			for _, l := range depsWithStubs {
-				l.Label = l.Label + "_stub_libs_current"
+				l.Label = l.Label + stubsSuffix
 				stubLibLabels = append(stubLibLabels, l)
 			}
 			inApexSelectValue := la.implementationDynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
@@ -945,14 +1003,14 @@
 				(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
 				(&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
 				(&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
-				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, inApexSelectValue)
-				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, nonApexSelectValue)
-				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, defaultSelectValue)
+				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
+				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
+				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
 			} else if config == bazel.OsAndroid {
 				(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
 				(&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
-				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, inApexSelectValue)
-				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, nonApexSelectValue)
+				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
+				la.implementationDynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
 			}
 		}
 	}
@@ -973,25 +1031,23 @@
 			axisFeatures = append(axisFeatures, "-static_flag")
 		}
 	}
+	additionalLinkerInputs := bazel.LabelList{}
 	if props.Version_script != nil {
 		label := android.BazelLabelForModuleSrcSingle(ctx, *props.Version_script)
-		la.additionalLinkerInputs.SetSelectValue(axis, config, bazel.LabelList{Includes: []bazel.Label{label}})
+		additionalLinkerInputs.Add(&label)
 		linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--version-script,$(location %s)", label.Label))
 	}
 
 	if props.Dynamic_list != nil {
 		label := android.BazelLabelForModuleSrcSingle(ctx, *props.Dynamic_list)
-		la.additionalLinkerInputs.SetSelectValue(axis, config, bazel.LabelList{Includes: []bazel.Label{label}})
+		additionalLinkerInputs.Add(&label)
 		linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--dynamic-list,$(location %s)", label.Label))
 	}
 
+	la.additionalLinkerInputs.SetSelectValue(axis, config, additionalLinkerInputs)
 	la.linkopts.SetSelectValue(axis, config, parseCommandLineFlags(linkerFlags, false, filterOutClangUnknownCflags))
 	la.useLibcrt.SetSelectValue(axis, config, props.libCrt())
 
-	if axis == bazel.NoConfigAxis {
-		la.useVersionLib.SetSelectValue(axis, config, props.Use_version_lib)
-	}
-
 	// it's very unlikely for nocrt to be arch variant, so bp2build doesn't support it.
 	if props.crt() != nil {
 		if axis == bazel.NoConfigAxis {
@@ -1096,12 +1152,20 @@
 	if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsDynamicDep) > 0 {
 		toRemove := bazelLabelForSharedDeps(ctx, android.SortedStringKeys(la.usedSystemDynamicDepAsDynamicDep))
 		la.dynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
-		la.implementationDynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
-		la.implementationDynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
 		la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
 		la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
+		la.implementationDynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
 		la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
 		la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
+
+		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, toRemove)
+		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, toRemove)
+		stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep))
+		for _, lib := range toRemove.Includes {
+			lib.Label += stubsSuffix
+			stubsToRemove = append(stubsToRemove, lib)
+		}
+		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove))
 	}
 
 	la.deps.ResolveExcludes()
@@ -1168,10 +1232,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/builder.go b/cc/builder.go
index cb21b1f..0bea9da 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -1135,7 +1135,3 @@
 		},
 	})
 }
-
-func mingwCmd(toolchain config.Toolchain, cmd string) string {
-	return filepath.Join(toolchain.GccRoot(), "bin", toolchain.GccTriple()+"-"+cmd)
-}
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..6a22bd0 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3260,6 +3260,102 @@
 	}
 }
 
+func pathsToBase(paths android.Paths) []string {
+	var ret []string
+	for _, p := range paths {
+		ret = append(ret, p.Base())
+	}
+	return ret
+}
+
+func TestStaticLibArchiveArgs(t *testing.T) {
+	ctx := testCc(t, `
+		cc_library_static {
+			name: "foo",
+			srcs: ["foo.c"],
+		}
+
+		cc_library_static {
+			name: "bar",
+			srcs: ["bar.c"],
+		}
+
+		cc_library_shared {
+			name: "qux",
+			srcs: ["qux.c"],
+		}
+
+		cc_library_static {
+			name: "baz",
+			srcs: ["baz.c"],
+			static_libs: ["foo"],
+			shared_libs: ["qux"],
+			whole_static_libs: ["bar"],
+		}`)
+
+	variant := "android_arm64_armv8-a_static"
+	arRule := ctx.ModuleForTests("baz", variant).Rule("ar")
+
+	// For static libraries, the object files of a whole static dep are included in the archive
+	// directly
+	if g, w := pathsToBase(arRule.Inputs), []string{"bar.o", "baz.o"}; !reflect.DeepEqual(w, g) {
+		t.Errorf("Expected input objects %q, got %q", w, g)
+	}
+
+	// non whole static dependencies are not linked into the archive
+	if len(arRule.Implicits) > 0 {
+		t.Errorf("Expected 0 additional deps, got %q", arRule.Implicits)
+	}
+}
+
+func TestSharedLibLinkingArgs(t *testing.T) {
+	ctx := testCc(t, `
+		cc_library_static {
+			name: "foo",
+			srcs: ["foo.c"],
+		}
+
+		cc_library_static {
+			name: "bar",
+			srcs: ["bar.c"],
+		}
+
+		cc_library_shared {
+			name: "qux",
+			srcs: ["qux.c"],
+		}
+
+		cc_library_shared {
+			name: "baz",
+			srcs: ["baz.c"],
+			static_libs: ["foo"],
+			shared_libs: ["qux"],
+			whole_static_libs: ["bar"],
+		}`)
+
+	variant := "android_arm64_armv8-a_shared"
+	linkRule := ctx.ModuleForTests("baz", variant).Rule("ld")
+	libFlags := linkRule.Args["libFlags"]
+	// When dynamically linking, we expect static dependencies to be found on the command line
+	if expected := "foo.a"; !strings.Contains(libFlags, expected) {
+		t.Errorf("Static lib %q was not found in %q", expected, libFlags)
+	}
+	// When dynamically linking, we expect whole static dependencies to be found on the command line
+	if expected := "bar.a"; !strings.Contains(libFlags, expected) {
+		t.Errorf("Static lib %q was not found in %q", expected, libFlags)
+	}
+
+	// When dynamically linking, we expect shared dependencies to be found on the command line
+	if expected := "qux.so"; !strings.Contains(libFlags, expected) {
+		t.Errorf("Shared lib %q was not found in %q", expected, libFlags)
+	}
+
+	// We should only have the objects from the shared library srcs, not the whole static dependencies
+	if g, w := pathsToBase(linkRule.Inputs), []string{"baz.o"}; !reflect.DeepEqual(w, g) {
+		t.Errorf("Expected input objects %q, got %q", w, g)
+	}
+}
+
 func TestStaticExecutable(t *testing.T) {
 	ctx := testCc(t, `
 		cc_binary {
@@ -3543,14 +3639,6 @@
 			defaults: ["defaults"],
 		}`)
 
-	pathsToBase := func(paths android.Paths) []string {
-		var ret []string
-		for _, p := range paths {
-			ret = append(ret, p.Base())
-		}
-		return ret
-	}
-
 	shared := ctx.ModuleForTests("libshared", "android_arm64_armv8-a_shared").Rule("ld")
 	if g, w := pathsToBase(shared.Inputs), []string{"foo.o", "baz.o"}; !reflect.DeepEqual(w, g) {
 		t.Errorf("libshared ld rule wanted %q, got %q", w, g)
@@ -4386,3 +4474,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/config/Android.bp b/cc/config/Android.bp
index 64a121e..fdc94ad 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -21,6 +21,7 @@
 
         "arm_device.go",
         "arm64_device.go",
+        "riscv64_device.go",
         "x86_device.go",
         "x86_64_device.go",
 
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 66087e6..d7f9618 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -74,7 +74,7 @@
 			"-mcpu=kryo",
 		},
 		"kryo385": []string{
-			// Use cortex-a53 because kryo385 is not supported in GCC/clang.
+			// Use cortex-a53 because kryo385 is not supported in clang.
 			"-mcpu=cortex-a53",
 		},
 		"exynos-m1": []string{
@@ -86,16 +86,7 @@
 	}
 )
 
-const (
-	arm64GccVersion = "4.9"
-)
-
 func init() {
-	pctx.StaticVariable("arm64GccVersion", arm64GccVersion)
-
-	pctx.SourcePathVariable("Arm64GccRoot",
-		"prebuilts/gcc/${HostPrebuiltTag}/aarch64/aarch64-linux-android-${arm64GccVersion}")
-
 	exportedVars.ExportStringListStaticVariable("Arm64Ldflags", arm64Ldflags)
 	exportedVars.ExportStringListStaticVariable("Arm64Lldflags", arm64Lldflags)
 
@@ -164,24 +155,12 @@
 	return "arm64"
 }
 
-func (t *toolchainArm64) GccRoot() string {
-	return "${config.Arm64GccRoot}"
-}
-
-func (t *toolchainArm64) GccTriple() string {
-	return "aarch64-linux-android"
-}
-
-func (t *toolchainArm64) GccVersion() string {
-	return arm64GccVersion
-}
-
 func (t *toolchainArm64) IncludeFlags() string {
 	return ""
 }
 
 func (t *toolchainArm64) ClangTriple() string {
-	return t.GccTriple()
+	return "aarch64-linux-android"
 }
 
 func (t *toolchainArm64) Cflags() string {
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index d702c61..b53a097 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -79,7 +79,7 @@
 		"cortex-a7": []string{
 			"-mcpu=cortex-a7",
 			"-mfpu=neon-vfpv4",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -91,7 +91,7 @@
 		"cortex-a15": []string{
 			"-mcpu=cortex-a15",
 			"-mfpu=neon-vfpv4",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -100,7 +100,7 @@
 		"cortex-a53": []string{
 			"-mcpu=cortex-a53",
 			"-mfpu=neon-fp-armv8",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -109,7 +109,7 @@
 		"cortex-a55": []string{
 			"-mcpu=cortex-a55",
 			"-mfpu=neon-fp-armv8",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -118,7 +118,7 @@
 		"cortex-a75": []string{
 			"-mcpu=cortex-a55",
 			"-mfpu=neon-fp-armv8",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -127,7 +127,7 @@
 		"cortex-a76": []string{
 			"-mcpu=cortex-a55",
 			"-mfpu=neon-fp-armv8",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -136,7 +136,7 @@
 		"krait": []string{
 			"-mcpu=krait",
 			"-mfpu=neon-vfpv4",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -147,16 +147,16 @@
 			// even though clang does.
 			"-mcpu=cortex-a53",
 			"-mfpu=neon-fp-armv8",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
 			"-D__ARM_FEATURE_LPAE=1",
 		},
 		"kryo385": []string{
-			// Use cortex-a53 because kryo385 is not supported in GCC/clang.
+			// Use cortex-a53 because kryo385 is not supported in clang.
 			"-mcpu=cortex-a53",
-			// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
+			// Fake an ARM compiler flag as these processors support LPAE which clang
 			// don't advertise.
 			// TODO This is a hack and we need to add it for each processor that supports LPAE until some
 			// better solution comes around. See Bug 27340895
@@ -166,17 +166,12 @@
 )
 
 const (
-	name          = "arm"
-	armGccVersion = "4.9"
-	gccTriple     = "arm-linux-androideabi"
-	clangTriple   = "armv7a-linux-androideabi"
+	name        = "arm"
+	ndkTriple   = "arm-linux-androideabi"
+	clangTriple = "armv7a-linux-androideabi"
 )
 
 func init() {
-	pctx.StaticVariable("armGccVersion", armGccVersion)
-
-	pctx.SourcePathVariable("ArmGccRoot", "prebuilts/gcc/${HostPrebuiltTag}/arm/arm-linux-androideabi-${armGccVersion}")
-
 	// Just exported. Not created as a Ninja static variable.
 	exportedVars.ExportString("ArmClangTriple", clangTriple)
 
@@ -255,18 +250,6 @@
 	return name
 }
 
-func (t *toolchainArm) GccRoot() string {
-	return "${config.ArmGccRoot}"
-}
-
-func (t *toolchainArm) GccTriple() string {
-	return gccTriple
-}
-
-func (t *toolchainArm) GccVersion() string {
-	return armGccVersion
-}
-
 func (t *toolchainArm) IncludeFlags() string {
 	return ""
 }
@@ -278,7 +261,7 @@
 
 func (t *toolchainArm) ndkTriple() string {
 	// Use current NDK include path, while ClangTriple is changed.
-	return t.GccTriple()
+	return ndkTriple
 }
 
 func (t *toolchainArm) ToolchainCflags() string {
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 01b1e63..2cabdc8 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -75,10 +75,6 @@
 	)
 )
 
-const (
-	darwinGccVersion = "4.2.1"
-)
-
 func init() {
 	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
 		return getMacTools(ctx).sdkRoot
@@ -100,12 +96,6 @@
 		return getMacTools(ctx).toolPath
 	})
 
-	pctx.StaticVariable("DarwinGccVersion", darwinGccVersion)
-	pctx.SourcePathVariable("DarwinGccRoot",
-		"prebuilts/gcc/${HostPrebuiltTag}/host/i686-apple-darwin-${DarwinGccVersion}")
-
-	pctx.StaticVariable("DarwinGccTriple", "i686-apple-darwin11")
-
 	pctx.StaticVariable("DarwinCflags", strings.Join(darwinCflags, " "))
 	pctx.StaticVariable("DarwinLdflags", strings.Join(darwinLdflags, " "))
 	pctx.StaticVariable("DarwinLldflags", strings.Join(darwinLdflags, " "))
@@ -196,30 +186,6 @@
 	return "x86_64"
 }
 
-func (t *toolchainDarwinArm) GccRoot() string {
-	panic("unimplemented")
-}
-
-func (t *toolchainDarwinArm) GccTriple() string {
-	panic("unimplemented")
-}
-
-func (t *toolchainDarwinArm) GccVersion() string {
-	panic("unimplemented")
-}
-
-func (t *toolchainDarwinX86) GccRoot() string {
-	return "${config.DarwinGccRoot}"
-}
-
-func (t *toolchainDarwinX86) GccTriple() string {
-	return "${config.DarwinGccTriple}"
-}
-
-func (t *toolchainDarwinX86) GccVersion() string {
-	return darwinGccVersion
-}
-
 func (t *toolchainDarwin) IncludeFlags() string {
 	return ""
 }
diff --git a/cc/config/global.go b/cc/config/global.go
index f920471..bf80907 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -244,6 +244,10 @@
 		"-Wno-error=unused-but-set-parameter", // http://b/197240255
 		// New warnings to be fixed after clang-r458507
 		"-Wno-error=unqualified-std-cast-call", // http://b/239662094
+		// New warnings to be fixed after clang-r468909
+		"-Wno-error=array-parameter",     // http://b/241941550
+		"-Wno-error=deprecated-builtins", // http://b/241601211
+		"-Wno-error=deprecated",          // in external/googletest/googletest
 	}
 
 	noOverrideExternalGlobalCflags = []string{
@@ -308,17 +312,14 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r458507"
-	ClangDefaultShortVersion = "15.0.1"
+	ClangDefaultVersion      = "clang-r468909"
+	ClangDefaultShortVersion = "15.0.2"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
 		"device/",
 		"vendor/",
 	}
-
-	// Directories with warnings from Android.mk files.
-	WarningAllowedOldProjects = []string{}
 )
 
 // BazelCcToolchainVars generates bzl file content containing variables for
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
new file mode 100644
index 0000000..d8918f1
--- /dev/null
+++ b/cc/config/riscv64_device.go
@@ -0,0 +1,140 @@
+// 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 config
+
+import (
+	"fmt"
+	"strings"
+
+	"android/soong/android"
+)
+
+var (
+	riscv64Cflags = []string{
+		// Help catch common 32/64-bit errors.
+		"-Werror=implicit-function-declaration",
+	}
+
+	riscv64ArchVariantCflags = map[string][]string{}
+
+	riscv64Ldflags = []string{
+		"-Wl,--hash-style=gnu",
+		"-Wl,-z,separate-code",
+	}
+
+	riscv64Lldflags = append(riscv64Ldflags,
+		"-Wl,-z,max-page-size=4096")
+
+	riscv64Cppflags = []string{}
+
+	riscv64CpuVariantCflags = map[string][]string{}
+)
+
+const ()
+
+func init() {
+
+	exportedVars.ExportStringListStaticVariable("Riscv64Ldflags", riscv64Ldflags)
+	exportedVars.ExportStringListStaticVariable("Riscv64Lldflags", riscv64Lldflags)
+
+	exportedVars.ExportStringListStaticVariable("Riscv64Cflags", riscv64Cflags)
+	exportedVars.ExportStringListStaticVariable("Riscv64Cppflags", riscv64Cppflags)
+
+	exportedVars.ExportVariableReferenceDict("Riscv64ArchVariantCflags", riscv64ArchVariantCflagsVar)
+	exportedVars.ExportVariableReferenceDict("Riscv64CpuVariantCflags", riscv64CpuVariantCflagsVar)
+	exportedVars.ExportVariableReferenceDict("Riscv64CpuVariantLdflags", riscv64CpuVariantLdflags)
+}
+
+var (
+	riscv64ArchVariantCflagsVar = map[string]string{}
+
+	riscv64CpuVariantCflagsVar = map[string]string{}
+
+	riscv64CpuVariantLdflags = map[string]string{}
+)
+
+type toolchainRiscv64 struct {
+	toolchainBionic
+	toolchain64Bit
+
+	ldflags         string
+	lldflags        string
+	toolchainCflags string
+}
+
+func (t *toolchainRiscv64) Name() string {
+	return "riscv64"
+}
+
+func (t *toolchainRiscv64) IncludeFlags() string {
+	return ""
+}
+
+func (t *toolchainRiscv64) ClangTriple() string {
+	return "riscv64-linux-android"
+}
+
+func (t *toolchainRiscv64) Cflags() string {
+	return "${config.Riscv64Cflags}"
+}
+
+func (t *toolchainRiscv64) Cppflags() string {
+	return "${config.Riscv64Cppflags}"
+}
+
+func (t *toolchainRiscv64) Ldflags() string {
+	return t.ldflags
+}
+
+func (t *toolchainRiscv64) Lldflags() string {
+	return t.lldflags
+}
+
+func (t *toolchainRiscv64) ToolchainCflags() string {
+	return t.toolchainCflags
+}
+
+func (toolchainRiscv64) LibclangRuntimeLibraryArch() string {
+	return "riscv64"
+}
+
+func riscv64ToolchainFactory(arch android.Arch) Toolchain {
+	switch arch.ArchVariant {
+	case "":
+	default:
+		panic(fmt.Sprintf("Unknown Riscv64 architecture version: %q", arch.ArchVariant))
+	}
+
+	toolchainCflags := []string{riscv64ArchVariantCflagsVar[arch.ArchVariant]}
+	toolchainCflags = append(toolchainCflags,
+		variantOrDefault(riscv64CpuVariantCflagsVar, arch.CpuVariant))
+
+	extraLdflags := variantOrDefault(riscv64CpuVariantLdflags, arch.CpuVariant)
+	return &toolchainRiscv64{
+		ldflags: strings.Join([]string{
+			"${config.Riscv64Ldflags}",
+			extraLdflags,
+		}, " "),
+		lldflags: strings.Join([]string{
+			"${config.Riscv64Lldflags}",
+			extraLdflags,
+		}, " "),
+		toolchainCflags: strings.Join(toolchainCflags, " "),
+	}
+}
+
+func init() {
+	registerToolchainFactory(android.Android, android.Riscv64, riscv64ToolchainFactory)
+}
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index d9eaf53..eb71aa1 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -63,11 +63,6 @@
 type Toolchain interface {
 	Name() string
 
-	GccRoot() string
-	GccTriple() string
-	// GccVersion should return a real value, not a ninja reference
-	GccVersion() string
-
 	IncludeFlags() string
 
 	ClangTriple() string
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index aebda0b..e2b0f06 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -80,17 +80,7 @@
 	}
 )
 
-const (
-	x86_64GccVersion = "4.9"
-)
-
 func init() {
-
-	pctx.StaticVariable("x86_64GccVersion", x86_64GccVersion)
-
-	pctx.SourcePathVariable("X86_64GccRoot",
-		"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86_64GccVersion}")
-
 	exportedVars.ExportStringListStaticVariable("X86_64ToolchainCflags", []string{"-m64"})
 	exportedVars.ExportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"})
 
@@ -128,24 +118,12 @@
 	return "x86_64"
 }
 
-func (t *toolchainX86_64) GccRoot() string {
-	return "${config.X86_64GccRoot}"
-}
-
-func (t *toolchainX86_64) GccTriple() string {
-	return "x86_64-linux-android"
-}
-
-func (t *toolchainX86_64) GccVersion() string {
-	return x86_64GccVersion
-}
-
 func (t *toolchainX86_64) IncludeFlags() string {
 	return ""
 }
 
 func (t *toolchainX86_64) ClangTriple() string {
-	return t.GccTriple()
+	return "x86_64-linux-android"
 }
 
 func (t *toolchainX86_64) ToolchainLdflags() string {
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 421b083..3001ab4 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -88,16 +88,7 @@
 	}
 )
 
-const (
-	x86GccVersion = "4.9"
-)
-
 func init() {
-	pctx.StaticVariable("x86GccVersion", x86GccVersion)
-
-	pctx.SourcePathVariable("X86GccRoot",
-		"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86GccVersion}")
-
 	exportedVars.ExportStringListStaticVariable("X86ToolchainCflags", []string{"-m32"})
 	exportedVars.ExportStringListStaticVariable("X86ToolchainLdflags", []string{"-m32"})
 
@@ -134,18 +125,6 @@
 	return "x86"
 }
 
-func (t *toolchainX86) GccRoot() string {
-	return "${config.X86GccRoot}"
-}
-
-func (t *toolchainX86) GccTriple() string {
-	return "x86_64-linux-android"
-}
-
-func (t *toolchainX86) GccVersion() string {
-	return x86GccVersion
-}
-
 func (t *toolchainX86) IncludeFlags() string {
 	return ""
 }
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index 976cc25..96a53bf 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -66,13 +66,20 @@
 		"host_bionic_linker_script")
 )
 
+const (
+	x86_64GccVersion = "4.9"
+)
+
 func init() {
+
 	pctx.StaticVariable("LinuxBionicCflags", strings.Join(linuxBionicCflags, " "))
 	pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " "))
 	pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLdflags, " "))
 
 	// Use the device gcc toolchain for now
-	pctx.StaticVariable("LinuxBionicGccRoot", "${X86_64GccRoot}")
+	pctx.StaticVariable("LinuxBionicGccVersion", x86_64GccVersion)
+	pctx.SourcePathVariable("LinuxBionicGccRoot",
+		"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${LinuxBionicGccVersion}")
 }
 
 type toolchainLinuxBionic struct {
@@ -84,18 +91,6 @@
 	return "x86_64"
 }
 
-func (t *toolchainLinuxBionic) GccRoot() string {
-	return "${config.LinuxBionicGccRoot}"
-}
-
-func (t *toolchainLinuxBionic) GccTriple() string {
-	return "x86_64-linux-android"
-}
-
-func (t *toolchainLinuxBionic) GccVersion() string {
-	return "4.9"
-}
-
 func (t *toolchainLinuxBionic) IncludeFlags() string {
 	return ""
 }
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 1b126de..740405e 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -109,7 +109,7 @@
 	}, "-l")
 
 	muslCrtBeginStaticBinary, muslCrtEndStaticBinary   = []string{"libc_musl_crtbegin_static"}, []string{"libc_musl_crtend"}
-	muslCrtBeginSharedBinary, muslCrtEndSharedBinary   = []string{"libc_musl_crtbegin_dynamic", "musl_linker_script"}, []string{"libc_musl_crtend"}
+	muslCrtBeginSharedBinary, muslCrtEndSharedBinary   = []string{"libc_musl_crtbegin_dynamic"}, []string{"libc_musl_crtend"}
 	muslCrtBeginSharedLibrary, muslCrtEndSharedLibrary = []string{"libc_musl_crtbegin_so"}, []string{"libc_musl_crtend_so"}
 
 	muslDefaultSharedLibraries = []string{"libc_musl"}
@@ -180,18 +180,6 @@
 	return "x86_64"
 }
 
-func (t *toolchainLinux) GccRoot() string {
-	return "${config.LinuxGccRoot}"
-}
-
-func (t *toolchainLinux) GccTriple() string {
-	return "${config.LinuxGccTriple}"
-}
-
-func (t *toolchainLinux) GccVersion() string {
-	return linuxGccVersion
-}
-
 func (t *toolchainLinux) IncludeFlags() string {
 	return ""
 }
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index a33606f..561c500 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -175,24 +175,12 @@
 	return "x86_64"
 }
 
-func (t *toolchainWindows) GccRoot() string {
-	return "${config.WindowsGccRoot}"
-}
-
-func (t *toolchainWindows) GccTriple() string {
-	return "${config.WindowsGccTriple}"
-}
-
 func (t *toolchainWindows) ToolchainCflags() string {
-	return "-B" + filepath.Join(t.GccRoot(), t.GccTriple(), "bin")
+	return "-B" + filepath.Join("${config.WindowsGccRoot}", "${config.WindowsGccTriple}", "bin")
 }
 
 func (t *toolchainWindows) ToolchainLdflags() string {
-	return "-B" + filepath.Join(t.GccRoot(), t.GccTriple(), "bin")
-}
-
-func (t *toolchainWindows) GccVersion() string {
-	return windowsGccVersion
+	return "-B" + filepath.Join("${config.WindowsGccRoot}", "${config.WindowsGccTriple}", "bin")
 }
 
 func (t *toolchainWindows) IncludeFlags() string {
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 8804bbb..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 {
@@ -339,14 +340,15 @@
 		Copts:   *compilerAttrs.copts.Clone().Append(sharedAttrs.Copts),
 		Hdrs:    *compilerAttrs.hdrs.Clone().Append(sharedAttrs.Hdrs),
 
-		Deps:                        *linkerAttrs.deps.Clone().Append(sharedAttrs.Deps),
-		Implementation_deps:         *linkerAttrs.implementationDeps.Clone().Append(sharedAttrs.Implementation_deps),
-		Dynamic_deps:                *linkerAttrs.dynamicDeps.Clone().Append(sharedAttrs.Dynamic_deps),
-		Implementation_dynamic_deps: *linkerAttrs.implementationDynamicDeps.Clone().Append(sharedAttrs.Implementation_dynamic_deps),
-		Whole_archive_deps:          *linkerAttrs.wholeArchiveDeps.Clone().Append(sharedAttrs.Whole_archive_deps),
-		System_dynamic_deps:         *linkerAttrs.systemDynamicDeps.Clone().Append(sharedAttrs.System_dynamic_deps),
-		Runtime_deps:                linkerAttrs.runtimeDeps,
-		sdkAttributes:               bp2BuildParseSdkAttributes(m),
+		Deps:                              *linkerAttrs.deps.Clone().Append(sharedAttrs.Deps),
+		Implementation_deps:               *linkerAttrs.implementationDeps.Clone().Append(sharedAttrs.Implementation_deps),
+		Dynamic_deps:                      *linkerAttrs.dynamicDeps.Clone().Append(sharedAttrs.Dynamic_deps),
+		Implementation_dynamic_deps:       *linkerAttrs.implementationDynamicDeps.Clone().Append(sharedAttrs.Implementation_dynamic_deps),
+		Whole_archive_deps:                *linkerAttrs.wholeArchiveDeps.Clone().Append(sharedAttrs.Whole_archive_deps),
+		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
+		System_dynamic_deps:               *linkerAttrs.systemDynamicDeps.Clone().Append(sharedAttrs.System_dynamic_deps),
+		Runtime_deps:                      linkerAttrs.runtimeDeps,
+		sdkAttributes:                     bp2BuildParseSdkAttributes(m),
 	}
 
 	staticTargetAttrs := &bazelCcLibraryStaticAttributes{
@@ -366,7 +368,6 @@
 		Stl:                      compilerAttrs.stl,
 		Cpp_std:                  compilerAttrs.cppStd,
 		C_std:                    compilerAttrs.cStd,
-		Use_version_lib:          linkerAttrs.useVersionLib,
 
 		Features: baseAttributes.features,
 	}
@@ -441,6 +442,10 @@
 		android.CommonAttributes{Name: m.Name()},
 		sharedTargetAttrs, sharedAttrs.Enabled)
 
+	createStubsBazelTargetIfNeeded(ctx, m, compilerAttrs, exportedIncludes, baseAttributes)
+}
+
+func createStubsBazelTargetIfNeeded(ctx android.TopDownMutatorContext, m *Module, compilerAttrs compilerAttributes, exportedIncludes BazelIncludes, baseAttributes baseAttributes) {
 	if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
 		stubSuitesProps := bazel.BazelTargetModuleProperties{
 			Rule_class:        "cc_stub_suite",
@@ -2630,8 +2635,7 @@
 		attrs = &bazelCcLibraryStaticAttributes{
 			staticOrSharedAttributes: commonAttrs,
 
-			Use_libcrt:      linkerAttrs.useLibcrt,
-			Use_version_lib: linkerAttrs.useVersionLib,
+			Use_libcrt: linkerAttrs.useLibcrt,
 
 			Rtti:    compilerAttrs.rtti,
 			Stl:     compilerAttrs.stl,
@@ -2701,6 +2705,7 @@
 		modType = "cc_library_static"
 	} else {
 		modType = "cc_library_shared"
+		createStubsBazelTargetIfNeeded(ctx, module, compilerAttrs, exportedIncludes, baseAttributes)
 	}
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class:        modType,
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/lto_test.go b/cc/lto_test.go
new file mode 100644
index 0000000..b52f2b6
--- /dev/null
+++ b/cc/lto_test.go
@@ -0,0 +1,90 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint"
+)
+
+func TestThinLtoDeps(t *testing.T) {
+	bp := `
+	cc_library {
+		name: "lto_enabled",
+		srcs: ["src.c"],
+		static_libs: ["foo"],
+		shared_libs: ["bar"],
+		lto: {
+			thin: true,
+		}
+	}
+	cc_library {
+		name: "foo",
+		static_libs: ["baz"],
+	}
+	cc_library {
+		name: "bar",
+		static_libs: ["qux"],
+	}
+	cc_library {
+		name: "baz",
+	}
+	cc_library {
+		name: "qux",
+	}
+`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module()
+	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module()
+	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module()
+
+	hasDep := func(m android.Module, wantDep android.Module) bool {
+		var found bool
+		result.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	if !hasDep(libLto, libFoo) {
+		t.Errorf("'lto_enabled' missing dependency on thin lto variant of 'foo'")
+	}
+
+	if !hasDep(libFoo, libBaz) {
+		t.Errorf("'lto_enabled' missing dependency on thin lto variant of transitive dep 'baz'")
+	}
+
+	barVariants := result.ModuleVariantsForTests("bar")
+	for _, v := range barVariants {
+		if strings.Contains(v, "lto-thin") {
+			t.Errorf("Expected variants for 'bar' to not contain 'lto-thin', but found %q", v)
+		}
+	}
+	quxVariants := result.ModuleVariantsForTests("qux")
+	for _, v := range quxVariants {
+		if strings.Contains(v, "lto-thin") {
+			t.Errorf("Expected variants for 'qux' to not contain 'lto-thin', but found %q", v)
+		}
+	}
+}
diff --git a/cc/makevars.go b/cc/makevars.go
index 8154436..c70d4a6 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -53,7 +53,6 @@
 
 func makeStringOfWarningAllowedProjects() string {
 	allProjects := append([]string{}, config.WarningAllowedProjects...)
-	allProjects = append(allProjects, config.WarningAllowedOldProjects...)
 	sort.Strings(allProjects)
 	// Makefile rules use pattern "path/%" to match module paths.
 	if len(allProjects) > 0 {
@@ -315,8 +314,6 @@
 		ctx.Strict(makePrefix+"LD", "${config.ClangBin}/lld")
 		ctx.Strict(makePrefix+"NDK_TRIPLE", config.NDKTriple(toolchain))
 		ctx.Strict(makePrefix+"TOOLS_PREFIX", "${config.ClangBin}/llvm-")
-		// TODO: GCC version is obsolete now that GCC has been removed.
-		ctx.Strict(makePrefix+"GCC_VERSION", toolchain.GccVersion())
 	}
 
 	if target.Os.Class == android.Host {
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/object.go b/cc/object.go
index 65a11e0..1a96b72 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"strings"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -254,22 +255,31 @@
 
 	var outputFile android.Path
 	builderFlags := flagsToBuilderFlags(flags)
+	outputName := ctx.ModuleName()
+	if !strings.HasSuffix(outputName, objectExtension) {
+		outputName += objectExtension
+	}
 
 	if len(objs.objFiles) == 1 && String(object.Properties.Linker_script) == "" {
-		outputFile = objs.objFiles[0]
-
-		if String(object.Properties.Prefix_symbols) != "" {
-			output := android.PathForModuleOut(ctx, ctx.ModuleName()+objectExtension)
-			transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), outputFile,
-				builderFlags, output)
-			outputFile = output
-		}
-	} else {
-		output := android.PathForModuleOut(ctx, ctx.ModuleName()+objectExtension)
+		output := android.PathForModuleOut(ctx, outputName)
 		outputFile = output
 
 		if String(object.Properties.Prefix_symbols) != "" {
-			input := android.PathForModuleOut(ctx, "unprefixed", ctx.ModuleName()+objectExtension)
+			transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), objs.objFiles[0],
+				builderFlags, output)
+		} else {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   android.Cp,
+				Input:  objs.objFiles[0],
+				Output: output,
+			})
+		}
+	} else {
+		output := android.PathForModuleOut(ctx, outputName)
+		outputFile = output
+
+		if String(object.Properties.Prefix_symbols) != "" {
+			input := android.PathForModuleOut(ctx, "unprefixed", outputName)
 			transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), input,
 				builderFlags, output)
 			output = input
diff --git a/cc/object_test.go b/cc/object_test.go
index 259a892..5359a35 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"fmt"
 	"testing"
 
 	"android/soong/android"
@@ -107,3 +108,65 @@
 	expectedOutputFiles := []string{"outputbase/execroot/__main__/bazel_out.o"}
 	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
 }
+
+func TestCcObjectOutputFile(t *testing.T) {
+	testcases := []struct {
+		name       string
+		moduleName string
+		bp         string
+	}{
+		{
+			name:       "normal",
+			moduleName: "foo",
+			bp: `
+				srcs: ["bar.c"],
+			`,
+		},
+		{
+			name:       "suffix",
+			moduleName: "foo.o",
+			bp: `
+				srcs: ["bar.c"],
+			`,
+		},
+		{
+			name:       "keep symbols",
+			moduleName: "foo",
+			bp: `
+				srcs: ["bar.c"],
+				prefix_symbols: "foo_",
+			`,
+		},
+		{
+			name:       "partial linking",
+			moduleName: "foo",
+			bp: `
+				srcs: ["bar.c", "baz.c"],
+			`,
+		},
+		{
+			name:       "partial linking and prefix symbols",
+			moduleName: "foo",
+			bp: `
+				srcs: ["bar.c", "baz.c"],
+				prefix_symbols: "foo_",
+			`,
+		},
+	}
+
+	for _, testcase := range testcases {
+		bp := fmt.Sprintf(`
+			cc_object {
+				name: "%s",
+				%s
+			}
+		`, testcase.moduleName, testcase.bp)
+		t.Run(testcase.name, func(t *testing.T) {
+			ctx := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp)
+			android.AssertPathRelativeToTopEquals(t, "expected output file foo.o",
+				fmt.Sprintf("out/soong/.intermediates/%s/android_arm64_armv8-a/foo.o", testcase.moduleName),
+				ctx.ModuleForTests(testcase.moduleName, "android_arm64_armv8-a").Output("foo.o").Output)
+		})
+	}
+
+}
diff --git a/cc/proto.go b/cc/proto.go
index 8e6d5ed..cf5ed04 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -178,7 +178,7 @@
 	var ret bp2buildProtoDeps
 
 	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
-	if !ok {
+	if !ok || protoInfo.Proto_libs.IsEmpty() {
 		return ret
 	}
 
@@ -201,9 +201,8 @@
 	dep := android.BazelLabelForModuleDepSingle(ctx, depName)
 	ret.protoDep = &bazel.LabelAttribute{Value: &dep}
 
-	protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
 	var protoAttrs protoAttributes
-	protoAttrs.Deps.SetValue(bazel.LabelList{Includes: []bazel.Label{protoLabel}})
+	protoAttrs.Deps.SetValue(protoInfo.Proto_libs)
 
 	name := m.Name() + suffix
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 436b149..0b47f0e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -881,8 +881,12 @@
 	switch t {
 	case Asan:
 		sanitize.Properties.Sanitize.Address = bPtr
+		// For ASAN variant, we need to disable Memtag_stack
+		sanitize.Properties.Sanitize.Memtag_stack = nil
 	case Hwasan:
 		sanitize.Properties.Sanitize.Hwaddress = bPtr
+		// For HWAsan variant, we need to disable Memtag_stack
+		sanitize.Properties.Sanitize.Memtag_stack = nil
 	case tsan:
 		sanitize.Properties.Sanitize.Thread = bPtr
 	case intOverflow:
@@ -895,6 +899,7 @@
 		sanitize.Properties.Sanitize.Memtag_heap = bPtr
 	case Memtag_stack:
 		sanitize.Properties.Sanitize.Memtag_stack = bPtr
+		// We do not need to disable ASAN or HWASan here, as there is no Memtag_stack variant.
 	case Fuzzer:
 		sanitize.Properties.Sanitize.Fuzzer = bPtr
 	default:
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/cc/test.go b/cc/test.go
index 28a0e5e..715c537 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -659,6 +659,7 @@
 	testBinaryAttrs.binaryAttributes = binaryBp2buildAttrs(ctx, m)
 
 	var data bazel.LabelListAttribute
+	var tags bazel.StringListAttribute
 
 	testBinaryProps := m.GetArchVariantProperties(ctx, &TestBinaryProperties{})
 	for axis, configToProps := range testBinaryProps {
@@ -670,6 +671,7 @@
 				combinedData.Append(android.BazelLabelForModuleDeps(ctx, p.Data_bins))
 				combinedData.Append(android.BazelLabelForModuleDeps(ctx, p.Data_libs))
 				data.SetSelectValue(axis, config, combinedData)
+				tags.SetSelectValue(axis, config, p.Test_options.Tags)
 			}
 		}
 	}
@@ -690,6 +692,7 @@
 		android.CommonAttributes{
 			Name: m.Name(),
 			Data: data,
+			Tags: tags,
 		},
 		&testBinaryAttrs)
 }
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 1cf64de..c420567 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -29,6 +29,7 @@
 
 	"google.golang.org/protobuf/proto"
 
+	"android/soong/cmd/extract_apks/bundle_proto"
 	android_bundle_proto "android/soong/cmd/extract_apks/bundle_proto"
 	"android/soong/third_party/zip"
 )
@@ -75,7 +76,7 @@
 		return nil, err
 	}
 	bytes := make([]byte, tocFile.FileHeader.UncompressedSize64)
-	if _, err := rc.Read(bytes); err != io.EOF {
+	if _, err := rc.Read(bytes); err != nil && err != io.EOF {
 		return nil, err
 	}
 	rc.Close()
@@ -197,6 +198,49 @@
 	*android_bundle_proto.MultiAbiTargeting
 }
 
+type multiAbiValue []*bundle_proto.Abi
+
+func (m multiAbiValue) compare(other multiAbiValue) int {
+	min := func(a, b int) int {
+		if a < b {
+			return a
+		}
+		return b
+	}
+
+	sortAbis := func(abiSlice multiAbiValue) func(i, j int) bool {
+		return func(i, j int) bool {
+			// sort priorities greatest to least
+			return multiAbiPriorities[abiSlice[i].Alias] > multiAbiPriorities[abiSlice[j].Alias]
+		}
+	}
+
+	m = append(multiAbiValue{}, m...)
+	sort.Slice(m, sortAbis(m))
+	other = append(multiAbiValue{}, other...)
+	sort.Slice(other, sortAbis(other))
+
+	for i := 0; i < min(len(m), len(other)); i++ {
+		if multiAbiPriorities[m[i].Alias] > multiAbiPriorities[other[i].Alias] {
+			return 1
+		}
+		if multiAbiPriorities[m[i].Alias] < multiAbiPriorities[other[i].Alias] {
+			return -1
+		}
+	}
+
+	if len(m) == len(other) {
+		return 0
+	}
+	if len(m) > len(other) {
+		return 1
+	}
+	return -1
+}
+
+// this logic should match the logic in bundletool at
+// https://github.com/google/bundletool/blob/ae0fc0162fd80d92ef8f4ef4527c066f0106942f/src/main/java/com/android/tools/build/bundletool/device/MultiAbiMatcher.java#L43
+// (note link is the commit at time of writing; but logic should always match the latest)
 func (t multiAbiTargetingMatcher) matches(config TargetConfig) bool {
 	if t.MultiAbiTargeting == nil {
 		return true
@@ -204,31 +248,45 @@
 	if _, ok := config.abis[android_bundle_proto.Abi_UNSPECIFIED_CPU_ARCHITECTURE]; ok {
 		return true
 	}
-	// Find the one with the highest priority.
-	highestPriority := 0
-	for _, v := range t.GetValue() {
-		for _, a := range v.GetAbi() {
-			if _, ok := config.abis[a.Alias]; ok {
-				if highestPriority < multiAbiPriorities[a.Alias] {
-					highestPriority = multiAbiPriorities[a.Alias]
-				}
+
+	multiAbiIsValid := func(m multiAbiValue) bool {
+		for _, abi := range m {
+			if _, ok := config.abis[abi.Alias]; !ok {
+				return false
 			}
 		}
+		return true
 	}
-	if highestPriority == 0 {
+
+	// ensure that the current value is valid for our config
+	valueSetContainsViableAbi := false
+	multiAbiSet := t.GetValue()
+	for _, multiAbi := range multiAbiSet {
+		if multiAbiIsValid(multiAbi.GetAbi()) {
+			valueSetContainsViableAbi = true
+		}
+	}
+
+	if !valueSetContainsViableAbi {
 		return false
 	}
+
 	// See if there are any matching alternatives with a higher priority.
-	for _, v := range t.GetAlternatives() {
-		for _, a := range v.GetAbi() {
-			if _, ok := config.abis[a.Alias]; ok {
-				if highestPriority < multiAbiPriorities[a.Alias] {
-					// There's a better one. Skip this one.
-					return false
-				}
+	for _, altMultiAbi := range t.GetAlternatives() {
+		if !multiAbiIsValid(altMultiAbi.GetAbi()) {
+			continue
+		}
+
+		for _, multiAbi := range multiAbiSet {
+			valueAbis := multiAbiValue(multiAbi.GetAbi())
+			altAbis := multiAbiValue(altMultiAbi.GetAbi())
+			if valueAbis.compare(altAbis) < 0 {
+				// An alternative has a higher priority, don't use this one
+				return false
 			}
 		}
 	}
+
 	return true
 }
 
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index f5e4046..c1d712d 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -420,6 +420,370 @@
 	}
 }
 
+func TestSelectApks_ApexSet_Variants(t *testing.T) {
+	testCases := []testDesc{
+		{
+			protoText: `
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: X86}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: X86}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-armeabi_v7a.apex"
+		}
+	}
+	variant_number: 0
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: X86}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: X86}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-arm64_v8a.apex"
+		}
+	}
+	variant_number: 1
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: X86}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: X86}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-armeabi_v7a.arm64_v8a.apex"
+		}
+	}
+	variant_number: 2
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {abi {alias: X86}}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {abi {alias: X86}}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-x86.apex"
+		}
+	}
+	variant_number: 3
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: X86}}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: X86}}
+				}
+			}
+			path: "standalones/standalone-x86.x86_64.apex"
+		}
+  }
+  variant_number: 4
+}
+`,
+			configs: []testConfigDesc{
+				{
+					name: "multi-variant multi-target ARM",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARM64_V8A:   0,
+							bp.Abi_ARMEABI_V7A: 1,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-armeabi_v7a.arm64_v8a.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target arm",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARMEABI_V7A: 0,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-armeabi_v7a.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target arm64",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARM64_V8A: 0,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-arm64_v8a.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant multi-target x86",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_X86:    0,
+							bp.Abi_X86_64: 1,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-x86.x86_64.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target x86",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_X86: 0,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-x86.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target x86_64",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_X86_64: 0,
+						},
+					},
+					expected: SelectionResult{},
+				},
+				{
+					name: "multi-variant multi-target cross-target",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARM64_V8A: 0,
+							bp.Abi_X86_64:    1,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-arm64_v8a.apex",
+						},
+					},
+				},
+			},
+		},
+	}
+	for _, testCase := range testCases {
+		var toc bp.BuildApksResult
+		if err := prototext.Unmarshal([]byte(testCase.protoText), &toc); err != nil {
+			t.Fatal(err)
+		}
+		for _, config := range testCase.configs {
+			t.Run(config.name, func(t *testing.T) {
+				actual := selectApks(&toc, config.targetConfig)
+				if !reflect.DeepEqual(config.expected, actual) {
+					t.Errorf("expected %v, got %v", config.expected, actual)
+				}
+			})
+		}
+	}
+}
+
 type testZip2ZipWriter struct {
 	entries map[string]string
 }
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index d4a57bf..0e8ad05 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -150,6 +150,7 @@
 var defaultMinSdkVersion string
 var useVersion string
 var staticDeps bool
+var writeCmd bool
 var jetifier bool
 
 func InList(s string, list []string) bool {
@@ -810,6 +811,9 @@
   -use-version <version>
      If the maven directory contains multiple versions of artifacts and their pom files,
      -use-version can be used to only write Android.bp files for a specific version of those artifacts.
+  -write-cmd
+     Whether to write the command line arguments used to generate the build file as a comment at
+     the top of the build file itself.
   -jetifier
      Sets jetifier: true for all modules.
   <dir>
@@ -837,6 +841,7 @@
 	flag.StringVar(&defaultMinSdkVersion, "default-min-sdk-version", "24", "Default min_sdk_version to use, if one is not available from AndroidManifest.xml. Default: 24")
 	flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
 	flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
+	flag.BoolVar(&writeCmd, "write-cmd", true, "Write command line arguments as a comment")
 	flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
 	flag.StringVar(&regen, "regen", "", "Rewrite specified file")
 	flag.BoolVar(&pom2build, "pom2build", false, "If true, will generate a Bazel BUILD file *instead* of a .bp file")
@@ -964,8 +969,13 @@
 	if pom2build {
 		commentString = "#"
 	}
-	fmt.Fprintln(buf, commentString, "Automatically generated with:")
-	fmt.Fprintln(buf, commentString, "pom2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
+
+	fmt.Fprintln(buf, commentString, "This is a generated file. Do not modify directly.")
+
+	if writeCmd {
+		fmt.Fprintln(buf, commentString, "Automatically generated with:")
+		fmt.Fprintln(buf, commentString, "pom2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
+	}
 
 	if prepend != "" {
 		contents, err := ioutil.ReadFile(prepend)
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/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index d8011d6..fdfd22e 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -201,6 +201,11 @@
 	if apex := global.AllApexSystemServerJars(ctx).ApexOfJar(lib); apex != "" {
 		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apex, lib)
 	}
+
+	if apex := global.AllPlatformSystemServerJars(ctx).ApexOfJar(lib); apex == "system_ext" {
+		return fmt.Sprintf("/system_ext/framework/%s.jar", lib)
+	}
+
 	return fmt.Sprintf("/system/framework/%s.jar", lib)
 }
 
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 07e4fad..429b5ff 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -59,6 +59,15 @@
 		android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
 }
 
+func testSystemExtSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
+	return createTestModuleConfig(
+		name,
+		fmt.Sprintf("/system_ext/framework/%s.jar", name),
+		android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)),
+		android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)),
+		android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
+}
+
 func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforceUsesLibrariesStatusFile android.OutputPath) *ModuleConfig {
 	return &ModuleConfig{
 		Name:                            name,
@@ -213,6 +222,29 @@
 	android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
 }
 
+func TestDexPreoptSystemExtSystemServerJars(t *testing.T) {
+	config := android.TestConfig("out", nil, "", nil)
+	ctx := android.BuilderContextForTesting(config)
+	globalSoong := globalSoongConfigForTests()
+	global := GlobalConfigForTests(ctx)
+	module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
+
+	global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
+		[]string{"system_ext:service-A"})
+
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	wantInstalls := android.RuleBuilderInstalls{
+		{android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system_ext/framework/oat/arm/service-A.odex"},
+		{android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system_ext/framework/oat/arm/service-A.vdex"},
+	}
+
+	android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
+}
+
 func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
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/aar.go b/java/aar.go
index d5996ba..6261f29 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -270,7 +270,7 @@
 
 func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext,
 	classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string,
-	extraLinkFlags ...string) {
+	enforceDefaultTargetSdkVersion bool, extraLinkFlags ...string) {
 
 	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags :=
 		aaptLibs(ctx, sdkContext, classLoaderContexts)
@@ -283,15 +283,16 @@
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
 	manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
-		SdkContext:             sdkContext,
-		ClassLoaderContexts:    classLoaderContexts,
-		IsLibrary:              a.isLibrary,
-		DefaultManifestVersion: a.defaultManifestVersion,
-		UseEmbeddedNativeLibs:  a.useEmbeddedNativeLibs,
-		UsesNonSdkApis:         a.usesNonSdkApis,
-		UseEmbeddedDex:         a.useEmbeddedDex,
-		HasNoCode:              a.hasNoCode,
-		LoggingParent:          a.LoggingParent,
+		SdkContext:                     sdkContext,
+		ClassLoaderContexts:            classLoaderContexts,
+		IsLibrary:                      a.isLibrary,
+		DefaultManifestVersion:         a.defaultManifestVersion,
+		UseEmbeddedNativeLibs:          a.useEmbeddedNativeLibs,
+		UsesNonSdkApis:                 a.usesNonSdkApis,
+		UseEmbeddedDex:                 a.useEmbeddedDex,
+		HasNoCode:                      a.hasNoCode,
+		LoggingParent:                  a.LoggingParent,
+		EnforceDefaultTargetSdkVersion: enforceDefaultTargetSdkVersion,
 	})
 
 	// Add additional manifest files to transitive manifests.
@@ -439,7 +440,7 @@
 		switch depTag {
 		case instrumentationForTag:
 			// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
-		case libTag:
+		case sdkLibTag, libTag:
 			if exportPackage != nil {
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
@@ -535,7 +536,7 @@
 func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.aapt.isLibrary = true
 	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
-	a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil)
+	a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil, false)
 
 	a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
 
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 522b664..c785310 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -43,13 +43,12 @@
 // targetSdkVersion for manifest_fixer
 // When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK
 // This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK
-func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string {
-	targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx)
-	// Return 10000 for modules targeting "current" if either
-	// 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty)
-	// 2. The module is run as part of MTS, and should be testable on stable branches
+func targetSdkVersionForManifestFixer(ctx android.ModuleContext, params ManifestFixerParams) string {
+	targetSdkVersionSpec := params.SdkContext.TargetSdkVersion(ctx)
+
+	// Check if we want to return 10000
 	// TODO(b/240294501): Determine the rules for handling test apexes
-	if targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) {
+	if shouldReturnFinalOrFutureInt(ctx, targetSdkVersionSpec, params.EnforceDefaultTargetSdkVersion) {
 		return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
 	}
 	targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx)
@@ -59,6 +58,17 @@
 	return targetSdkVersion
 }
 
+// Return true for modules targeting "current" if either
+// 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty)
+// 2. The module is run as part of MTS, and should be testable on stable branches
+// Do not return 10000 if we are enforcing default targetSdkVersion and sdk has been finalised
+func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionSpec android.SdkSpec, enforceDefaultTargetSdkVersion bool) bool {
+	if enforceDefaultTargetSdkVersion && ctx.Config().PlatformSdkFinal() {
+		return false
+	}
+	return targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module()))
+}
+
 // Helper function that casts android.Module to java.androidTestApp
 // If this type conversion is possible, it queries whether the test app is included in an MTS suite
 func includedInMts(module android.Module) bool {
@@ -69,16 +79,17 @@
 }
 
 type ManifestFixerParams struct {
-	SdkContext             android.SdkContext
-	ClassLoaderContexts    dexpreopt.ClassLoaderContextMap
-	IsLibrary              bool
-	DefaultManifestVersion string
-	UseEmbeddedNativeLibs  bool
-	UsesNonSdkApis         bool
-	UseEmbeddedDex         bool
-	HasNoCode              bool
-	TestOnly               bool
-	LoggingParent          string
+	SdkContext                     android.SdkContext
+	ClassLoaderContexts            dexpreopt.ClassLoaderContextMap
+	IsLibrary                      bool
+	DefaultManifestVersion         string
+	UseEmbeddedNativeLibs          bool
+	UsesNonSdkApis                 bool
+	UseEmbeddedDex                 bool
+	HasNoCode                      bool
+	TestOnly                       bool
+	LoggingParent                  string
+	EnforceDefaultTargetSdkVersion bool
 }
 
 // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
@@ -137,7 +148,7 @@
 	var argsMapper = make(map[string]string)
 
 	if params.SdkContext != nil {
-		targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params.SdkContext)
+		targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params)
 		args = append(args, "--targetSdkVersion ", targetSdkVersion)
 
 		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
diff --git a/java/app.go b/java/app.go
index bccd37f..a428165 100755
--- a/java/app.go
+++ b/java/app.go
@@ -101,6 +101,15 @@
 	PreventInstall    bool `blueprint:"mutated"`
 	IsCoverageVariant bool `blueprint:"mutated"`
 
+	// It can be set to test the behaviour of default target sdk version.
+	// Only required when updatable: false. It is an error if updatable: true and this is false.
+	Enforce_default_target_sdk_version *bool
+
+	// If set, the targetSdkVersion for the target is set to the latest default API level.
+	// This would be by default false, unless updatable: true or
+	// enforce_default_target_sdk_version: true in which case this defaults to true.
+	EnforceDefaultTargetSdkVersion bool `blueprint:"mutated"`
+
 	// Whether this app is considered mainline updatable or not. When set to true, this will enforce
 	// additional rules to make sure an app can safely be updated. Default is false.
 	// Prefer using other specific properties if build behaviour must be changed; avoid using this
@@ -296,6 +305,18 @@
 		} else {
 			ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
 		}
+
+		if !BoolDefault(a.appProperties.Enforce_default_target_sdk_version, true) {
+			ctx.PropertyErrorf("enforce_default_target_sdk_version", "Updatable apps must enforce default target sdk version")
+		}
+		// TODO(b/227460469) after all the modules removes the target sdk version, throw an error if the target sdk version is explicitly set.
+		if a.deviceProperties.Target_sdk_version == nil {
+			a.SetEnforceDefaultTargetSdkVersion(true)
+		}
+	}
+
+	if Bool(a.appProperties.Enforce_default_target_sdk_version) {
+		a.SetEnforceDefaultTargetSdkVersion(true)
 	}
 
 	a.checkPlatformAPI(ctx)
@@ -427,7 +448,7 @@
 		a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion
 	}
 	a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts,
-		a.usesLibraryProperties.Exclude_uses_libs, aaptLinkFlags...)
+		a.usesLibraryProperties.Exclude_uses_libs, a.enforceDefaultTargetSdkVersion(), aaptLinkFlags...)
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -526,7 +547,8 @@
 
 // Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
 // isn't a cert module reference. Also checks and enforces system cert restriction if applicable.
-func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate {
+func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate,
+	ctx android.ModuleContext) (mainCertificate Certificate, allCertificates []Certificate) {
 	if android.SrcIsModule(certPropValue) == "" {
 		var mainCert Certificate
 		if certPropValue != "" {
@@ -558,7 +580,22 @@
 		}
 	}
 
-	return certificates
+	if len(certificates) > 0 {
+		mainCertificate = certificates[0]
+	} else {
+		// This can be reached with an empty certificate list if AllowMissingDependencies is set
+		// and the certificate property for this module is a module reference to a missing module.
+		if !ctx.Config().AllowMissingDependencies() && len(ctx.GetMissingDependencies()) > 0 {
+			panic("Should only get here if AllowMissingDependencies set and there are missing dependencies")
+		}
+		// Set a certificate to avoid panics later when accessing it.
+		mainCertificate = Certificate{
+			Key: android.PathForModuleOut(ctx, "missing.pk8"),
+			Pem: android.PathForModuleOut(ctx, "missing.pem"),
+		}
+	}
+
+	return mainCertificate, certificates
 }
 
 func (a *AndroidApp) InstallApkName() string {
@@ -632,29 +669,14 @@
 
 	dexJarFile := a.dexBuildActions(ctx)
 
-	jniLibs, prebuiltJniPackages, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
+	jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
 	jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx)
 
 	if ctx.Failed() {
 		return
 	}
 
-	certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx)
-
-	// This can be reached with an empty certificate list if AllowMissingDependencies is set
-	// and the certificate property for this module is a module reference to a missing module.
-	if len(certificates) > 0 {
-		a.certificate = certificates[0]
-	} else {
-		if !ctx.Config().AllowMissingDependencies() && len(ctx.GetMissingDependencies()) > 0 {
-			panic("Should only get here if AllowMissingDependencies set and there are missing dependencies")
-		}
-		// Set a certificate to avoid panics later when accessing it.
-		a.certificate = Certificate{
-			Key: android.PathForModuleOut(ctx, "missing.pk8"),
-			Pem: android.PathForModuleOut(ctx, "missing.pem"),
-		}
-	}
+	a.certificate, certificates = processMainCert(a.ModuleBase, a.getCertString(ctx), certificates, ctx)
 
 	// Build a final signed app package.
 	packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk")
@@ -667,10 +689,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)
@@ -699,7 +720,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)
@@ -865,6 +886,14 @@
 	a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depsInfo)
 }
 
+func (a *AndroidApp) enforceDefaultTargetSdkVersion() bool {
+	return a.appProperties.EnforceDefaultTargetSdkVersion
+}
+
+func (a *AndroidApp) SetEnforceDefaultTargetSdkVersion(val bool) {
+	a.appProperties.EnforceDefaultTargetSdkVersion = val
+}
+
 func (a *AndroidApp) Updatable() bool {
 	return Bool(a.appProperties.Updatable)
 }
@@ -1460,6 +1489,20 @@
 	Certificate_name *string
 }
 
+// ParseCertificateToAttribute splits the certificate prop into a certificate
+// label attribute or a certificate_name string attribute.
+func ParseCertificateToAttribute(ctx android.TopDownMutatorContext, certificate *string) (*string, *bazel.Label) {
+	var certificateLabel *bazel.Label
+	certificateName := proptools.StringDefault(certificate, "")
+	certModule := android.SrcIsModule(certificateName)
+	if certModule != "" {
+		c := android.BazelLabelForModuleDepSingle(ctx, certificateName)
+		certificateLabel = &c
+		certificate = nil
+	}
+	return certificate, certificateLabel
+}
+
 // ConvertWithBp2build is used to convert android_app to Bazel.
 func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx)
@@ -1469,15 +1512,7 @@
 
 	aapt := a.convertAaptAttrsWithBp2Build(ctx)
 
-	var certificate *bazel.Label
-	certificateNamePtr := a.overridableAppProperties.Certificate
-	certificateName := proptools.StringDefault(certificateNamePtr, "")
-	certModule := android.SrcIsModule(certificateName)
-	if certModule != "" {
-		c := android.BazelLabelForModuleDepSingle(ctx, certificateName)
-		certificate = &c
-		certificateNamePtr = nil
-	}
+	certificateName, certificate := ParseCertificateToAttribute(ctx, a.overridableAppProperties.Certificate)
 	attrs := &bazelAndroidAppAttributes{
 		commonAttrs,
 		aapt,
@@ -1485,7 +1520,7 @@
 		// TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
 		a.overridableAppProperties.Package_name,
 		certificate,
-		certificateNamePtr,
+		certificateName,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
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/app_import.go b/java/app_import.go
index d6dca38..6e603c9 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -318,19 +318,17 @@
 
 	if a.isPrebuiltFrameworkRes() {
 		a.outputFile = srcApk
-		certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
+		a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
 		if len(certificates) != 1 {
 			ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
 		}
-		a.certificate = certificates[0]
 	} else if a.preprocessed {
 		a.outputFile = srcApk
 		a.certificate = PresignedCertificate
 	} else if !Bool(a.properties.Presigned) {
 		// If the certificate property is empty at this point, default_dev_cert must be set to true.
 		// Which makes processMainCert's behavior for the empty cert string WAI.
-		certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
-		a.certificate = certificates[0]
+		a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
 		signed := android.PathForModuleOut(ctx, "signed", apkFilename)
 		var lineageFile android.Path
 		if lineage := String(a.properties.Lineage); lineage != "" {
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 41be092..ad27e3a 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -807,3 +807,23 @@
 		}
 	}
 }
+
+func TestAppImportMissingCertificateAllowMissingDependencies(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+		android.PrepareForTestWithAllowMissingDependencies,
+		android.PrepareForTestWithAndroidMk,
+	).RunTestWithBp(t, `
+		android_app_import {
+			name: "foo",
+			apk: "a.apk",
+			certificate: ":missing_certificate",
+		}`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+	fooApk := foo.Output("signed/foo.apk")
+	if fooApk.Rule != android.ErrorRule {
+		t.Fatalf("expected ErrorRule for foo.apk, got %s", fooApk.Rule.String())
+	}
+	android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n")
+}
diff --git a/java/app_test.go b/java/app_test.go
index 23635b9..e216c63 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -3057,6 +3057,179 @@
 	}
 }
 
+func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) {
+	platform_sdk_codename := "Tiramisu"
+	platform_sdk_version := 33
+	testCases := []struct {
+		name                     string
+		platform_sdk_final       bool
+		targetSdkVersionInBp     *string
+		targetSdkVersionExpected *string
+		updatable                bool
+	}{
+		{
+			name:                     "Non-Updatable Module: Android.bp has older targetSdkVersion",
+			targetSdkVersionInBp:     proptools.StringPtr("29"),
+			targetSdkVersionExpected: proptools.StringPtr("29"),
+			updatable:                false,
+		},
+		{
+			name:                     "Updatable Module: Android.bp has older targetSdkVersion",
+			targetSdkVersionInBp:     proptools.StringPtr("30"),
+			targetSdkVersionExpected: proptools.StringPtr("30"),
+			updatable:                true,
+		},
+		{
+			name:                     "Updatable Module: Android.bp has no targetSdkVersion",
+			targetSdkVersionExpected: proptools.StringPtr("10000"),
+			updatable:                true,
+		},
+		{
+			name:                     "[SDK finalised] Non-Updatable Module: Android.bp has older targetSdkVersion",
+			platform_sdk_final:       true,
+			targetSdkVersionInBp:     proptools.StringPtr("30"),
+			targetSdkVersionExpected: proptools.StringPtr("30"),
+			updatable:                false,
+		},
+		{
+			name:                     "[SDK finalised] Updatable Module: Android.bp has older targetSdkVersion",
+			platform_sdk_final:       true,
+			targetSdkVersionInBp:     proptools.StringPtr("30"),
+			targetSdkVersionExpected: proptools.StringPtr("30"),
+			updatable:                true,
+		},
+		{
+			name:                     "[SDK finalised] Updatable Module: Android.bp has targetSdkVersion as platform sdk codename",
+			platform_sdk_final:       true,
+			targetSdkVersionInBp:     proptools.StringPtr(platform_sdk_codename),
+			targetSdkVersionExpected: proptools.StringPtr("33"),
+			updatable:                true,
+		},
+		{
+			name:                     "[SDK finalised] Updatable Module: Android.bp has no targetSdkVersion",
+			platform_sdk_final:       true,
+			targetSdkVersionExpected: proptools.StringPtr("33"),
+			updatable:                true,
+		},
+	}
+	for _, testCase := range testCases {
+		bp := fmt.Sprintf(`
+			android_app {
+				name: "foo",
+				sdk_version: "current",
+				min_sdk_version: "29",
+				target_sdk_version: "%v",
+				updatable: %t,
+				enforce_default_target_sdk_version: %t
+			}
+			`, proptools.String(testCase.targetSdkVersionInBp), testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable
+
+		fixture := android.GroupFixturePreparers(
+			PrepareForTestWithJavaDefaultModules,
+			android.PrepareForTestWithAllowMissingDependencies,
+			android.PrepareForTestWithAndroidMk,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				// explicitly set following platform variables to make the test deterministic
+				variables.Platform_sdk_final = &testCase.platform_sdk_final
+				variables.Platform_sdk_version = &platform_sdk_version
+				variables.Platform_sdk_codename = &platform_sdk_codename
+				variables.Platform_version_active_codenames = []string{platform_sdk_codename}
+				variables.Unbundled_build_apps = []string{"sampleModule"}
+			}),
+		)
+
+		result := fixture.RunTestWithBp(t, bp)
+		foo := result.ModuleForTests("foo", "android_common")
+
+		manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+		android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion  "+*testCase.targetSdkVersionExpected)
+	}
+}
+
+func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) {
+	platform_sdk_codename := "Tiramisu"
+	platform_sdk_version := 33
+	testCases := []struct {
+		name                           string
+		enforceDefaultTargetSdkVersion bool
+		expectedError                  string
+		platform_sdk_final             bool
+		targetSdkVersionInBp           string
+		targetSdkVersionExpected       string
+		updatable                      bool
+	}{
+		{
+			name:                           "Not enforcing Target SDK Version: Android.bp has older targetSdkVersion",
+			enforceDefaultTargetSdkVersion: false,
+			targetSdkVersionInBp:           "29",
+			targetSdkVersionExpected:       "29",
+			updatable:                      false,
+		},
+		{
+			name:                           "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion",
+			enforceDefaultTargetSdkVersion: true,
+			platform_sdk_final:             true,
+			targetSdkVersionInBp:           "current",
+			targetSdkVersionExpected:       "33",
+			updatable:                      true,
+		},
+		{
+			name:                           "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion",
+			enforceDefaultTargetSdkVersion: true,
+			platform_sdk_final:             false,
+			targetSdkVersionInBp:           "current",
+			targetSdkVersionExpected:       "10000",
+			updatable:                      false,
+		},
+		{
+			name:                           "Not enforcing Target SDK Version for Updatable app",
+			enforceDefaultTargetSdkVersion: false,
+			expectedError:                  "Updatable apps must enforce default target sdk version",
+			targetSdkVersionInBp:           "29",
+			targetSdkVersionExpected:       "29",
+			updatable:                      true,
+		},
+	}
+	for _, testCase := range testCases {
+		errExpected := testCase.expectedError != ""
+		bp := fmt.Sprintf(`
+			android_app {
+				name: "foo",
+				enforce_default_target_sdk_version: %t,
+				sdk_version: "current",
+				min_sdk_version: "29",
+				target_sdk_version: "%v",
+				updatable: %t
+			}
+			`, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp, testCase.updatable)
+
+		fixture := android.GroupFixturePreparers(
+			PrepareForTestWithJavaDefaultModules,
+			android.PrepareForTestWithAllowMissingDependencies,
+			android.PrepareForTestWithAndroidMk,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				// explicitly set following platform variables to make the test deterministic
+				variables.Platform_sdk_final = &testCase.platform_sdk_final
+				variables.Platform_sdk_version = &platform_sdk_version
+				variables.Platform_sdk_codename = &platform_sdk_codename
+				variables.Unbundled_build_apps = []string{"sampleModule"}
+			}),
+		)
+
+		errorHandler := android.FixtureExpectsNoErrors
+		if errExpected {
+			errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError)
+		}
+		result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp)
+
+		if !errExpected {
+			foo := result.ModuleForTests("foo", "android_common")
+			manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+			android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion  "+testCase.targetSdkVersionExpected)
+		}
+	}
+}
+
 func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		PrepareForTestWithJavaDefaultModules,
diff --git a/java/base.go b/java/base.go
index 23b4d46..656a080 100644
--- a/java/base.go
+++ b/java/base.go
@@ -530,7 +530,7 @@
 		// TODO(satayev): cover other types as well, e.g. imports
 		case *Library, *AndroidLibrary:
 			switch tag {
-			case bootClasspathTag, libTag, staticLibTag, java9LibTag:
+			case bootClasspathTag, sdkLibTag, libTag, staticLibTag, java9LibTag:
 				j.checkSdkLinkType(ctx, module.(moduleWithSdkDep), tag.(dependencyTag))
 			}
 		}
@@ -1955,7 +1955,7 @@
 
 		if dep, ok := module.(SdkLibraryDependency); ok {
 			switch tag {
-			case libTag:
+			case sdkLibTag, libTag:
 				depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))
 				deps.classpath = append(deps.classpath, depHeaderJars...)
 				deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...)
@@ -1975,7 +1975,7 @@
 			switch tag {
 			case bootClasspathTag:
 				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
-			case libTag, instrumentationForTag:
+			case sdkLibTag, libTag, instrumentationForTag:
 				if _, ok := module.(*Plugin); ok {
 					ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName)
 				}
@@ -2048,7 +2048,7 @@
 			}
 		} else if dep, ok := module.(android.SourceFileProducer); ok {
 			switch tag {
-			case libTag:
+			case sdkLibTag, libTag:
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
 				deps.dexClasspath = append(deps.classpath, dep.Srcs()...)
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 9316807..f5b5f99 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -257,7 +257,7 @@
 	// Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the
 	// module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a
 	// versioned sdk.
-	produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
+	produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
 
 	// produceBootImageFiles will attempt to produce rules to create the boot image files at the paths
 	// predefined in the bootImageConfig.
@@ -716,8 +716,6 @@
 	// This is an exception to support end-to-end test for SdkExtensions, until such support exists.
 	if android.InList("test_framework-sdkextensions", possibleUpdatableModules) {
 		jars = jars.Append("com.android.sdkext", "test_framework-sdkextensions")
-	} else if android.InList("AddNewActivity", possibleUpdatableModules) {
-		jars = jars.Append("test_com.android.cts.frameworkresapkplits", "AddNewActivity")
 	} else if android.InList("test_framework-apexd", possibleUpdatableModules) {
 		jars = jars.Append("com.android.apex.test_package", "test_framework-apexd")
 	} else if global.ApexBootJars.Len() != 0 && !android.IsModuleInVersionedSdk(ctx.Module()) {
@@ -761,7 +759,7 @@
 
 	// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
 	common := ctx.Module().(commonBootclasspathFragment)
-	output := common.produceHiddenAPIOutput(ctx, contents, input)
+	output := common.produceHiddenAPIOutput(ctx, contents, fragments, input)
 
 	// If the source or prebuilts module does not provide a signature patterns file then generate one
 	// from the flags.
@@ -769,7 +767,7 @@
 	//  their own.
 	if output.SignaturePatternsPath == nil {
 		output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
-			ctx, output.AllFlagsPath, []string{"*"}, nil, nil)
+			ctx, output.AllFlagsPath, []string{"*"}, nil, nil, "")
 	}
 
 	// Initialize a HiddenAPIInfo structure.
@@ -840,30 +838,15 @@
 
 // isTestFragment returns true if the current module is a test bootclasspath_fragment.
 func (b *BootclasspathFragmentModule) isTestFragment() bool {
-	if b.testFragment {
-		return true
-	}
-
-	// TODO(b/194063708): Once test fragments all use bootclasspath_fragment_test
-	// Some temporary exceptions until all test fragments use the
-	// bootclasspath_fragment_test module type.
-	name := b.BaseModuleName()
-	if strings.HasPrefix(name, "test_") {
-		return true
-	}
-	if name == "apex.apexd_test_bootclasspath-fragment" {
-		return true
-	}
-
-	return false
+	return b.testFragment
 }
 
-// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files)
-// for the fragment as well as encoding the flags in the boot dex jars.
-func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+// generateHiddenApiFlagRules generates rules to generate hidden API flags and compute the signature
+// patterns file.
+func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput {
 	// Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
 	// paths to the created files.
-	output := hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
+	flagOutput := hiddenAPIFlagRulesForBootclasspathFragment(ctx, bootDexInfoByModule, contents, input, suffix)
 
 	// If the module specifies split_packages or package_prefixes then use those to generate the
 	// signature patterns.
@@ -871,8 +854,8 @@
 	packagePrefixes := input.PackagePrefixes
 	singlePackages := input.SinglePackages
 	if splitPackages != nil || packagePrefixes != nil || singlePackages != nil {
-		output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
-			ctx, output.AllFlagsPath, splitPackages, packagePrefixes, singlePackages)
+		flagOutput.SignaturePatternsPath = buildRuleSignaturePatternsFile(
+			ctx, flagOutput.AllFlagsPath, splitPackages, packagePrefixes, singlePackages, suffix)
 	} else if !b.isTestFragment() {
 		ctx.ModuleErrorf(`Must specify at least one of the split_packages, package_prefixes and single_packages properties
   If this is a new bootclasspath_fragment or you are unsure what to do add the
@@ -884,6 +867,68 @@
   should specify here. If you are happy with its suggestions then you can add
   the --fix option and it will fix them for you.`, b.BaseModuleName())
 	}
+	return flagOutput
+}
+
+// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files)
+// for the fragment as well as encoding the flags in the boot dex jars.
+func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+	// Gather information about the boot dex files for the boot libraries provided by this fragment.
+	bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
+
+	// Generate the flag file needed to encode into the dex files.
+	flagOutput := b.generateHiddenApiFlagRules(ctx, contents, input, bootDexInfoByModule, "")
+
+	// Encode those flags into the dex files of the contents of this fragment.
+	encodedBootDexFilesByModule := hiddenAPIEncodeRulesForBootclasspathFragment(ctx, bootDexInfoByModule, flagOutput.AllFlagsPath)
+
+	// Store that information for return for use by other rules.
+	output := &HiddenAPIOutput{
+		HiddenAPIFlagOutput:         flagOutput,
+		EncodedBootDexFilesByModule: encodedBootDexFilesByModule,
+	}
+
+	// Get the ApiLevel associated with SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE, defaulting to current
+	// if not set.
+	config := ctx.Config()
+	targetApiLevel := android.ApiLevelOrPanic(ctx,
+		config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", "current"))
+
+	// Filter the contents list to remove any modules that do not support the target build release.
+	// The current build release supports all the modules.
+	contentsForSdkSnapshot := []android.Module{}
+	for _, module := range contents {
+		// If the module has a min_sdk_version that is higher than the target build release then it will
+		// not work on the target build release and so must not be included in the sdk snapshot.
+		minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, module)
+		if minApiLevel.GreaterThan(targetApiLevel) {
+			continue
+		}
+
+		contentsForSdkSnapshot = append(contentsForSdkSnapshot, module)
+	}
+
+	var flagFilesByCategory FlagFilesByCategory
+	if len(contentsForSdkSnapshot) != len(contents) {
+		// The sdk snapshot has different contents to the runtime fragment so it is not possible to
+		// reuse the hidden API information generated for the fragment. So, recompute that information
+		// for the sdk snapshot.
+		filteredInput := b.createHiddenAPIFlagInput(ctx, contentsForSdkSnapshot, fragments)
+
+		// Gather information about the boot dex files for the boot libraries provided by this fragment.
+		filteredBootDexInfoByModule := extractBootDexInfoFromModules(ctx, contentsForSdkSnapshot)
+		flagOutput = b.generateHiddenApiFlagRules(ctx, contentsForSdkSnapshot, filteredInput, filteredBootDexInfoByModule, "-for-sdk-snapshot")
+		flagFilesByCategory = filteredInput.FlagFilesByCategory
+	} else {
+		// The sdk snapshot has the same contents as the runtime fragment so reuse that information.
+		flagFilesByCategory = input.FlagFilesByCategory
+	}
+
+	// Make the information available for the sdk snapshot.
+	ctx.SetProvider(HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
+		FlagFilesByCategory: flagFilesByCategory,
+		HiddenAPIFlagOutput: flagOutput,
+	})
 
 	return output
 }
@@ -1049,7 +1094,7 @@
 
 	// Get the hidden API information from the module.
 	mctx := ctx.SdkModuleContext()
-	hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoProvider).(HiddenAPIInfo)
+	hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoForSdkProvider).(HiddenAPIInfoForSdk)
 	b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
 
 	// Copy all the generated file paths.
@@ -1191,7 +1236,7 @@
 }
 
 // produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
-func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
+func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
 	pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path {
 		if src == nil {
 			return defaultPath
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index c63df59..2541f14 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -408,22 +408,6 @@
 			},
 		}
 
-		bootclasspath_fragment {
-			name: "test_fragment",
-			contents: ["mysdklibrary"],
-			hidden_api: {
-				split_packages: [],
-			},
-		}
-
-		bootclasspath_fragment {
-			name: "apex.apexd_test_bootclasspath-fragment",
-			contents: ["mysdklibrary"],
-			hidden_api: {
-				split_packages: [],
-			},
-		}
-
 		bootclasspath_fragment_test {
 			name: "a_test_fragment",
 			contents: ["mysdklibrary"],
@@ -445,12 +429,6 @@
 	fragment := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
 	android.AssertBoolEquals(t, "not a test fragment", false, fragment.isTestFragment())
 
-	fragment = result.Module("test_fragment", "android_common").(*BootclasspathFragmentModule)
-	android.AssertBoolEquals(t, "is a test fragment by prefix", true, fragment.isTestFragment())
-
 	fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule)
 	android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment())
-
-	fragment = result.Module("apex.apexd_test_bootclasspath-fragment", "android_common").(*BootclasspathFragmentModule)
-	android.AssertBoolEquals(t, "is a test fragment by name", true, fragment.isTestFragment())
 }
diff --git a/java/config/config.go b/java/config/config.go
index b026d73..ea44aaa 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -78,7 +78,7 @@
 func init() {
 	pctx.Import("github.com/google/blueprint/bootstrap")
 
-	exportedVars.ExportStringStaticVariable("JavacHeapSize", "2048M")
+	exportedVars.ExportStringStaticVariable("JavacHeapSize", "4096M")
 	exportedVars.ExportStringStaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
 
 	// ErrorProne can use significantly more memory than javac alone, give it a higher heap
@@ -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/droiddoc.go b/java/droiddoc.go
index fc95184..2173dae 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -267,7 +267,7 @@
 			ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 			ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
 			ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
-			ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
+			ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
 		}
 	}
 
@@ -367,7 +367,7 @@
 			} else {
 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 			}
-		case libTag:
+		case libTag, sdkLibTag:
 			if dep, ok := module.(SdkLibraryDependency); ok {
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
 			} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
@@ -684,7 +684,7 @@
 	outDir, srcJarDir, srcJarList android.Path, sourcepaths android.Paths) *android.RuleBuilderCommand {
 
 	cmd := rule.Command().
-		BuiltTool("soong_javac_wrapper").Tool(config.JavadocCmd(ctx)).
+		BuiltTool("soong_javac_wrapper").Tool(android.PathForSource(ctx, "prebuilts/jdk/jdk11/linux-x86/bin/javadoc")).
 		Flag(config.JavacVmFlags).
 		FlagWithArg("-encoding ", "UTF-8").
 		FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "javadoc.rsp"), srcs).
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 7b67803..5474ae1 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -594,6 +594,23 @@
 
 var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
 
+// HiddenAPIInfoForSdk contains information provided by the hidden API processing for use
+// by the sdk snapshot.
+//
+// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
+// processing.
+type HiddenAPIInfoForSdk struct {
+	// FlagFilesByCategory maps from the flag file category to the paths containing information for
+	// that category.
+	FlagFilesByCategory FlagFilesByCategory
+
+	// The output from the hidden API processing needs to be made available to other modules.
+	HiddenAPIFlagOutput
+}
+
+// Provides hidden API info for the sdk snapshot.
+var HiddenAPIInfoForSdkProvider = blueprint.NewProvider(HiddenAPIInfoForSdk{})
+
 // ModuleStubDexJars contains the stub dex jars provided by a single module.
 //
 // It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See
@@ -1024,8 +1041,11 @@
 // patterns that will select a subset of the monolithic flags.
 func buildRuleSignaturePatternsFile(
 	ctx android.ModuleContext, flagsPath android.Path,
-	splitPackages []string, packagePrefixes []string, singlePackages []string) android.Path {
-	patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
+	splitPackages []string, packagePrefixes []string, singlePackages []string,
+	suffix string) android.Path {
+	hiddenApiSubDir := "modular-hiddenapi" + suffix
+
+	patternsFile := android.PathForModuleOut(ctx, hiddenApiSubDir, "signature-patterns.csv")
 	// Create a rule to validate the output from the following rule.
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -1042,7 +1062,7 @@
 		FlagForEachArg("--package-prefix ", packagePrefixes).
 		FlagForEachArg("--single-package ", singlePackages).
 		FlagWithOutput("--output ", patternsFile)
-	rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
+	rule.Build("hiddenAPISignaturePatterns"+suffix, "hidden API signature patterns"+suffix)
 
 	return patternsFile
 }
@@ -1116,8 +1136,8 @@
 	return validFile
 }
 
-// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
-// bootclasspath and then encode the flags into the boot dex files.
+// hiddenAPIFlagRulesForBootclasspathFragment will generate all the flags for a fragment of the
+// bootclasspath.
 //
 // It takes:
 // * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
@@ -1130,31 +1150,27 @@
 // * metadata.csv
 // * index.csv
 // * all-flags.csv
-// * encoded boot dex files
-func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
-	hiddenApiSubDir := "modular-hiddenapi"
-
-	// Gather information about the boot dex files for the boot libraries provided by this fragment.
-	bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
+func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput {
+	hiddenApiSubDir := "modular-hiddenapi" + suffix
 
 	// Generate the stub-flags.csv.
 	stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
-	buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
+	buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile"+suffix, "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
 
 	// Extract the classes jars from the contents.
 	classesJars := extractClassesJarsFromModules(contents)
 
 	// Generate the set of flags from the annotations in the source code.
 	annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
-	buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
+	buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags"+suffix, classesJars, stubFlagsCSV, annotationFlagsCSV)
 
 	// Generate the metadata from the annotations in the source code.
 	metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
-	buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
+	buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata"+suffix, classesJars, stubFlagsCSV, metadataCSV)
 
 	// Generate the index file from the CSV files in the classes jars.
 	indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
-	buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
+	buildRuleToGenerateIndex(ctx, "modular hiddenapi index"+suffix, classesJars, indexCSV)
 
 	// Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files
 	// containing dex signatures of all the removed APIs. In the monolithic files that is done by
@@ -1162,15 +1178,44 @@
 	// signatures, see the combined-removed-dex module. This does that automatically by using the
 	// *removed.txt files retrieved from the java_sdk_library modules that are specified in the
 	// stub_libs and contents properties of a bootclasspath_fragment.
-	removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
+	removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, suffix, input.RemovedTxtFiles)
 
 	// Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
 	// files.
 	allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
-	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
+	buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags"+suffix, "modular hiddenapi all flags"+suffix, allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
 
+	// Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
+	// compared against the monolithic stub flags.
+	filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
+	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags"+suffix,
+		"modular hiddenapi filtered stub flags"+suffix, stubFlagsCSV, filteredStubFlagsCSV,
+		HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
+
+	// Generate the filtered-flags.csv file which contains the filtered flags that will be compared
+	// against the monolithic flags.
+	filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
+	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags"+suffix,
+		"modular hiddenapi filtered flags"+suffix, allFlagsCSV, filteredFlagsCSV,
+		HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
+
+	// Store the paths in the info for use by other modules and sdk snapshot generation.
+	return HiddenAPIFlagOutput{
+		AnnotationFlagsPath:   annotationFlagsCSV,
+		MetadataPath:          metadataCSV,
+		IndexPath:             indexCSV,
+		StubFlagsPath:         stubFlagsCSV,
+		AllFlagsPath:          allFlagsCSV,
+		FilteredStubFlagsPath: filteredStubFlagsCSV,
+		FilteredFlagsPath:     filteredFlagsCSV,
+	}
+}
+
+// hiddenAPIEncodeRulesForBootclasspathFragment generates rules to encode hidden API flags into the
+// dex jars in bootDexInfoByModule.
+func hiddenAPIEncodeRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, allFlagsCSV android.Path) bootDexJarByModule {
 	// Encode the flags into the boot dex files.
-	encodedBootDexJarsByModule := map[string]android.Path{}
+	encodedBootDexJarsByModule := bootDexJarByModule{}
 	outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
 	for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
 		bootDexInfo := bootDexInfoByModule[name]
@@ -1178,43 +1223,15 @@
 		encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir)
 		encodedBootDexJarsByModule[name] = encodedDex
 	}
-
-	// Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
-	// compared against the monolithic stub flags.
-	filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
-	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags",
-		"modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV,
-		HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
-
-	// Generate the filtered-flags.csv file which contains the filtered flags that will be compared
-	// against the monolithic flags.
-	filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
-	buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags",
-		"modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV,
-		HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
-
-	// Store the paths in the info for use by other modules and sdk snapshot generation.
-	output := HiddenAPIOutput{
-		HiddenAPIFlagOutput: HiddenAPIFlagOutput{
-			AnnotationFlagsPath:   annotationFlagsCSV,
-			MetadataPath:          metadataCSV,
-			IndexPath:             indexCSV,
-			StubFlagsPath:         stubFlagsCSV,
-			AllFlagsPath:          allFlagsCSV,
-			FilteredStubFlagsPath: filteredStubFlagsCSV,
-			FilteredFlagsPath:     filteredFlagsCSV,
-		},
-		EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
-	}
-	return &output
+	return encodedBootDexJarsByModule
 }
 
-func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
+func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix string, removedTxtFiles android.Paths) android.OptionalPath {
 	if len(removedTxtFiles) == 0 {
 		return android.OptionalPath{}
 	}
 
-	output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
+	output := android.PathForModuleOut(ctx, "module-hiddenapi"+suffix, "removed-dex-signatures.txt")
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
@@ -1222,7 +1239,7 @@
 		Flag("--no-banner").
 		Inputs(removedTxtFiles).
 		FlagWithOutput("--dex-api ", output)
-	rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
+	rule.Build("modular-hiddenapi-removed-dex-signatures"+suffix, "modular hiddenapi removed dex signatures"+suffix)
 	return android.OptionalPathForPath(output)
 }
 
diff --git a/java/java.go b/java/java.go
index d04e52a..fc2af3b 100644
--- a/java/java.go
+++ b/java/java.go
@@ -348,6 +348,7 @@
 	dataDeviceBinsTag       = dependencyTag{name: "dataDeviceBins"}
 	staticLibTag            = dependencyTag{name: "staticlib"}
 	libTag                  = dependencyTag{name: "javalib", runtimeLinked: true}
+	sdkLibTag               = dependencyTag{name: "sdklib", runtimeLinked: true}
 	java9LibTag             = dependencyTag{name: "java9lib", runtimeLinked: true}
 	pluginTag               = dependencyTag{name: "plugin", toolchain: true}
 	errorpronePluginTag     = dependencyTag{name: "errorprone-plugin", toolchain: true}
@@ -374,7 +375,7 @@
 )
 
 func IsLibDepTag(depTag blueprint.DependencyTag) bool {
-	return depTag == libTag
+	return depTag == libTag || depTag == sdkLibTag
 }
 
 func IsStaticLibDepTag(depTag blueprint.DependencyTag) bool {
@@ -427,7 +428,7 @@
 	if sdkDep.useModule {
 		ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
 		ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
-		ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
+		ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
 		if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
 			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
 		}
@@ -1654,7 +1655,7 @@
 		if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
 			dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
 			switch tag {
-			case libTag:
+			case libTag, sdkLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
 				flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
 			case staticLibTag:
@@ -1664,7 +1665,7 @@
 			}
 		} else if dep, ok := module.(SdkLibraryDependency); ok {
 			switch tag {
-			case libTag:
+			case libTag, sdkLibTag:
 				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
 			}
 		}
@@ -2178,7 +2179,7 @@
 	}
 
 	depTag := ctx.OtherModuleDependencyTag(depModule)
-	if depTag == libTag {
+	if IsLibDepTag(depTag) {
 		// Ok, propagate <uses-library> through non-static library dependencies.
 	} else if tag, ok := depTag.(usesLibraryDependencyTag); ok && tag.sdkVersion == dexpreopt.AnySdkVersion {
 		// Ok, propagate <uses-library> through non-compatibility <uses-library> dependencies.
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 01e7e6e..519a702 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -39,6 +39,7 @@
 # Downgrade existing errors to warnings
 --warning_check AppCompatResource                  # 55 occurences in 10 modules
 --warning_check AppLinkUrlError                    # 111 occurences in 53 modules
+--warning_check BinderGetCallingInMainThread
 --warning_check ByteOrderMark                      # 2 occurences in 2 modules
 --warning_check DuplicateActivity                  # 3 occurences in 3 modules
 --warning_check DuplicateDefinition                # 3623 occurences in 48 modules
@@ -91,6 +92,7 @@
 --warning_check StringFormatInvalid                # 148 occurences in 11 modules
 --warning_check StringFormatMatches                # 4800 occurences in 30 modules
 --warning_check UnknownId                          # 8 occurences in 7 modules
+--warning_check UnspecifiedImmutableFlag
 --warning_check ValidFragment                      # 12 occurences in 5 modules
 --warning_check ValidRestrictions                  # 5 occurences in 1 modules
 --warning_check WebViewLayout                      # 3 occurences in 1 modules
diff --git a/java/lint_test.go b/java/lint_test.go
index 456e6ba..62450d5 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -271,7 +271,7 @@
 				"a.java",
 			],
 			min_sdk_version: "29",
-			sdk_version: "module_current",
+			sdk_version: "XXX",
 			lint: {
 				strict_updatability_linting: true,
 			},
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/java/robolectric.go b/java/robolectric.go
index 71ffdb1..7f2981f 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -23,6 +23,7 @@
 	"android/soong/android"
 	"android/soong/java/config"
 	"android/soong/tradefed"
+
 	"github.com/google/blueprint/proptools"
 )
 
@@ -166,7 +167,7 @@
 		instrumentedApp.implementationAndResourcesJar,
 	}
 
-	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+	handleLibDeps := func(dep android.Module) {
 		m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
 		r.libs = append(r.libs, ctx.OtherModuleName(dep))
 		if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
@@ -174,6 +175,13 @@
 		}
 	}
 
+	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+		handleLibDeps(dep)
+	}
+	for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) {
+		handleLibDeps(dep)
+	}
+
 	r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base())
 	TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{},
 		false, nil, nil)
diff --git a/java/rro.go b/java/rro.go
index c12e748..cd8c635 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -142,11 +142,11 @@
 		aaptLinkFlags = append(aaptLinkFlags,
 			"--rename-overlay-target-package "+*r.overridableProperties.Target_package_name)
 	}
-	r.aapt.buildActions(ctx, r, nil, nil, aaptLinkFlags...)
+	r.aapt.buildActions(ctx, r, nil, nil, false, aaptLinkFlags...)
 
 	// Sign the built package
 	_, _, certificates := collectAppDeps(ctx, r, false, false)
-	certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
+	r.certificate, certificates = processMainCert(r.ModuleBase, String(r.properties.Certificate), certificates, ctx)
 	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
 	var lineageFile android.Path
 	if lineage := String(r.properties.Lineage); lineage != "" {
@@ -156,7 +156,6 @@
 	rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion)
 
 	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion)
-	r.certificate = certificates[0]
 
 	r.outputFile = signed
 	partition := rroPartition(ctx)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 8f499b1..59ffff5 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -539,7 +539,7 @@
 	}
 
 	// TODO: determines whether to create HTML doc or not
-	//Html_doc *bool
+	// Html_doc *bool
 }
 
 // Paths to outputs from java_sdk_library and java_sdk_library_import.
@@ -1354,7 +1354,7 @@
 	// Provide additional information for inclusion in an sdk's generated .info file.
 	additionalSdkInfo := map[string]interface{}{}
 	additionalSdkInfo["dist_stem"] = module.distStem()
-	baseModuleName := module.BaseModuleName()
+	baseModuleName := module.distStem()
 	scopes := map[string]interface{}{}
 	additionalSdkInfo["scopes"] = scopes
 	for scope, scopePaths := range module.scopePaths {
@@ -2236,8 +2236,9 @@
 		Sdk_version *string
 		Libs        []string
 		Jars        []string
-		Prefer      *bool
 		Compile_dex *bool
+
+		android.UserSuppliedPrebuiltProperties
 	}{}
 	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
 	props.Sdk_version = scopeProperties.Sdk_version
@@ -2247,7 +2248,7 @@
 	props.Jars = scopeProperties.Jars
 
 	// The imports are preferred if the java_sdk_library_import is preferred.
-	props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
+	props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
 
 	// The imports need to be compiled to dex if the java_sdk_library_import requests it.
 	compileDex := module.properties.Compile_dex
@@ -2261,16 +2262,18 @@
 
 func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	props := struct {
-		Name   *string
-		Srcs   []string
-		Prefer *bool
+		Name *string
+		Srcs []string
+
+		android.UserSuppliedPrebuiltProperties
 	}{}
 	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope))
 	props.Srcs = scopeProperties.Stub_srcs
-	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
 
 	// The stubs source is preferred if the java_sdk_library_import is preferred.
-	props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
+	props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
+
+	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
 }
 
 // Add the dependencies on the child module in the component deps mutator so that it
@@ -2904,6 +2907,18 @@
 type sdkLibrarySdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
+	// Stem name for files in the sdk snapshot.
+	//
+	// This is used to construct the path names of various sdk library files in the sdk snapshot to
+	// make sure that they match the finalized versions of those files in prebuilts/sdk.
+	//
+	// This property is marked as keep so that it will be kept in all instances of this struct, will
+	// not be cleared but will be copied to common structs. That is needed because this field is used
+	// to construct many file names for other parts of this struct and so it needs to be present in
+	// all structs. If it was not marked as keep then it would be cleared in some structs and so would
+	// be unavailable for generating file names if there were other properties that were still set.
+	Stem string `sdk:"keep"`
+
 	// Scope to per scope properties.
 	Scopes map[*apiScope]*scopeProperties
 
@@ -2965,6 +2980,9 @@
 func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	sdk := variant.(*SdkLibrary)
 
+	// Copy the stem name for files in the sdk snapshot.
+	s.Stem = sdk.distStem()
+
 	s.Scopes = make(map[*apiScope]*scopeProperties)
 	for _, apiScope := range allApiScopes {
 		paths := sdk.findScopePaths(apiScope)
@@ -3017,6 +3035,8 @@
 		propertySet.AddProperty("permitted_packages", s.Permitted_packages)
 	}
 
+	stem := s.Stem
+
 	for _, apiScope := range allApiScopes {
 		if properties, ok := s.Scopes[apiScope]; ok {
 			scopeSet := propertySet.AddPropertySet(apiScope.propertyName)
@@ -3025,7 +3045,7 @@
 
 			var jars []string
 			for _, p := range properties.Jars {
-				dest := filepath.Join(scopeDir, ctx.Name()+"-stubs.jar")
+				dest := filepath.Join(scopeDir, stem+"-stubs.jar")
 				ctx.SnapshotBuilder().CopyToSnapshot(p, dest)
 				jars = append(jars, dest)
 			}
@@ -3033,31 +3053,31 @@
 
 			if ctx.SdkModuleContext().Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_USE_SRCJAR") {
 				// Copy the stubs source jar into the snapshot zip as is.
-				srcJarSnapshotPath := filepath.Join(scopeDir, ctx.Name()+".srcjar")
+				srcJarSnapshotPath := filepath.Join(scopeDir, stem+".srcjar")
 				ctx.SnapshotBuilder().CopyToSnapshot(properties.StubsSrcJar, srcJarSnapshotPath)
 				scopeSet.AddProperty("stub_srcs", []string{srcJarSnapshotPath})
 			} else {
 				// Merge the stubs source jar into the snapshot zip so that when it is unpacked
 				// the source files are also unpacked.
-				snapshotRelativeDir := filepath.Join(scopeDir, ctx.Name()+"_stub_sources")
+				snapshotRelativeDir := filepath.Join(scopeDir, stem+"_stub_sources")
 				ctx.SnapshotBuilder().UnzipToSnapshot(properties.StubsSrcJar, snapshotRelativeDir)
 				scopeSet.AddProperty("stub_srcs", []string{snapshotRelativeDir})
 			}
 
 			if properties.CurrentApiFile != nil {
-				currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(ctx.Name())
+				currentApiSnapshotPath := apiScope.snapshotRelativeCurrentApiTxtPath(stem)
 				ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, currentApiSnapshotPath)
 				scopeSet.AddProperty("current_api", currentApiSnapshotPath)
 			}
 
 			if properties.RemovedApiFile != nil {
-				removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(ctx.Name())
+				removedApiSnapshotPath := apiScope.snapshotRelativeRemovedApiTxtPath(stem)
 				ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath)
 				scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
 			}
 
 			if properties.AnnotationsZip != nil {
-				annotationsSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"_annotations.zip")
+				annotationsSnapshotPath := filepath.Join(scopeDir, stem+"_annotations.zip")
 				ctx.SnapshotBuilder().CopyToSnapshot(properties.AnnotationsZip, annotationsSnapshotPath)
 				scopeSet.AddProperty("annotations", annotationsSnapshotPath)
 			}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 805bc22..ea7b2f7 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -875,11 +875,12 @@
 	})
 }
 
-func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
+func testJavaSdkLibraryImport_Preferred(t *testing.T, prefer string, preparer android.FixturePreparer) {
 	result := android.GroupFixturePreparers(
 		prepareForJavaTest,
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("sdklib"),
+		preparer,
 	).RunTestWithBp(t, `
 		java_sdk_library {
 			name: "sdklib",
@@ -893,11 +894,37 @@
 
 		java_sdk_library_import {
 			name: "sdklib",
-			prefer: true,
+			`+prefer+`
 			public: {
 				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
 			},
 		}
+
+		java_library {
+			name: "combined",
+			static_libs: [
+				"sdklib.stubs",
+			],
+			java_resources: [
+				":sdklib.stubs.source",
+				":sdklib{.public.api.txt}",
+				":sdklib{.public.removed-api.txt}",
+				":sdklib{.public.annotations.zip}",
+			],
+			sdk_version: "none",
+			system_modules: "none",
+		}
+
+		java_library {
+			name: "public",
+			srcs: ["a.java"],
+			libs: ["sdklib"],
+			sdk_version: "current",
+		}
 		`)
 
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
@@ -913,9 +940,48 @@
 	CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
 		`dex2oatd`,
 		`prebuilt_sdklib.stubs`,
+		`prebuilt_sdklib.stubs.source`,
 		`sdklib.impl`,
 		`sdklib.xml`,
 	})
+
+	// Make sure that dependencies on child modules use the prebuilt when preferred.
+	CheckModuleDependencies(t, result.TestContext, "combined", "android_common", []string{
+		// Each use of :sdklib{...} adds a dependency onto prebuilt_sdklib.
+		`prebuilt_sdklib`,
+		`prebuilt_sdklib`,
+		`prebuilt_sdklib`,
+		`prebuilt_sdklib.stubs`,
+		`prebuilt_sdklib.stubs.source`,
+	})
+
+	// Make sure that dependencies on sdklib that resolve to one of the child libraries use the
+	// prebuilt library.
+	public := result.ModuleForTests("public", "android_common")
+	rule := public.Output("javac/public.jar")
+	inputs := rule.Implicits.Strings()
+	expected := "out/soong/.intermediates/prebuilt_sdklib.stubs/android_common/combined/sdklib.stubs.jar"
+	if !android.InList(expected, inputs) {
+		t.Errorf("expected %q to contain %q", inputs, expected)
+	}
+}
+
+func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
+	t.Run("prefer", func(t *testing.T) {
+		testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer)
+	})
+
+	t.Run("use_source_config_var", func(t *testing.T) {
+		testJavaSdkLibraryImport_Preferred(t,
+			"use_source_config_var: {config_namespace: \"acme\", var_name: \"use_source\"},",
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "false",
+					},
+				}
+			}))
+	})
 }
 
 func TestJavaSdkLibraryEnforce(t *testing.T) {
diff --git a/licenses/Android.bp b/licenses/Android.bp
index 133f7f7..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",
 }
 
@@ -762,7 +762,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-GPL-2.0-with-classpath-exception",
-    conditions: ["restricted"],
+    conditions: ["permissive"],
     url: "https://spdx.org/licenses/GPL-2.0-with-classpath-exception.html",
 }
 
@@ -810,7 +810,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-GPL-with-classpath-exception",
-    conditions: ["restricted"],
+    conditions: ["permissive"],
 }
 
 license_kind {
@@ -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/linkerconfig/proto/Android.bp b/linkerconfig/proto/Android.bp
index 3b1e4ab..754e7bf 100644
--- a/linkerconfig/proto/Android.bp
+++ b/linkerconfig/proto/Android.bp
@@ -19,14 +19,6 @@
 
 python_library_host {
     name: "linker_config_proto",
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
     srcs: [
         "linker_config.proto",
     ],
diff --git a/python/Android.bp b/python/Android.bp
index e49fa6a..99c02bd 100644
--- a/python/Android.bp
+++ b/python/Android.bp
@@ -27,3 +27,15 @@
     ],
     pluginFor: ["soong_build"],
 }
+
+// We're transitioning all of these flags to be true by default.
+// This is a defaults flag that can be used to easily add all of them to
+// certain modules.
+python_defaults {
+    name: "modern_python_path_defaults",
+    dont_add_top_level_directories_to_path: true,
+    dont_add_entrypoint_folder_to_path: true,
+    proto: {
+        respect_pkg_path: true,
+    },
+}
diff --git a/python/binary.go b/python/binary.go
index af29bb6..e6324a3 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -116,6 +116,22 @@
 	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
 	// explicitly.
 	Auto_gen_config *bool
+
+	// Currently, both the root of the zipfile and all the directories 1 level
+	// below that are added to the python path. When this flag is set to true,
+	// only the root of the zipfile will be added to the python path. This flag
+	// will be removed after all the python modules in the tree have been updated
+	// to support it. When using embedded_launcher: true, this is already the
+	// behavior. The default is currently false.
+	Dont_add_top_level_directories_to_path *bool
+
+	// Setting this to true will mimic Python 3.11+'s PYTHON_SAFE_PATH environment
+	// variable or -P flag, even on older python versions. This is a temporary
+	// flag while modules are changed to support it, eventually true will be the
+	// default and the flag will be removed. The default is currently false. It
+	// is only applicable when embedded_launcher is false, when embedded_launcher
+	// is true this is already implied.
+	Dont_add_entrypoint_folder_to_path *bool
 }
 
 type binaryDecorator struct {
@@ -128,10 +144,6 @@
 	IntermPathForModuleOut() android.OptionalPath
 }
 
-var (
-	StubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
-)
-
 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
 	module := newModule(hod, android.MultilibFirst)
 	decorator := &binaryDecorator{pythonInstaller: NewPythonInstaller("bin", "")}
@@ -180,9 +192,13 @@
 		})
 	}
 
+	addTopDirectoriesToPath := !proptools.BoolDefault(binary.binaryProperties.Dont_add_top_level_directories_to_path, false)
+	dontAddEntrypointFolderToPath := proptools.BoolDefault(binary.binaryProperties.Dont_add_entrypoint_folder_to_path, false)
+
 	binFile := registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
 		binary.getHostInterpreterName(ctx, actualVersion),
-		main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...))
+		main, binary.getStem(ctx), append(android.Paths{srcsZip}, depsSrcsZips...),
+		addTopDirectoriesToPath, dontAddEntrypointFolderToPath)
 
 	return android.OptionalPathForPath(binFile)
 }
diff --git a/python/builder.go b/python/builder.go
index 7d7239c..f7f9a99 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -20,7 +20,6 @@
 	"strings"
 
 	"android/soong/android"
-
 	"github.com/google/blueprint"
 	_ "github.com/google/blueprint/bootstrap"
 )
@@ -44,13 +43,25 @@
 
 	hostPar = pctx.AndroidStaticRule("hostPar",
 		blueprint.RuleParams{
-			Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' $template > $stub && ` +
+			Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/$main/g' -e 's/ADD_TOP_DIRECTORIES_TO_PATH/$addTopDirectoriesToPath/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` +
 				`echo "#!/usr/bin/env $interp" >${out}.prefix &&` +
-				`$mergeParCmd -p --prefix ${out}.prefix -pm $stub $out $srcsZips && ` +
-				`chmod +x $out && (rm -f $stub; rm -f ${out}.prefix)`,
-			CommandDeps: []string{"$mergeParCmd"},
+				`$mergeParCmd -p --prefix ${out}.prefix -pm $out.main $out $srcsZips && ` +
+				`chmod +x $out && (rm -f $out.main; rm -f ${out}.prefix)`,
+			CommandDeps: []string{"$mergeParCmd", "build/soong/python/scripts/stub_template_host.txt"},
 		},
-		"interp", "main", "template", "stub", "srcsZips")
+		"interp", "main", "srcsZips", "addTopDirectoriesToPath")
+
+	hostParWithoutAddingEntrypointFolderToPath = pctx.AndroidStaticRule("hostParWithoutAddingEntrypointFolderToPath",
+		blueprint.RuleParams{
+			Command: `sed -e 's/%interpreter%/$interp/g' -e 's/%main%/__soong_entrypoint_redirector__.py/g' -e 's/ADD_TOP_DIRECTORIES_TO_PATH/$addTopDirectoriesToPath/g' build/soong/python/scripts/stub_template_host.txt > $out.main && ` +
+				"sed -e 's/ENTRY_POINT/$main/g' build/soong/python/scripts/main_non_embedded.py >`dirname $out`/__soong_entrypoint_redirector__.py && " +
+				"$parCmd -o $out.entrypoint_zip -C `dirname $out` -f `dirname $out`/__soong_entrypoint_redirector__.py && " +
+				`echo "#!/usr/bin/env $interp" >${out}.prefix &&` +
+				`$mergeParCmd -p --prefix ${out}.prefix -pm $out.main $out $srcsZips $out.entrypoint_zip && ` +
+				"chmod +x $out && (rm -f $out.main; rm -f ${out}.prefix; rm -f $out.entrypoint_zip; rm -f `dirname $out`/__soong_entrypoint_redirector__.py)",
+			CommandDeps: []string{"$mergeParCmd", "$parCmd", "build/soong/python/scripts/stub_template_host.txt", "build/soong/python/scripts/main_non_embedded.py"},
+		},
+		"interp", "main", "srcsZips", "addTopDirectoriesToPath")
 
 	embeddedPar = pctx.AndroidStaticRule("embeddedPar",
 		blueprint.RuleParams{
@@ -58,7 +69,7 @@
 				`sed 's/ENTRY_POINT/$main/' build/soong/python/scripts/main.py >$out.main &&` +
 				`$mergeParCmd -p -pm $out.main --prefix $launcher $out $srcsZips && ` +
 				`chmod +x $out && rm -rf $out.main`,
-			CommandDeps: []string{"$mergeParCmd", "$parCmd", "build/soong/python/scripts/main.py"},
+			CommandDeps: []string{"$mergeParCmd", "build/soong/python/scripts/main.py"},
 		},
 		"main", "srcsZips", "launcher")
 
@@ -81,7 +92,7 @@
 
 func registerBuildActionForParFile(ctx android.ModuleContext, embeddedLauncher bool,
 	launcherPath android.OptionalPath, interpreter, main, binName string,
-	srcsZips android.Paths) android.Path {
+	srcsZips android.Paths, addTopDirectoriesToPath bool, dontAddEntrypointFolderToPath bool) android.Path {
 
 	// .intermediate output path for bin executable.
 	binFile := android.PathForModuleOut(ctx, binName)
@@ -90,26 +101,37 @@
 	implicits := srcsZips
 
 	if !embeddedLauncher {
-		// the path of stub_template_host.txt from source tree.
-		template := android.PathForSource(ctx, StubTemplateHost)
-		implicits = append(implicits, template)
-
-		// intermediate output path for __main__.py
-		stub := android.PathForModuleOut(ctx, mainFileName).String()
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        hostPar,
-			Description: "host python archive",
-			Output:      binFile,
-			Implicits:   implicits,
-			Args: map[string]string{
-				"interp":   strings.Replace(interpreter, "/", `\/`, -1),
-				"main":     strings.Replace(main, "/", `\/`, -1),
-				"template": template.String(),
-				"stub":     stub,
-				"srcsZips": strings.Join(srcsZips.Strings(), " "),
-			},
-		})
+		addDirsString := "False"
+		if addTopDirectoriesToPath {
+			addDirsString = "True"
+		}
+		if dontAddEntrypointFolderToPath {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        hostParWithoutAddingEntrypointFolderToPath,
+				Description: "host python archive",
+				Output:      binFile,
+				Implicits:   implicits,
+				Args: map[string]string{
+					"interp":                  strings.Replace(interpreter, "/", `\/`, -1),
+					"main":                    strings.Replace(strings.TrimSuffix(main, pyExt), "/", ".", -1),
+					"srcsZips":                strings.Join(srcsZips.Strings(), " "),
+					"addTopDirectoriesToPath": addDirsString,
+				},
+			})
+		} else {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        hostPar,
+				Description: "host python archive",
+				Output:      binFile,
+				Implicits:   implicits,
+				Args: map[string]string{
+					"interp":                  strings.Replace(interpreter, "/", `\/`, -1),
+					"main":                    strings.Replace(main, "/", `\/`, -1),
+					"srcsZips":                strings.Join(srcsZips.Strings(), " "),
+					"addTopDirectoriesToPath": addDirsString,
+				},
+			})
+		}
 	} else if launcherPath.Valid() {
 		// added launcherPath to the implicits Ninja dependencies.
 		implicits = append(implicits, launcherPath.Path())
diff --git a/python/defaults.go b/python/defaults.go
index dba23a7..c54e7d0 100644
--- a/python/defaults.go
+++ b/python/defaults.go
@@ -31,15 +31,12 @@
 }
 
 func defaultsFactory() android.Module {
-	return DefaultsFactory()
-}
-
-func DefaultsFactory(props ...interface{}) android.Module {
 	module := &Defaults{}
 
-	module.AddProperties(props...)
 	module.AddProperties(
 		&BaseProperties{},
+		&android.ProtoProperties{},
+		&BinaryProperties{},
 	)
 
 	android.InitDefaultsModule(module)
diff --git a/python/python.go b/python/python.go
index 8364169..f6029c2 100644
--- a/python/python.go
+++ b/python/python.go
@@ -120,6 +120,15 @@
 	// whether the binary is required to be built with embedded launcher for this actual_version.
 	// this is set by the python version mutator based on version-specific properties
 	Embedded_launcher *bool `blueprint:"mutated"`
+
+	Proto struct {
+		// Whether generated python protos should include the pkg_path in
+		// their import statements. This is a temporary flag to help transition to
+		// the new behavior where this is always true. It will be removed after all
+		// usages of protos with pkg_path have been updated. The default is currently
+		// false.
+		Respect_pkg_path *bool
+	}
 }
 
 type baseAttributes struct {
@@ -347,10 +356,6 @@
 	protoExt             = ".proto"
 	pyVersion2           = "PY2"
 	pyVersion3           = "PY3"
-	initFileName         = "__init__.py"
-	mainFileName         = "__main__.py"
-	entryPointFile       = "entry_point.txt"
-	parFileExt           = ".zip"
 	internalPath         = "internal"
 )
 
@@ -672,8 +677,26 @@
 		protoFlags := android.GetProtoFlags(ctx, &p.protoProperties)
 		protoFlags.OutTypeFlag = "--python_out"
 
+		// TODO(b/247578564): Change the default to true, and then eventually remove respect_pkg_path
+		protosRespectPkgPath := proptools.BoolDefault(p.properties.Proto.Respect_pkg_path, false)
+		pkgPathForProtos := pkgPath
+		if pkgPathForProtos != "" && protosRespectPkgPath {
+			pkgPathStagingDir := android.PathForModuleGen(ctx, "protos_staged_for_pkg_path")
+			rule := android.NewRuleBuilder(pctx, ctx)
+			var stagedProtoSrcs android.Paths
+			for _, srcFile := range protoSrcs {
+				stagedProtoSrc := pkgPathStagingDir.Join(ctx, pkgPath, srcFile.Rel())
+				rule.Command().Text("mkdir -p").Flag(filepath.Base(stagedProtoSrc.String()))
+				rule.Command().Text("cp -f").Input(srcFile).Output(stagedProtoSrc)
+				stagedProtoSrcs = append(stagedProtoSrcs, stagedProtoSrc)
+			}
+			rule.Build("stage_protos_for_pkg_path", "Stage protos for pkg_path")
+			protoSrcs = stagedProtoSrcs
+			pkgPathForProtos = ""
+		}
+
 		for _, srcFile := range protoSrcs {
-			zip := genProto(ctx, srcFile, protoFlags, pkgPath)
+			zip := genProto(ctx, srcFile, protoFlags, pkgPathForProtos)
 			zips = append(zips, zip)
 		}
 	}
diff --git a/python/python_test.go b/python/python_test.go
index f57f504..42a1ffb 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -300,8 +300,6 @@
 				filepath.Join("dir", "file2.py"):       nil,
 				filepath.Join("dir", "bin.py"):         nil,
 				filepath.Join("dir", "file4.py"):       nil,
-				StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
-				MAIN_FILE = '%main%'`),
 			},
 			expectedBinaries: []pyModule{
 				{
diff --git a/python/scripts/main_non_embedded.py b/python/scripts/main_non_embedded.py
new file mode 100644
index 0000000..ffbaaa8
--- /dev/null
+++ b/python/scripts/main_non_embedded.py
@@ -0,0 +1,6 @@
+import runpy
+
+# The purpose of this file is to implement python 3.11+'s
+# PYTHON_SAFE_PATH / -P option on older python versions.
+
+runpy._run_module_as_main("ENTRY_POINT", alter_argv=False)
diff --git a/python/scripts/stub_template_host.txt b/python/scripts/stub_template_host.txt
index 23897b3..a0ddffe 100644
--- a/python/scripts/stub_template_host.txt
+++ b/python/scripts/stub_template_host.txt
@@ -1,7 +1,6 @@
 #!/usr/bin/env '%interpreter%'
 
 import os
-import re
 import tempfile
 import shutil
 import sys
@@ -15,56 +14,31 @@
 # Don't imply 'import site' on initialization
 PYTHON_ARG = '-S'
 
-def SearchPathEnv(name):
-  search_path = os.getenv('PATH', os.defpath).split(os.pathsep)
-  for directory in search_path:
-    if directory == '': continue
-    path = os.path.join(directory, name)
-    # Check if path is actual executable file.
-    if os.path.isfile(path) and os.access(path, os.X_OK):
-      return path
-  return None
-
-def FindPythonBinary():
-  if PYTHON_BINARY.startswith('/'):
-    # Case 1: Python interpreter is directly provided with absolute path.
-    return PYTHON_BINARY
-  else:
-    # Case 2: Find Python interpreter through environment variable: PATH.
-    return SearchPathEnv(PYTHON_BINARY)
-
-# Create the runfiles tree by extracting the zip file
-def ExtractRunfiles():
-  temp_dir = tempfile.mkdtemp("", "Soong.python_")
-  zf = zipfile.ZipFile(os.path.dirname(__file__))
-  zf.extractall(temp_dir)
-  return temp_dir
-
 def Main():
   args = sys.argv[1:]
 
-  new_env = {}
-  runfiles_path = None
-
+  runfiles_path = tempfile.mkdtemp(prefix="Soong.python_")
   try:
-    runfiles_path = ExtractRunfiles()
+    zf = zipfile.ZipFile(os.path.dirname(__file__))
+    zf.extractall(runfiles_path)
+    zf.close()
 
     # Add runfiles path to PYTHONPATH.
     python_path_entries = [runfiles_path]
 
-    # Add top dirs within runfiles path to PYTHONPATH.
-    top_entries = [os.path.join(runfiles_path, i) for i in os.listdir(runfiles_path)]
-    top_pkg_dirs = [i for i in top_entries if os.path.isdir(i)]
-    python_path_entries += top_pkg_dirs
+    if ADD_TOP_DIRECTORIES_TO_PATH:
+      # Add top dirs within runfiles path to PYTHONPATH.
+      top_entries = [os.path.join(runfiles_path, i) for i in os.listdir(runfiles_path)]
+      top_pkg_dirs = [i for i in top_entries if os.path.isdir(i)]
+      python_path_entries += top_pkg_dirs
 
+    new_python_path = ":".join(python_path_entries)
     old_python_path = os.environ.get(PYTHON_PATH)
-    separator = ':'
-    new_python_path = separator.join(python_path_entries)
 
-    # Copy old PYTHONPATH.
     if old_python_path:
-      new_python_path += separator + old_python_path
-    new_env[PYTHON_PATH] = new_python_path
+      os.environ.update({PYTHON_PATH: new_python_path + ":" + old_python_path})
+    else:
+      os.environ.update({PYTHON_PATH: new_python_path})
 
     # Now look for main python source file.
     main_filepath = os.path.join(runfiles_path, MAIN_FILE)
@@ -73,23 +47,14 @@
     assert os.access(main_filepath, os.R_OK), \
            'Cannot exec() %r: file not readable.' % main_filepath
 
-    python_program = FindPythonBinary()
-    if python_program is None:
-      raise AssertionError('Could not find python binary: ' + PYTHON_BINARY)
-    args = [python_program, PYTHON_ARG, main_filepath] + args
-
-    os.environ.update(new_env)
+    args = [PYTHON_BINARY, PYTHON_ARG, main_filepath] + args
 
     sys.stdout.flush()
     # close_fds=False so that you can run binaries with files provided on the command line:
     # my_python_app --file <(echo foo)
-    retCode = subprocess.call(args, close_fds=False)
-    sys.exit(retCode)
-  except:
-    raise
+    sys.exit(subprocess.call(args, close_fds=False))
   finally:
-    if runfiles_path is not None:
-      shutil.rmtree(runfiles_path, True)
+    shutil.rmtree(runfiles_path, ignore_errors=True)
 
 if __name__ == '__main__':
   Main()
diff --git a/python/tests/dont_import_folder_of_entrypoint/Android.bp b/python/tests/dont_import_folder_of_entrypoint/Android.bp
new file mode 100644
index 0000000..ea5076e
--- /dev/null
+++ b/python/tests/dont_import_folder_of_entrypoint/Android.bp
@@ -0,0 +1,27 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_test_host {
+    name: "py_dont_import_folder_of_entrypoint_test",
+    main: "mypkg/main.py",
+    srcs: [
+        "mypkg/main.py",
+        "mypkg/mymodule.py",
+    ],
+    defaults: ["modern_python_path_defaults"],
+}
+
+python_test_host {
+    name: "py_dont_import_folder_of_entrypoint_test_embedded_launcher",
+    main: "mypkg/main.py",
+    srcs: [
+        "mypkg/main.py",
+        "mypkg/mymodule.py",
+    ],
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
diff --git a/python/tests/dont_import_folder_of_entrypoint/mypkg/main.py b/python/tests/dont_import_folder_of_entrypoint/mypkg/main.py
new file mode 100644
index 0000000..c6a36ed
--- /dev/null
+++ b/python/tests/dont_import_folder_of_entrypoint/mypkg/main.py
@@ -0,0 +1,15 @@
+import unittest
+import sys
+
+class TestProtoWithPkgPath(unittest.TestCase):
+
+    def test_cant_import_mymodule_directly(self):
+        with self.assertRaises(ImportError):
+            import mymodule
+
+    def test_can_import_mymodule_by_parent_package(self):
+        import mypkg.mymodule
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/python/tests/dont_import_folder_of_entrypoint/mypkg/mymodule.py b/python/tests/dont_import_folder_of_entrypoint/mypkg/mymodule.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/tests/dont_import_folder_of_entrypoint/mypkg/mymodule.py
diff --git a/python/tests/proto_pkg_path/Android.bp b/python/tests/proto_pkg_path/Android.bp
new file mode 100644
index 0000000..ef79850
--- /dev/null
+++ b/python/tests/proto_pkg_path/Android.bp
@@ -0,0 +1,17 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_test_host {
+    name: "py_proto_pkg_path_test",
+    main: "main.py",
+    srcs: [
+        "main.py",
+        "proto/*.proto",
+    ],
+    pkg_path: "mylib/subpackage",
+    proto: {
+        canonical_path_from_root: false,
+        respect_pkg_path: true,
+    },
+}
diff --git a/python/tests/proto_pkg_path/main.py b/python/tests/proto_pkg_path/main.py
new file mode 100644
index 0000000..c4acdde
--- /dev/null
+++ b/python/tests/proto_pkg_path/main.py
@@ -0,0 +1,18 @@
+import sys
+
+import unittest
+import mylib.subpackage.proto.test_pb2 as test_pb2
+import mylib.subpackage.proto.common_pb2 as common_pb2
+
+print(sys.path)
+
+class TestProtoWithPkgPath(unittest.TestCase):
+
+    def test_main(self):
+        x = test_pb2.MyMessage(name="foo",
+                               common = common_pb2.MyCommonMessage(common="common"))
+        self.assertEqual(x.name, "foo")
+        self.assertEqual(x.common.common, "common")
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/python/tests/proto_pkg_path/proto/common.proto b/python/tests/proto_pkg_path/proto/common.proto
new file mode 100644
index 0000000..b24b8ea
--- /dev/null
+++ b/python/tests/proto_pkg_path/proto/common.proto
@@ -0,0 +1,5 @@
+syntax = "proto3";
+
+message MyCommonMessage {
+  string common = 1;
+}
diff --git a/python/tests/proto_pkg_path/proto/test.proto b/python/tests/proto_pkg_path/proto/test.proto
new file mode 100644
index 0000000..55f3b17
--- /dev/null
+++ b/python/tests/proto_pkg_path/proto/test.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+
+import "mylib/subpackage/proto/common.proto";
+
+message MyMessage {
+  string name = 1;
+  MyCommonMessage common = 2;
+}
diff --git a/python/tests/top_level_dirs/Android.bp b/python/tests/top_level_dirs/Android.bp
new file mode 100644
index 0000000..fe13d4f
--- /dev/null
+++ b/python/tests/top_level_dirs/Android.bp
@@ -0,0 +1,13 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_test_host {
+    name: "py_dont_add_top_level_dirs_test",
+    main: "main.py",
+    srcs: [
+        "main.py",
+        "mypkg/mymodule.py",
+    ],
+    dont_add_top_level_directories_to_path: true,
+}
diff --git a/python/tests/top_level_dirs/main.py b/python/tests/top_level_dirs/main.py
new file mode 100644
index 0000000..9f30bfa
--- /dev/null
+++ b/python/tests/top_level_dirs/main.py
@@ -0,0 +1,17 @@
+import unittest
+import sys
+
+print(sys.path, file=sys.stderr)
+
+class TestProtoWithPkgPath(unittest.TestCase):
+
+    def test_cant_import_mymodule_directly(self):
+        with self.assertRaises(ImportError):
+            import mymodule
+
+    def test_can_import_mymodule_by_parent_package(self):
+        import mypkg.mymodule
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/python/tests/top_level_dirs/mypkg/mymodule.py b/python/tests/top_level_dirs/mypkg/mymodule.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/tests/top_level_dirs/mypkg/mymodule.py
diff --git a/rust/binary.go b/rust/binary.go
index 41110f9..056888e 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -106,7 +106,7 @@
 		if static {
 			deps.CrtBegin = []string{"libc_musl_crtbegin_static"}
 		} else {
-			deps.CrtBegin = []string{"libc_musl_crtbegin_dynamic", "musl_linker_script"}
+			deps.CrtBegin = []string{"libc_musl_crtbegin_dynamic"}
 		}
 		deps.CrtEnd = []string{"libc_musl_crtend"}
 	}
diff --git a/rust/compiler.go b/rust/compiler.go
index bf6a488..6055158 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -161,7 +161,7 @@
 	// This is primarily meant for rust_binary and rust_ffi modules where the default
 	// linkage of libstd might need to be overridden in some use cases. This should
 	// generally be avoided with other module types since it may cause collisions at
-	// linkage if all dependencies of the root binary module do not link against libstd\
+	// linkage if all dependencies of the root binary module do not link against libstd
 	// the same way.
 	Prefer_rlib *bool `android:"arch_variant"`
 
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index be73d69..79ea7a1 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -15,6 +15,7 @@
         "arm64_device.go",
         "global.go",
         "lints.go",
+        "riscv64_device.go",
         "toolchain.go",
         "darwin_host.go",
         "x86_linux_bionic_host.go",
diff --git a/rust/config/global.go b/rust/config/global.go
index e676837..81aec7e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var pctx = android.NewPackageContext("android/soong/rust/config")
 
 var (
-	RustDefaultVersion = "1.63.0"
+	RustDefaultVersion = "1.64.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/rust/config/riscv64_device.go b/rust/config/riscv64_device.go
new file mode 100644
index 0000000..3b41a10
--- /dev/null
+++ b/rust/config/riscv64_device.go
@@ -0,0 +1,91 @@
+// Copyright 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.
+
+package config
+
+import (
+	"strings"
+
+	"android/soong/android"
+)
+
+var (
+	Riscv64RustFlags            = []string{}
+	Riscv64ArchFeatureRustFlags = map[string][]string{"": {}}
+	Riscv64LinkFlags            = []string{}
+
+	Riscv64ArchVariantRustFlags = map[string][]string{}
+)
+
+func init() {
+	registerToolchainFactory(android.Android, android.Riscv64, Riscv64ToolchainFactory)
+
+	pctx.StaticVariable("Riscv64ToolchainRustFlags", strings.Join(Riscv64RustFlags, " "))
+	pctx.StaticVariable("Riscv64ToolchainLinkFlags", strings.Join(Riscv64LinkFlags, " "))
+
+	for variant, rustFlags := range Riscv64ArchVariantRustFlags {
+		pctx.StaticVariable("Riscv64"+variant+"VariantRustFlags",
+			strings.Join(rustFlags, " "))
+	}
+
+}
+
+type toolchainRiscv64 struct {
+	toolchain64Bit
+	toolchainRustFlags string
+}
+
+func (t *toolchainRiscv64) RustTriple() string {
+	return "riscv64-linux-android"
+}
+
+func (t *toolchainRiscv64) ToolchainLinkFlags() string {
+	// Prepend the lld flags from cc_config so we stay in sync with cc
+	return "${config.DeviceGlobalLinkFlags} ${cc_config.Riscv64Lldflags} ${config.Riscv64ToolchainLinkFlags}"
+}
+
+func (t *toolchainRiscv64) ToolchainRustFlags() string {
+	return t.toolchainRustFlags
+}
+
+func (t *toolchainRiscv64) RustFlags() string {
+	return "${config.Riscv64ToolchainRustFlags}"
+}
+
+func (t *toolchainRiscv64) Supported() bool {
+	return true
+}
+
+func (toolchainRiscv64) LibclangRuntimeLibraryArch() string {
+	return "riscv64"
+}
+
+func Riscv64ToolchainFactory(arch android.Arch) Toolchain {
+	archVariant := arch.ArchVariant
+
+	toolchainRustFlags := []string{
+		"${config.Riscv64ToolchainRustFlags}",
+		"${config.Riscv64" + archVariant + "VariantRustFlags}",
+	}
+
+	toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...)
+
+	for _, feature := range arch.ArchFeatures {
+		toolchainRustFlags = append(toolchainRustFlags, Riscv64ArchFeatureRustFlags[feature]...)
+	}
+
+	return &toolchainRiscv64{
+		toolchainRustFlags: strings.Join(toolchainRustFlags, " "),
+	}
+}
diff --git a/rust/rust.go b/rust/rust.go
index 1517e62..7342a14 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -1615,7 +1615,7 @@
 		}
 	}
 
-	if depTag == procMacroDepTag {
+	if depTag == procMacroDepTag || depTag == customBindgenDepTag {
 		return false
 	}
 
diff --git a/scripts/Android.bp b/scripts/Android.bp
index b5b588b..5dd45cd 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -199,6 +199,17 @@
     ],
 }
 
+python_binary_host {
+    name: "build-apex-bundle",
+    main: "build-apex-bundle.py",
+    srcs: [
+        "build-apex-bundle.py",
+    ],
+    required: [
+        "bundletool",
+    ],
+}
+
 sh_binary_host {
     name: "list_image",
     src: "list_image.sh",
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 3f4f9c0..7b003fd 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,5 +1,4 @@
 per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
-per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
 per-file construct_context.py = ngeoffray@google.com,calin@google.com,skvadrik@google.com
 per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com
-per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
\ No newline at end of file
+per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
deleted file mode 100755
index 1a16f7c..0000000
--- a/scripts/build-aml-prebuilts.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash -e
-
-# This script is similar to "m" but builds in --soong-only mode, and handles
-# special cases to make that mode work. All arguments are passed on to
-# build/soong/soong_ui.bash.
-#
-# --soong-only bypasses the kati step and hence the make logic that e.g. doesn't
-# handle more than two device architectures. It is particularly intended for use
-# with TARGET_PRODUCT=mainline_sdk to build 'sdk' and 'module_export' Soong
-# modules in TARGET_ARCH_SUITE=mainline_sdk mode so that they get all four
-# device architectures (artifacts get installed in $OUT_DIR/soong/mainline-sdks
-# - cf PathForMainlineSdksInstall in android/paths.go).
-#
-# TODO(b/174315599): Replace this script completely with a 'soong_ui.bash
-# --soong-only' invocation. For now it is still necessary to set up
-# build_number.txt.
-
-if [ ! -e build/soong/soong_ui.bash ]; then
-  echo "$0 must be run from the top of the tree"
-  exit 1
-fi
-
-export OUT_DIR=${OUT_DIR:-out}
-
-if [ -e ${OUT_DIR}/soong/.soong.kati_enabled ]; then
-  # If ${OUT_DIR} has been created without --soong-only, Soong will create an
-  # ${OUT_DIR}/soong/build.ninja that leaves out many targets which are
-  # expected to be supplied by the .mk files, and that might cause errors in
-  # "m --soong-only" below. We therefore default to a different out dir
-  # location in that case.
-  AML_OUT_DIR=out/aml
-  echo "Avoiding in-make OUT_DIR '${OUT_DIR}' - building in '${AML_OUT_DIR}' instead"
-  OUT_DIR=${AML_OUT_DIR}
-fi
-
-mkdir -p ${OUT_DIR}/soong
-
-# The --dumpvars-mode invocation will run Soong in normal make mode where it
-# creates .soong.kati_enabled. That would clobber our real out directory, so we
-# need to use a different OUT_DIR.
-vars="$(OUT_DIR=${OUT_DIR}/dumpvars_mode build/soong/soong_ui.bash \
-        --dumpvars-mode --vars=BUILD_NUMBER)"
-# Assign to a variable and eval that, since bash ignores any error status
-# from the command substitution if it's directly on the eval line.
-eval $vars
-
-# Some Soong build rules may require this, and the failure mode if it's missing
-# is confusing (b/172548608).
-echo -n ${BUILD_NUMBER} > ${OUT_DIR}/soong/build_number.txt
-
-build/soong/soong_ui.bash --make-mode --soong-only "$@"
diff --git a/scripts/build-apex-bundle.py b/scripts/build-apex-bundle.py
new file mode 100644
index 0000000..dcdd9ef
--- /dev/null
+++ b/scripts/build-apex-bundle.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""A tool to create an APEX bundle out of Soong-built base.zip"""
+
+from __future__ import print_function
+
+import argparse
+import sys
+import tempfile
+import zipfile
+import os
+import json
+import subprocess
+
+
+def parse_args():
+  """Parse commandline arguments."""
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--overwrite',
+      action='store_true',
+      help='If set, any previous existing output will be overwritten')
+  parser.add_argument('--output', help='specify the output .aab file')
+  parser.add_argument(
+      'input', help='specify the input <apex name>-base.zip file')
+  return parser.parse_args()
+
+
+def build_bundle(input, output, overwrite):
+  base_zip = zipfile.ZipFile(input)
+
+  tmpdir = tempfile.mkdtemp()
+  tmp_base_zip = os.path.join(tmpdir, 'base.zip')
+  tmp_bundle_config = os.path.join(tmpdir, 'bundle_config.json')
+
+  bundle_config = None
+  abi = []
+
+  # This block performs three tasks
+  # - extract/load bundle_config.json from input => bundle_config
+  # - get ABI from input => abi
+  # - discard bundle_config.json from input => tmp/base.zip
+  with zipfile.ZipFile(tmp_base_zip, 'a') as out:
+    for info in base_zip.infolist():
+
+      # discard bundle_config.json
+      if info.filename == 'bundle_config.json':
+        bundle_config = json.load(base_zip.open(info.filename))
+        continue
+
+      # get ABI from apex/{abi}.img
+      dir, basename = os.path.split(info.filename)
+      name, ext = os.path.splitext(basename)
+      if dir == 'apex' and ext == '.img':
+        abi.append(name)
+
+      # copy entries to tmp/base.zip
+      out.writestr(info, base_zip.open(info.filename).read())
+
+  base_zip.close()
+
+  if not bundle_config:
+    raise ValueError(f'bundle_config.json not found in {input}')
+  if len(abi) != 1:
+    raise ValueError(f'{input} should have only a single apex/*.img file')
+
+  # add ABI to tmp/bundle_config.json
+  apex_config = bundle_config['apex_config']
+  if 'supported_abi_set' not in apex_config:
+    apex_config['supported_abi_set'] = []
+  supported_abi_set = apex_config['supported_abi_set']
+  supported_abi_set.append({'abi': abi})
+
+  with open(tmp_bundle_config, 'w') as out:
+    json.dump(bundle_config, out)
+
+  # invoke bundletool
+  cmd = [
+      'bundletool', 'build-bundle', '--config', tmp_bundle_config, '--modules',
+      tmp_base_zip, '--output', output
+  ]
+  if overwrite:
+    cmd.append('--overwrite')
+  subprocess.check_call(cmd)
+
+
+def main():
+  """Program entry point."""
+  try:
+    args = parse_args()
+    build_bundle(args.input, args.output, args.overwrite)
+
+  # pylint: disable=broad-except
+  except Exception as err:
+    print('error: ' + str(err), file=sys.stderr)
+    sys.exit(-1)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
index 07878f9..1e89efe 100644
--- a/scripts/hiddenapi/Android.bp
+++ b/scripts/hiddenapi/Android.bp
@@ -18,29 +18,31 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+python_defaults {
+    name: "hiddenapi_defaults",
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
+
 python_binary_host {
     name: "analyze_bcpf",
     main: "analyze_bcpf.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: ["analyze_bcpf.py"],
     // Make sure that the bpmodify tool is built.
     data: [":bpmodify"],
     libs: [
         "signature_trie",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
 }
 
 python_test_host {
     name: "analyze_bcpf_test",
     main: "analyze_bcpf_test.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: [
         "analyze_bcpf.py",
         "analyze_bcpf_test.py",
@@ -50,15 +52,6 @@
     libs: [
         "signature_trie",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
     test_options: {
         unit_test: true,
     },
@@ -67,49 +60,25 @@
 python_binary_host {
     name: "merge_csv",
     main: "merge_csv.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: ["merge_csv.py"],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
 }
 
 python_binary_host {
     name: "generate_hiddenapi_lists",
     main: "generate_hiddenapi_lists.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: ["generate_hiddenapi_lists.py"],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
 }
 
 python_test_host {
     name: "generate_hiddenapi_lists_test",
     main: "generate_hiddenapi_lists_test.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: [
         "generate_hiddenapi_lists.py",
         "generate_hiddenapi_lists_test.py",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
     test_options: {
         unit_test: true,
     },
@@ -123,17 +92,9 @@
 python_test_host {
     name: "signature_trie_test",
     main: "signature_trie_test.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: ["signature_trie_test.py"],
     libs: ["signature_trie"],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
     test_options: {
         unit_test: true,
     },
@@ -142,24 +103,17 @@
 python_binary_host {
     name: "verify_overlaps",
     main: "verify_overlaps.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: ["verify_overlaps.py"],
     libs: [
         "signature_trie",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
 }
 
 python_test_host {
     name: "verify_overlaps_test",
     main: "verify_overlaps_test.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: [
         "verify_overlaps.py",
         "verify_overlaps_test.py",
@@ -167,15 +121,6 @@
     libs: [
         "signature_trie",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
     test_options: {
         unit_test: true,
     },
@@ -184,34 +129,18 @@
 python_binary_host {
     name: "signature_patterns",
     main: "signature_patterns.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: ["signature_patterns.py"],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
 }
 
 python_test_host {
     name: "signature_patterns_test",
     main: "signature_patterns_test.py",
+    defaults: ["hiddenapi_defaults"],
     srcs: [
         "signature_patterns.py",
         "signature_patterns_test.py",
     ],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-    },
     test_options: {
         unit_test: true,
     },
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index c93055a..4be0ace 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -895,3 +895,222 @@
 		snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
 	)
 }
+
+func testSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T, targetBuildRelease string,
+	expectedSdkSnapshot string,
+	expectedCopyRules string,
+	expectedStubFlagsInputs []string,
+	suffix string) {
+
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("mysdklibrary", "mynewsdklibrary"),
+		java.FixtureConfigureApexBootJars("myapex:mysdklibrary", "myapex:mynewsdklibrary"),
+		prepareForSdkTestWithApex,
+
+		// Add a platform_bootclasspath that depends on the fragment.
+		fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
+
+		android.FixtureMergeEnv(map[string]string{
+			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
+		}),
+
+		android.FixtureWithRootAndroidBp(`
+			sdk {
+				name: "mysdk",
+				apexes: ["myapex"],
+			}
+
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				min_sdk_version: "S",
+				bootclasspath_fragments: ["mybootclasspathfragment"],
+			}
+
+			bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				apex_available: ["myapex"],
+				contents: [
+					"mysdklibrary",
+					"mynewsdklibrary",
+				],
+
+				hidden_api: {
+					split_packages: [],
+				},
+			}
+
+			java_sdk_library {
+				name: "mysdklibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				shared_library: false,
+				public: {enabled: true},
+				min_sdk_version: "S",
+			}
+
+			java_sdk_library {
+				name: "mynewsdklibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				compile_dex: true,
+				public: {enabled: true},
+				min_sdk_version: "Tiramisu",
+				permitted_packages: ["mynewsdklibrary"],
+			}
+		`),
+	).RunTest(t)
+
+	bcpf := result.ModuleForTests("mybootclasspathfragment", "android_common")
+	rule := bcpf.Output("out/soong/.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi" + suffix + "/stub-flags.csv")
+	android.AssertPathsRelativeToTopEquals(t, "stub flags inputs", expectedStubFlagsInputs, rule.Implicits)
+
+	CheckSnapshot(t, result, "mysdk", "",
+		checkAndroidBpContents(expectedSdkSnapshot),
+		checkAllCopyRules(expectedCopyRules),
+	)
+}
+
+func TestSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T) {
+	t.Run("target S build", func(t *testing.T) {
+		expectedSnapshot := `
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_bootclasspath_fragment {
+    name: "mybootclasspathfragment",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    contents: ["mysdklibrary"],
+    hidden_api: {
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        stub_flags: "hiddenapi/stub-flags.csv",
+        all_flags: "hiddenapi/all-flags.csv",
+    },
+}
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+`
+		expectedCopyRules := `
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/stub-flags.csv -> hiddenapi/stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/all-flags.csv -> hiddenapi/all-flags.csv
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+`
+
+		// On S the stub flags should only be generated from mysdklibrary as mynewsdklibrary is not part
+		// of the snapshot.
+		expectedStubFlagsInputs := []string{
+			"out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar",
+			"out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar",
+		}
+
+		testSnapshotWithBootClasspathFragment_MinSdkVersion(t, "S",
+			expectedSnapshot, expectedCopyRules, expectedStubFlagsInputs, "-for-sdk-snapshot")
+	})
+
+	t.Run("target-Tiramisu-build", func(t *testing.T) {
+		expectedSnapshot := `
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_bootclasspath_fragment {
+    name: "mybootclasspathfragment",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    contents: [
+        "mysdklibrary",
+        "mynewsdklibrary",
+    ],
+    hidden_api: {
+        annotation_flags: "hiddenapi/annotation-flags.csv",
+        metadata: "hiddenapi/metadata.csv",
+        index: "hiddenapi/index.csv",
+        signature_patterns: "hiddenapi/signature-patterns.csv",
+        filtered_stub_flags: "hiddenapi/filtered-stub-flags.csv",
+        filtered_flags: "hiddenapi/filtered-flags.csv",
+    },
+}
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+
+java_sdk_library_import {
+    name: "mynewsdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: true,
+    compile_dex: true,
+    permitted_packages: ["mynewsdklibrary"],
+    public: {
+        jars: ["sdk_library/public/mynewsdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mynewsdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mynewsdklibrary.txt",
+        removed_api: "sdk_library/public/mynewsdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+`
+		expectedCopyRules := `
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
+.intermediates/mysdklibrary.stubs/android_common/javac/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mynewsdklibrary.stubs/android_common/javac/mynewsdklibrary.stubs.jar -> sdk_library/public/mynewsdklibrary-stubs.jar
+.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_api.txt -> sdk_library/public/mynewsdklibrary.txt
+.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_removed.txt -> sdk_library/public/mynewsdklibrary-removed.txt
+`
+
+		// On tiramisu the stub flags should be generated from both mynewsdklibrary and mysdklibrary as
+		// they are both part of the snapshot.
+		expectedStubFlagsInputs := []string{
+			"out/soong/.intermediates/mynewsdklibrary.stubs/android_common/dex/mynewsdklibrary.stubs.jar",
+			"out/soong/.intermediates/mynewsdklibrary/android_common/aligned/mynewsdklibrary.jar",
+			"out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar",
+			"out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar",
+		}
+
+		testSnapshotWithBootClasspathFragment_MinSdkVersion(t, "Tiramisu",
+			expectedSnapshot, expectedCopyRules, expectedStubFlagsInputs, "")
+	})
+}
diff --git a/sdk/build_release.go b/sdk/build_release.go
index ac57a32..6bb05a3 100644
--- a/sdk/build_release.go
+++ b/sdk/build_release.go
@@ -100,6 +100,7 @@
 	// Add the dessert build releases from oldest to newest.
 	buildReleaseS = initBuildRelease("S")
 	buildReleaseT = initBuildRelease("Tiramisu")
+	buildReleaseU = initBuildRelease("UpsideDownCake")
 
 	// Add the current build release which is always treated as being more recent than any other
 	// build release, including those added in tests.
diff --git a/sdk/build_release_test.go b/sdk/build_release_test.go
index 13730cb..5bf57b5 100644
--- a/sdk/build_release_test.go
+++ b/sdk/build_release_test.go
@@ -42,7 +42,7 @@
 		android.AssertDeepEquals(t, "release", (*buildRelease)(nil), release)
 		// Uses a wildcard in the error message to allow for additional build releases to be added to
 		// the supported set without breaking this test.
-		android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,F1,F2,current\]`, []error{err})
+		android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,UpsideDownCake,F1,F2,current\]`, []error{err})
 	})
 }
 
@@ -60,7 +60,7 @@
 	t.Run("closed range", func(t *testing.T) {
 		set, err := parseBuildReleaseSet("S-F1")
 		android.AssertDeepEquals(t, "errors", nil, err)
-		android.AssertStringEquals(t, "set", "[S,Tiramisu,F1]", set.String())
+		android.AssertStringEquals(t, "set", "[S,Tiramisu,UpsideDownCake,F1]", set.String())
 	})
 	invalidAReleaseMessage := `unknown release "A", expected one of ` + allBuildReleaseSet.String()
 	t.Run("invalid release", func(t *testing.T) {
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 7ab5285..51903ce3 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -889,6 +889,56 @@
 	)
 }
 
+func TestSnapshotWithJavaSdkLibrary_DistStem(t *testing.T) {
+	result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
+		sdk {
+			name: "mysdk",
+			java_sdk_libs: ["myjavalib-foo"],
+		}
+
+		java_sdk_library {
+			name: "myjavalib-foo",
+			apex_available: ["//apex_available:anyapex"],
+			srcs: ["Test.java"],
+			sdk_version: "current",
+			shared_library: false,
+			public: {
+				enabled: true,
+			},
+			dist_stem: "myjavalib",
+		}
+	`)
+
+	CheckSnapshot(t, result, "mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "myjavalib-foo",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["//apex_available:anyapex"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        sdk_version: "current",
+    },
+}
+`),
+		checkAllCopyRules(`
+.intermediates/myjavalib-foo.stubs/android_common/javac/myjavalib-foo.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+`),
+		checkMergeZips(
+			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
+		),
+	)
+}
+
 func TestSnapshotWithJavaSdkLibrary_UseSrcJar(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForSdkTestWithJavaSdkLibrary,
@@ -1004,7 +1054,7 @@
 		java_sdk_library {
 			name: "myjavalib",
 			srcs: ["Test.java"],
-			sdk_version: "current",
+			sdk_version: "S",
 			shared_library: false,
 			annotations_enabled: true,
 			public: {
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 1ec12c3..2f9aee9 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -218,15 +218,16 @@
 }
 
 type testPropertiesStruct struct {
-	name        string
-	private     string
-	Public_Kept string `sdk:"keep"`
-	S_Common    string
-	S_Different string `android:"arch_variant"`
-	A_Common    []string
-	A_Different []string `android:"arch_variant"`
-	F_Common    *bool
-	F_Different *bool `android:"arch_variant"`
+	name          string
+	private       string
+	Public_Ignore string `sdk:"ignore"`
+	Public_Keep   string `sdk:"keep"`
+	S_Common      string
+	S_Different   string `android:"arch_variant"`
+	A_Common      []string
+	A_Different   []string `android:"arch_variant"`
+	F_Common      *bool
+	F_Different   *bool `android:"arch_variant"`
 	EmbeddedPropertiesStruct
 }
 
@@ -244,30 +245,32 @@
 	common := &testPropertiesStruct{name: "common"}
 	structs := []propertiesContainer{
 		&testPropertiesStruct{
-			name:        "struct-0",
-			private:     "common",
-			Public_Kept: "common",
-			S_Common:    "common",
-			S_Different: "upper",
-			A_Common:    []string{"first", "second"},
-			A_Different: []string{"alpha", "beta"},
-			F_Common:    proptools.BoolPtr(false),
-			F_Different: proptools.BoolPtr(false),
+			name:          "struct-0",
+			private:       "common",
+			Public_Ignore: "common",
+			Public_Keep:   "keep",
+			S_Common:      "common",
+			S_Different:   "upper",
+			A_Common:      []string{"first", "second"},
+			A_Different:   []string{"alpha", "beta"},
+			F_Common:      proptools.BoolPtr(false),
+			F_Different:   proptools.BoolPtr(false),
 			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
 				S_Embedded_Common:    "embedded_common",
 				S_Embedded_Different: "embedded_upper",
 			},
 		},
 		&testPropertiesStruct{
-			name:        "struct-1",
-			private:     "common",
-			Public_Kept: "common",
-			S_Common:    "common",
-			S_Different: "lower",
-			A_Common:    []string{"first", "second"},
-			A_Different: []string{"alpha", "delta"},
-			F_Common:    proptools.BoolPtr(false),
-			F_Different: proptools.BoolPtr(true),
+			name:          "struct-1",
+			private:       "common",
+			Public_Ignore: "common",
+			Public_Keep:   "keep",
+			S_Common:      "common",
+			S_Different:   "lower",
+			A_Common:      []string{"first", "second"},
+			A_Different:   []string{"alpha", "delta"},
+			F_Common:      proptools.BoolPtr(false),
+			F_Different:   proptools.BoolPtr(true),
 			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
 				S_Embedded_Common:    "embedded_common",
 				S_Embedded_Different: "embedded_lower",
@@ -282,15 +285,16 @@
 
 	android.AssertDeepEquals(t, "common properties not correct",
 		&testPropertiesStruct{
-			name:        "common",
-			private:     "",
-			Public_Kept: "",
-			S_Common:    "common",
-			S_Different: "",
-			A_Common:    []string{"first", "second"},
-			A_Different: []string(nil),
-			F_Common:    proptools.BoolPtr(false),
-			F_Different: nil,
+			name:          "common",
+			private:       "",
+			Public_Ignore: "",
+			Public_Keep:   "keep",
+			S_Common:      "common",
+			S_Different:   "",
+			A_Common:      []string{"first", "second"},
+			A_Different:   []string(nil),
+			F_Common:      proptools.BoolPtr(false),
+			F_Different:   nil,
 			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
 				S_Embedded_Common:    "embedded_common",
 				S_Embedded_Different: "",
@@ -300,15 +304,16 @@
 
 	android.AssertDeepEquals(t, "updated properties[0] not correct",
 		&testPropertiesStruct{
-			name:        "struct-0",
-			private:     "common",
-			Public_Kept: "common",
-			S_Common:    "",
-			S_Different: "upper",
-			A_Common:    nil,
-			A_Different: []string{"alpha", "beta"},
-			F_Common:    nil,
-			F_Different: proptools.BoolPtr(false),
+			name:          "struct-0",
+			private:       "common",
+			Public_Ignore: "common",
+			Public_Keep:   "keep",
+			S_Common:      "",
+			S_Different:   "upper",
+			A_Common:      nil,
+			A_Different:   []string{"alpha", "beta"},
+			F_Common:      nil,
+			F_Different:   proptools.BoolPtr(false),
 			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
 				S_Embedded_Common:    "",
 				S_Embedded_Different: "embedded_upper",
@@ -318,15 +323,16 @@
 
 	android.AssertDeepEquals(t, "updated properties[1] not correct",
 		&testPropertiesStruct{
-			name:        "struct-1",
-			private:     "common",
-			Public_Kept: "common",
-			S_Common:    "",
-			S_Different: "lower",
-			A_Common:    nil,
-			A_Different: []string{"alpha", "delta"},
-			F_Common:    nil,
-			F_Different: proptools.BoolPtr(true),
+			name:          "struct-1",
+			private:       "common",
+			Public_Ignore: "common",
+			Public_Keep:   "keep",
+			S_Common:      "",
+			S_Different:   "lower",
+			A_Common:      nil,
+			A_Different:   []string{"alpha", "delta"},
+			F_Common:      nil,
+			F_Different:   proptools.BoolPtr(true),
 			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
 				S_Embedded_Common:    "",
 				S_Embedded_Different: "embedded_lower",
@@ -482,6 +488,7 @@
 				name: "mysdklibrary",
 				srcs: ["Test.java"],
 				compile_dex: true,
+				sdk_version: "S",
 				public: {enabled: true},
 				permitted_packages: ["mysdklibrary"],
 			}
diff --git a/sdk/update.go b/sdk/update.go
index 5c9376b..92a13fa 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -211,11 +211,14 @@
 				container = parent.(android.SdkAware)
 			}
 
+			minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, child)
+
 			export := memberTag.ExportMember()
 			s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
 				sdkVariant:             s,
 				memberType:             memberType,
 				variant:                child.(android.SdkAware),
+				minApiLevel:            minApiLevel,
 				container:              container,
 				export:                 export,
 				exportedComponentsInfo: exportedComponentsInfo,
@@ -332,10 +335,28 @@
 //         <arch>/lib/
 //            libFoo.so   : a stub library
 
+func (s sdk) targetBuildRelease(ctx android.ModuleContext) *buildRelease {
+	config := ctx.Config()
+	targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", buildReleaseCurrent.name)
+	targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv)
+	if err != nil {
+		ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err)
+		targetBuildRelease = buildReleaseCurrent
+	}
+
+	return targetBuildRelease
+}
+
 // buildSnapshot is the main function in this source file. It creates rules to copy
 // the contents (header files, stub libraries, etc) into the zip file.
 func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) {
 
+	targetBuildRelease := s.targetBuildRelease(ctx)
+	targetApiLevel, err := android.ApiLevelFromUser(ctx, targetBuildRelease.name)
+	if err != nil {
+		targetApiLevel = android.FutureApiLevel
+	}
+
 	// Aggregate all the sdkMemberVariantDep instances from all the sdk variants.
 	hasLicenses := false
 	var memberVariantDeps []sdkMemberVariantDep
@@ -346,12 +367,18 @@
 	// Filter out any sdkMemberVariantDep that is a component of another.
 	memberVariantDeps = filterOutComponents(ctx, memberVariantDeps)
 
-	// Record the names of all the members, both explicitly specified and implicitly
-	// included.
+	// Record the names of all the members, both explicitly specified and implicitly included. Also,
+	// record the names of any members that should be excluded from this snapshot.
 	allMembersByName := make(map[string]struct{})
 	exportedMembersByName := make(map[string]struct{})
+	excludedMembersByName := make(map[string]struct{})
 
-	addMember := func(name string, export bool) {
+	addMember := func(name string, export bool, exclude bool) {
+		if exclude {
+			excludedMembersByName[name] = struct{}{}
+			return
+		}
+
 		allMembersByName[name] = struct{}{}
 		if export {
 			exportedMembersByName[name] = struct{}{}
@@ -362,11 +389,15 @@
 		name := memberVariantDep.variant.Name()
 		export := memberVariantDep.export
 
-		addMember(name, export)
+		// If the minApiLevel of the member is greater than the target API level then exclude it from
+		// this snapshot.
+		exclude := memberVariantDep.minApiLevel.GreaterThan(targetApiLevel)
+
+		addMember(name, export, exclude)
 
 		// Add any components provided by the module.
 		for _, component := range memberVariantDep.exportedComponentsInfo.Components {
-			addMember(component, export)
+			addMember(component, export, exclude)
 		}
 
 		if memberVariantDep.memberType == android.LicenseModuleSdkMemberType {
@@ -382,18 +413,9 @@
 		modules: make(map[string]*bpModule),
 	}
 
-	config := ctx.Config()
-
 	// Always add -current to the end
 	snapshotFileSuffix := "-current"
 
-	targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", buildReleaseCurrent.name)
-	targetBuildRelease, err := nameToRelease(targetBuildReleaseEnv)
-	if err != nil {
-		ctx.ModuleErrorf("invalid SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE: %s", err)
-		targetBuildRelease = buildReleaseCurrent
-	}
-
 	builder := &snapshotBuilder{
 		ctx:                   ctx,
 		sdk:                   s,
@@ -404,6 +426,7 @@
 		prebuiltModules:       make(map[string]*bpModule),
 		allMembersByName:      allMembersByName,
 		exportedMembersByName: exportedMembersByName,
+		excludedMembersByName: excludedMembersByName,
 		targetBuildRelease:    targetBuildRelease,
 	}
 	s.builderForTests = builder
@@ -437,6 +460,10 @@
 		}
 
 		name := member.name
+		if _, ok := excludedMembersByName[name]; ok {
+			continue
+		}
+
 		requiredTraits := traits[name]
 		if requiredTraits == nil {
 			requiredTraits = android.EmptySdkMemberTraitSet()
@@ -1034,6 +1061,9 @@
 	// The set of exported members by name.
 	exportedMembersByName map[string]struct{}
 
+	// The set of members which have been excluded from this snapshot; by name.
+	excludedMembersByName map[string]struct{}
+
 	// The target build release for which the snapshot is to be generated.
 	targetBuildRelease *buildRelease
 
@@ -1218,6 +1248,9 @@
 func (s *snapshotBuilder) snapshotSdkMemberNames(members []string, required bool) []string {
 	var references []string = nil
 	for _, m := range members {
+		if _, ok := s.excludedMembersByName[m]; ok {
+			continue
+		}
 		references = append(references, s.snapshotSdkMemberName(m, required))
 	}
 	return references
@@ -1260,6 +1293,9 @@
 
 	// The names of additional component modules provided by the variant.
 	exportedComponentsInfo android.ExportedComponentsInfo
+
+	// The minimum API level on which this module is supported.
+	minApiLevel android.ApiLevel
 }
 
 var _ android.SdkMember = (*sdkMember)(nil)
@@ -2136,6 +2172,11 @@
 	// Retrieves the value on which common value optimization will be performed.
 	getter fieldAccessorFunc
 
+	// True if the field should never be cleared.
+	//
+	// This is set to true if and only if the field is annotated with `sdk:"keep"`.
+	keep bool
+
 	// The empty value for the field.
 	emptyValue reflect.Value
 
@@ -2181,8 +2222,8 @@
 			continue
 		}
 
-		// Ignore fields whose value should be kept.
-		if proptools.HasTag(field, "sdk", "keep") {
+		// Ignore fields tagged with sdk:"ignore".
+		if proptools.HasTag(field, "sdk", "ignore") {
 			continue
 		}
 
@@ -2200,6 +2241,8 @@
 			}
 		}
 
+		keep := proptools.HasTag(field, "sdk", "keep")
+
 		// Save a copy of the field index for use in the function.
 		fieldIndex := f
 
@@ -2239,6 +2282,7 @@
 				name,
 				filter,
 				fieldGetter,
+				keep,
 				reflect.Zero(field.Type),
 				proptools.HasTag(field, "android", "arch_variant"),
 			}
@@ -2358,11 +2402,13 @@
 		if commonValue != nil {
 			emptyValue := property.emptyValue
 			fieldGetter(commonStructValue).Set(*commonValue)
-			for i := 0; i < sliceValue.Len(); i++ {
-				container := sliceValue.Index(i).Interface().(propertiesContainer)
-				itemValue := reflect.ValueOf(container.optimizableProperties())
-				fieldValue := fieldGetter(itemValue)
-				fieldValue.Set(emptyValue)
+			if !property.keep {
+				for i := 0; i < sliceValue.Len(); i++ {
+					container := sliceValue.Index(i).Interface().(propertiesContainer)
+					itemValue := reflect.ValueOf(container.optimizableProperties())
+					fieldValue := fieldGetter(itemValue)
+					fieldValue.Set(emptyValue)
+				}
 			}
 		}
 
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/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
index 6bc0165..61d131b 100755
--- a/tests/apex_comparison_tests.sh
+++ b/tests/apex_comparison_tests.sh
@@ -58,7 +58,7 @@
 ######################
 build/soong/soong_ui.bash --make-mode BP2BUILD_VERBOSE=1 --skip-soong-tests bp2build
 
-BAZEL_OUT="$(call_bazel info output_path)"
+BAZEL_OUT="$(call_bazel info --config=bp2build output_path)"
 
 export TARGET_PRODUCT="module_arm"
 call_bazel build --config=bp2build --config=ci --config=android \
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 78af54d..3cb6c8c 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -114,7 +114,10 @@
   fi
 }
 
+_save_trap=$(trap -p EXIT)
+trap '[[ $? -ne 0 ]] && echo Are you running this locally? Try changing --sandbox_tmpfs_path to something other than /tmp/ in build/bazel/linux.bazelrc.' EXIT
 test_bp2build_generates_all_buildfiles
+eval ${_save_trap}
 
 function test_cc_correctness {
   setup
diff --git a/tests/lib.sh b/tests/lib.sh
index 7248ade..4b4d908 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -123,6 +123,7 @@
   symlink_directory prebuilts/jdk
   symlink_directory external/bazel-skylib
   symlink_directory external/bazelbuild-rules_android
+  symlink_directory external/bazelbuild-rules_license
   symlink_directory external/bazelbuild-kotlin-rules
 
   symlink_file WORKSPACE
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index b408fd3..f6fffad 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -14,7 +14,9 @@
   setup
   create_mock_bazel
 
-  STANDALONE_BAZEL=true run_bazel info
+  run_soong bp2build
+
+  run_bazel info --config=bp2build
 }
 
 test_bazel_smoke
diff --git a/ui/build/build.go b/ui/build/build.go
index 387962b..2022e50 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -245,41 +245,7 @@
 
 	SetupPath(ctx, config)
 
-	what := RunAll
-	if config.Checkbuild() {
-		what |= RunBuildTests
-	}
-	if config.SkipConfig() {
-		ctx.Verboseln("Skipping Config as requested")
-		what = what &^ RunProductConfig
-	}
-	if config.SkipKati() {
-		ctx.Verboseln("Skipping Kati as requested")
-		what = what &^ RunKati
-	}
-	if config.SkipKatiNinja() {
-		ctx.Verboseln("Skipping use of Kati ninja as requested")
-		what = what &^ RunKatiNinja
-	}
-	if config.SkipSoong() {
-		ctx.Verboseln("Skipping use of Soong as requested")
-		what = what &^ RunSoong
-	}
-
-	if config.SkipNinja() {
-		ctx.Verboseln("Skipping Ninja as requested")
-		what = what &^ RunNinja
-	}
-
-	if !config.SoongBuildInvocationNeeded() {
-		// This means that the output of soong_build is not needed and thus it would
-		// run unnecessarily. In addition, if this code wasn't there invocations
-		// with only special-cased target names like "m bp2build" would result in
-		// passing Ninja the empty target list and it would then build the default
-		// targets which is not what the user asked for.
-		what = what &^ RunNinja
-		what = what &^ RunKati
-	}
+	what := evaluateWhatToRun(config, ctx.Verboseln)
 
 	if config.StartGoma() {
 		startGoma(ctx, config)
@@ -355,6 +321,46 @@
 	}
 }
 
+func evaluateWhatToRun(config Config, verboseln func(v ...interface{})) int {
+	//evaluate what to run
+	what := RunAll
+	if config.Checkbuild() {
+		what |= RunBuildTests
+	}
+	if config.SkipConfig() {
+		verboseln("Skipping Config as requested")
+		what = what &^ RunProductConfig
+	}
+	if config.SkipKati() {
+		verboseln("Skipping Kati as requested")
+		what = what &^ RunKati
+	}
+	if config.SkipKatiNinja() {
+		verboseln("Skipping use of Kati ninja as requested")
+		what = what &^ RunKatiNinja
+	}
+	if config.SkipSoong() {
+		verboseln("Skipping use of Soong as requested")
+		what = what &^ RunSoong
+	}
+
+	if config.SkipNinja() {
+		verboseln("Skipping Ninja as requested")
+		what = what &^ RunNinja
+	}
+
+	if !config.SoongBuildInvocationNeeded() {
+		// This means that the output of soong_build is not needed and thus it would
+		// run unnecessarily. In addition, if this code wasn't there invocations
+		// with only special-cased target names like "m bp2build" would result in
+		// passing Ninja the empty target list and it would then build the default
+		// targets which is not what the user asked for.
+		what = what &^ RunNinja
+		what = what &^ RunKati
+	}
+	return what
+}
+
 var distWaitGroup sync.WaitGroup
 
 // waitForDist waits for all backgrounded distGzipFile and distFile writes to finish
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 3ef77c7..ac00fe6 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -381,7 +381,9 @@
 	soongBuildEnv.Set("TOP", os.Getenv("TOP"))
 	// For Bazel mixed builds.
 	soongBuildEnv.Set("BAZEL_PATH", "./tools/bazel")
-	soongBuildEnv.Set("BAZEL_HOME", filepath.Join(config.BazelOutDir(), "bazelhome"))
+	// Bazel's HOME var is set to an output subdirectory which doesn't exist. This
+	// prevents Bazel from file I/O in the actual user HOME directory.
+	soongBuildEnv.Set("BAZEL_HOME", absPath(ctx, filepath.Join(config.BazelOutDir(), "bazelhome")))
 	soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
 	soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
 	soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
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",
+)