Merge "Revert "[soong] Add memtag-stack sanitizer, switch to linker-gen...""
diff --git a/README.md b/README.md
index caffd3d..87d6948 100644
--- a/README.md
+++ b/README.md
@@ -13,8 +13,7 @@
 By design, Android.bp files are very simple.  There are no conditionals or
 control flow statements - any complexity is handled in build logic written in
 Go.  The syntax and semantics of Android.bp files are intentionally similar
-to [Bazel BUILD files](https://www.bazel.io/versions/master/docs/be/overview.html)
-when possible.
+to [Bazel BUILD files](https://bazel.build/concepts/build-files) when possible.
 
 ### Modules
 
@@ -596,14 +595,14 @@
 start the build with `SOONG_DELVE=<listen addr>` in the environment.
 For example:
 ```bash
-SOONG_DELVE=:5006 m nothing
+SOONG_DELVE=5006 m nothing
 ```
 
 To make `soong_ui` wait for a debugger connection, use the `SOONG_UI_DELVE`
 variable:
 
 ```
-SOONG_UI_DELVE=:5006 m nothing
+SOONG_UI_DELVE=5006 m nothing
 ```
 
 
diff --git a/android/Android.bp b/android/Android.bp
index f58a472..e0ad58f 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -38,7 +38,9 @@
         "bazel_paths.go",
         "buildinfo_prop.go",
         "config.go",
+        "test_config.go",
         "config_bp2build.go",
+        "configured_jars.go",
         "csuite_config.go",
         "deapexer.go",
         "defaults.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index aa4363c..8bef725 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -37,150 +37,194 @@
 
 var (
 	Bp2buildDefaultConfig = Bp2BuildConfig{
-		"prebuilts/runtime/mainline/platform/sdk":                Bp2BuildDefaultTrueRecursively,
-		"art/libartpalette":                                      Bp2BuildDefaultTrueRecursively,
-		"art/libartbase":                                         Bp2BuildDefaultTrueRecursively,
-		"art/libdexfile":                                         Bp2BuildDefaultTrueRecursively,
-		"art/libnativebridge":                                    Bp2BuildDefaultTrueRecursively,
-		"art/runtime":                                            Bp2BuildDefaultTrueRecursively,
-		"art/tools":                                              Bp2BuildDefaultTrue,
-		"bionic":                                                 Bp2BuildDefaultTrueRecursively,
-		"bootable/recovery/tools/recovery_l10n":                  Bp2BuildDefaultTrue,
-		"build/bazel/examples/apex/minimal":                      Bp2BuildDefaultTrueRecursively,
-		"build/bazel/examples/soong_config_variables":            Bp2BuildDefaultTrueRecursively,
-		"build/bazel/examples/python":                            Bp2BuildDefaultTrueRecursively,
-		"build/bazel/examples/gensrcs":                           Bp2BuildDefaultTrueRecursively,
-		"build/make/target/product/security":                     Bp2BuildDefaultTrue,
-		"build/make/tools/signapk":                               Bp2BuildDefaultTrue,
-		"build/make/tools/zipalign":                              Bp2BuildDefaultTrueRecursively,
-		"build/soong":                                            Bp2BuildDefaultTrue,
-		"build/soong/cc/libbuildversion":                         Bp2BuildDefaultTrue, // Skip tests subdir
-		"build/soong/cc/ndkstubgen":                              Bp2BuildDefaultTrue,
-		"build/soong/cc/symbolfile":                              Bp2BuildDefaultTrue,
-		"build/soong/linkerconfig":                               Bp2BuildDefaultTrueRecursively,
-		"build/soong/scripts":                                    Bp2BuildDefaultTrueRecursively,
-		"cts/common/device-side/nativetesthelper/jni":            Bp2BuildDefaultTrueRecursively,
-		"development/apps/DevelopmentSettings":                   Bp2BuildDefaultTrue,
-		"development/apps/Fallback":                              Bp2BuildDefaultTrue,
-		"development/apps/WidgetPreview":                         Bp2BuildDefaultTrue,
-		"development/samples/BasicGLSurfaceView":                 Bp2BuildDefaultTrue,
-		"development/samples/BluetoothChat":                      Bp2BuildDefaultTrue,
-		"development/samples/BrokenKeyDerivation":                Bp2BuildDefaultTrue,
-		"development/samples/Compass":                            Bp2BuildDefaultTrue,
-		"development/samples/ContactManager":                     Bp2BuildDefaultTrue,
-		"development/samples/FixedGridLayout":                    Bp2BuildDefaultTrue,
-		"development/samples/HelloEffects":                       Bp2BuildDefaultTrue,
-		"development/samples/Home":                               Bp2BuildDefaultTrue,
-		"development/samples/HoneycombGallery":                   Bp2BuildDefaultTrue,
-		"development/samples/JetBoy":                             Bp2BuildDefaultTrue,
-		"development/samples/KeyChainDemo":                       Bp2BuildDefaultTrue,
-		"development/samples/LceDemo":                            Bp2BuildDefaultTrue,
-		"development/samples/LunarLander":                        Bp2BuildDefaultTrue,
-		"development/samples/MultiResolution":                    Bp2BuildDefaultTrue,
-		"development/samples/MultiWindow":                        Bp2BuildDefaultTrue,
-		"development/samples/NotePad":                            Bp2BuildDefaultTrue,
-		"development/samples/Obb":                                Bp2BuildDefaultTrue,
-		"development/samples/RSSReader":                          Bp2BuildDefaultTrue,
-		"development/samples/ReceiveShareDemo":                   Bp2BuildDefaultTrue,
-		"development/samples/SearchableDictionary":               Bp2BuildDefaultTrue,
-		"development/samples/SipDemo":                            Bp2BuildDefaultTrue,
-		"development/samples/SkeletonApp":                        Bp2BuildDefaultTrue,
-		"development/samples/Snake":                              Bp2BuildDefaultTrue,
-		"development/samples/SpellChecker/":                      Bp2BuildDefaultTrueRecursively,
-		"development/samples/ThemedNavBarKeyboard":               Bp2BuildDefaultTrue,
-		"development/samples/ToyVpn":                             Bp2BuildDefaultTrue,
-		"development/samples/TtsEngine":                          Bp2BuildDefaultTrue,
-		"development/samples/USB/AdbTest":                        Bp2BuildDefaultTrue,
-		"development/samples/USB/MissileLauncher":                Bp2BuildDefaultTrue,
-		"development/samples/VoiceRecognitionService":            Bp2BuildDefaultTrue,
-		"development/samples/VoicemailProviderDemo":              Bp2BuildDefaultTrue,
-		"development/samples/WiFiDirectDemo":                     Bp2BuildDefaultTrue,
-		"development/sdk":                                        Bp2BuildDefaultTrueRecursively,
-		"external/aac":                                           Bp2BuildDefaultTrueRecursively,
-		"external/arm-optimized-routines":                        Bp2BuildDefaultTrueRecursively,
-		"external/auto/android-annotation-stubs":                 Bp2BuildDefaultTrueRecursively,
-		"external/auto/common":                                   Bp2BuildDefaultTrueRecursively,
-		"external/auto/service":                                  Bp2BuildDefaultTrueRecursively,
-		"external/boringssl":                                     Bp2BuildDefaultTrueRecursively,
-		"external/bouncycastle":                                  Bp2BuildDefaultTrue,
-		"external/brotli":                                        Bp2BuildDefaultTrue,
-		"external/conscrypt":                                     Bp2BuildDefaultTrue,
-		"external/e2fsprogs":                                     Bp2BuildDefaultTrueRecursively,
-		"external/eigen":                                         Bp2BuildDefaultTrueRecursively,
-		"external/erofs-utils":                                   Bp2BuildDefaultTrueRecursively,
-		"external/error_prone":                                   Bp2BuildDefaultTrueRecursively,
-		"external/expat":                                         Bp2BuildDefaultTrueRecursively,
-		"external/f2fs-tools":                                    Bp2BuildDefaultTrue,
-		"external/flac":                                          Bp2BuildDefaultTrueRecursively,
-		"external/fmtlib":                                        Bp2BuildDefaultTrueRecursively,
-		"external/google-benchmark":                              Bp2BuildDefaultTrueRecursively,
-		"external/googletest":                                    Bp2BuildDefaultTrueRecursively,
-		"external/gwp_asan":                                      Bp2BuildDefaultTrueRecursively,
-		"external/hamcrest":                                      Bp2BuildDefaultTrueRecursively,
-		"external/icu":                                           Bp2BuildDefaultTrueRecursively,
-		"external/icu/android_icu4j":                             Bp2BuildDefaultFalse, // java rules incomplete
-		"external/icu/icu4j":                                     Bp2BuildDefaultFalse, // java rules incomplete
-		"external/jarjar":                                        Bp2BuildDefaultTrueRecursively,
-		"external/javapoet":                                      Bp2BuildDefaultTrueRecursively,
-		"external/jemalloc_new":                                  Bp2BuildDefaultTrueRecursively,
-		"external/jsoncpp":                                       Bp2BuildDefaultTrueRecursively,
-		"external/junit":                                         Bp2BuildDefaultTrueRecursively,
-		"external/libavc":                                        Bp2BuildDefaultTrueRecursively,
-		"external/libcap":                                        Bp2BuildDefaultTrueRecursively,
-		"external/libcxx":                                        Bp2BuildDefaultTrueRecursively,
-		"external/libcxxabi":                                     Bp2BuildDefaultTrueRecursively,
-		"external/libevent":                                      Bp2BuildDefaultTrueRecursively,
-		"external/libgav1":                                       Bp2BuildDefaultTrueRecursively,
-		"external/libhevc":                                       Bp2BuildDefaultTrueRecursively,
-		"external/libmpeg2":                                      Bp2BuildDefaultTrueRecursively,
-		"external/libpng":                                        Bp2BuildDefaultTrueRecursively,
-		"external/lz4/lib":                                       Bp2BuildDefaultTrue,
-		"external/lzma/C":                                        Bp2BuildDefaultTrueRecursively,
-		"external/mdnsresponder":                                 Bp2BuildDefaultTrueRecursively,
-		"external/minijail":                                      Bp2BuildDefaultTrueRecursively,
-		"external/pcre":                                          Bp2BuildDefaultTrueRecursively,
-		"external/protobuf":                                      Bp2BuildDefaultTrueRecursively,
-		"external/python/six":                                    Bp2BuildDefaultTrueRecursively,
-		"external/rappor":                                        Bp2BuildDefaultTrueRecursively,
-		"external/scudo":                                         Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libselinux":                            Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libsepol":                              Bp2BuildDefaultTrueRecursively,
-		"external/zlib":                                          Bp2BuildDefaultTrueRecursively,
-		"external/zopfli":                                        Bp2BuildDefaultTrueRecursively,
-		"external/zstd":                                          Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/codecs":                             Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/services/minijail":                        Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/media/tests/MediaDump":                  Bp2BuildDefaultTrue,
-		"frameworks/base/startop/apps/test":                      Bp2BuildDefaultTrue,
-		"frameworks/base/tests/appwidgets/AppWidgetHostTest":     Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/adbd_auth":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/arect":                           Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/math":                            Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/nativebase":                      Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/opengl/tests/gl2_cameraeye":           Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/gl2_java":                Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testLatency":             Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testPauseResume":         Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testViewport":            Bp2BuildDefaultTrue,
-		"frameworks/proto_logging/stats/stats_log_api_gen":       Bp2BuildDefaultTrueRecursively,
-		"libnativehelper":                                        Bp2BuildDefaultTrueRecursively,
-		"packages/apps/DevCamera":                                Bp2BuildDefaultTrue,
-		"packages/apps/HTMLViewer":                               Bp2BuildDefaultTrue,
-		"packages/apps/Protips":                                  Bp2BuildDefaultTrue,
-		"packages/modules/StatsD/lib/libstatssocket":             Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb":                                   Bp2BuildDefaultTrue,
-		"packages/modules/adb/apex":                              Bp2BuildDefaultTrue,
-		"packages/modules/adb/crypto":                            Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/libs":                              Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_auth":                      Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_connection":                Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/proto":                             Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/tls":                               Bp2BuildDefaultTrueRecursively,
-		"packages/providers/MediaProvider/tools/dialogs":         Bp2BuildDefaultTrue,
-		"packages/screensavers/Basic":                            Bp2BuildDefaultTrue,
-		"packages/services/Car/tests/SampleRearViewCamera":       Bp2BuildDefaultTrue,
-		"prebuilts/clang/host/linux-x86":                         Bp2BuildDefaultTrueRecursively,
-		"prebuilts/tools/common/m2":                              Bp2BuildDefaultTrue,
+		"art/libartpalette":                     Bp2BuildDefaultTrueRecursively,
+		"art/libartbase":                        Bp2BuildDefaultTrueRecursively,
+		"art/libdexfile":                        Bp2BuildDefaultTrueRecursively,
+		"art/libnativebridge":                   Bp2BuildDefaultTrueRecursively,
+		"art/runtime":                           Bp2BuildDefaultTrueRecursively,
+		"art/tools":                             Bp2BuildDefaultTrue,
+		"bionic":                                Bp2BuildDefaultTrueRecursively,
+		"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
+
+		"build/bazel":                        Bp2BuildDefaultTrueRecursively,
+		"build/make/target/product/security": Bp2BuildDefaultTrue,
+		"build/make/tools/signapk":           Bp2BuildDefaultTrue,
+		"build/make/tools/zipalign":          Bp2BuildDefaultTrueRecursively,
+		"build/soong":                        Bp2BuildDefaultTrue,
+		"build/soong/cc/libbuildversion":     Bp2BuildDefaultTrue, // Skip tests subdir
+		"build/soong/cc/ndkstubgen":          Bp2BuildDefaultTrue,
+		"build/soong/cc/symbolfile":          Bp2BuildDefaultTrue,
+		"build/soong/linkerconfig":           Bp2BuildDefaultTrueRecursively,
+		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
+
+		"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
+		"development/apps/DevelopmentSettings":        Bp2BuildDefaultTrue,
+		"development/apps/Fallback":                   Bp2BuildDefaultTrue,
+		"development/apps/WidgetPreview":              Bp2BuildDefaultTrue,
+		"development/samples/BasicGLSurfaceView":      Bp2BuildDefaultTrue,
+		"development/samples/BluetoothChat":           Bp2BuildDefaultTrue,
+		"development/samples/BrokenKeyDerivation":     Bp2BuildDefaultTrue,
+		"development/samples/Compass":                 Bp2BuildDefaultTrue,
+		"development/samples/ContactManager":          Bp2BuildDefaultTrue,
+		"development/samples/FixedGridLayout":         Bp2BuildDefaultTrue,
+		"development/samples/HelloEffects":            Bp2BuildDefaultTrue,
+		"development/samples/Home":                    Bp2BuildDefaultTrue,
+		"development/samples/HoneycombGallery":        Bp2BuildDefaultTrue,
+		"development/samples/JetBoy":                  Bp2BuildDefaultTrue,
+		"development/samples/KeyChainDemo":            Bp2BuildDefaultTrue,
+		"development/samples/LceDemo":                 Bp2BuildDefaultTrue,
+		"development/samples/LunarLander":             Bp2BuildDefaultTrue,
+		"development/samples/MultiResolution":         Bp2BuildDefaultTrue,
+		"development/samples/MultiWindow":             Bp2BuildDefaultTrue,
+		"development/samples/NotePad":                 Bp2BuildDefaultTrue,
+		"development/samples/Obb":                     Bp2BuildDefaultTrue,
+		"development/samples/RSSReader":               Bp2BuildDefaultTrue,
+		"development/samples/ReceiveShareDemo":        Bp2BuildDefaultTrue,
+		"development/samples/SearchableDictionary":    Bp2BuildDefaultTrue,
+		"development/samples/SipDemo":                 Bp2BuildDefaultTrue,
+		"development/samples/SkeletonApp":             Bp2BuildDefaultTrue,
+		"development/samples/Snake":                   Bp2BuildDefaultTrue,
+		"development/samples/SpellChecker/":           Bp2BuildDefaultTrueRecursively,
+		"development/samples/ThemedNavBarKeyboard":    Bp2BuildDefaultTrue,
+		"development/samples/ToyVpn":                  Bp2BuildDefaultTrue,
+		"development/samples/TtsEngine":               Bp2BuildDefaultTrue,
+		"development/samples/USB/AdbTest":             Bp2BuildDefaultTrue,
+		"development/samples/USB/MissileLauncher":     Bp2BuildDefaultTrue,
+		"development/samples/VoiceRecognitionService": Bp2BuildDefaultTrue,
+		"development/samples/VoicemailProviderDemo":   Bp2BuildDefaultTrue,
+		"development/samples/WiFiDirectDemo":          Bp2BuildDefaultTrue,
+		"development/sdk":                             Bp2BuildDefaultTrueRecursively,
+
+		"external/aac":                           Bp2BuildDefaultTrueRecursively,
+		"external/arm-optimized-routines":        Bp2BuildDefaultTrueRecursively,
+		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
+		"external/auto/common":                   Bp2BuildDefaultTrueRecursively,
+		"external/auto/service":                  Bp2BuildDefaultTrueRecursively,
+		"external/boringssl":                     Bp2BuildDefaultTrueRecursively,
+		"external/bouncycastle":                  Bp2BuildDefaultTrue,
+		"external/brotli":                        Bp2BuildDefaultTrue,
+		"external/conscrypt":                     Bp2BuildDefaultTrue,
+		"external/e2fsprogs":                     Bp2BuildDefaultTrueRecursively,
+		"external/eigen":                         Bp2BuildDefaultTrueRecursively,
+		"external/erofs-utils":                   Bp2BuildDefaultTrueRecursively,
+		"external/error_prone":                   Bp2BuildDefaultTrueRecursively,
+		"external/expat":                         Bp2BuildDefaultTrueRecursively,
+		"external/f2fs-tools":                    Bp2BuildDefaultTrue,
+		"external/flac":                          Bp2BuildDefaultTrueRecursively,
+		"external/fmtlib":                        Bp2BuildDefaultTrueRecursively,
+		"external/google-benchmark":              Bp2BuildDefaultTrueRecursively,
+		"external/googletest":                    Bp2BuildDefaultTrueRecursively,
+		"external/gwp_asan":                      Bp2BuildDefaultTrueRecursively,
+		"external/hamcrest":                      Bp2BuildDefaultTrueRecursively,
+		"external/icu":                           Bp2BuildDefaultTrueRecursively,
+		"external/icu/android_icu4j":             Bp2BuildDefaultFalse, // java rules incomplete
+		"external/icu/icu4j":                     Bp2BuildDefaultFalse, // java rules incomplete
+		"external/jarjar":                        Bp2BuildDefaultTrueRecursively,
+		"external/javapoet":                      Bp2BuildDefaultTrueRecursively,
+		"external/jemalloc_new":                  Bp2BuildDefaultTrueRecursively,
+		"external/jsoncpp":                       Bp2BuildDefaultTrueRecursively,
+		"external/junit":                         Bp2BuildDefaultTrueRecursively,
+		"external/libavc":                        Bp2BuildDefaultTrueRecursively,
+		"external/libcap":                        Bp2BuildDefaultTrueRecursively,
+		"external/libcxx":                        Bp2BuildDefaultTrueRecursively,
+		"external/libcxxabi":                     Bp2BuildDefaultTrueRecursively,
+		"external/libevent":                      Bp2BuildDefaultTrueRecursively,
+		"external/libgav1":                       Bp2BuildDefaultTrueRecursively,
+		"external/libhevc":                       Bp2BuildDefaultTrueRecursively,
+		"external/libjpeg-turbo":                 Bp2BuildDefaultTrueRecursively,
+		"external/libmpeg2":                      Bp2BuildDefaultTrueRecursively,
+		"external/libpng":                        Bp2BuildDefaultTrueRecursively,
+		"external/libyuv":                        Bp2BuildDefaultTrueRecursively,
+		"external/lz4/lib":                       Bp2BuildDefaultTrue,
+		"external/lzma/C":                        Bp2BuildDefaultTrueRecursively,
+		"external/mdnsresponder":                 Bp2BuildDefaultTrueRecursively,
+		"external/minijail":                      Bp2BuildDefaultTrueRecursively,
+		"external/pcre":                          Bp2BuildDefaultTrueRecursively,
+		"external/protobuf":                      Bp2BuildDefaultTrueRecursively,
+		"external/python/six":                    Bp2BuildDefaultTrueRecursively,
+		"external/rappor":                        Bp2BuildDefaultTrueRecursively,
+		"external/scudo":                         Bp2BuildDefaultTrueRecursively,
+		"external/selinux/libselinux":            Bp2BuildDefaultTrueRecursively,
+		"external/selinux/libsepol":              Bp2BuildDefaultTrueRecursively,
+		"external/speex":                         Bp2BuildDefaultTrueRecursively,
+		"external/toybox":                        Bp2BuildDefaultTrueRecursively,
+		"external/zlib":                          Bp2BuildDefaultTrueRecursively,
+		"external/zopfli":                        Bp2BuildDefaultTrueRecursively,
+		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
+
+		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
+		"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/native/libs/adbd_auth":                   Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/arect":                       Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/math":                        Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/common/aidl":                    Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/aidl":           Bp2BuildDefaultTrue,
+		"hardware/interfaces/neuralnetworks/aidl":            Bp2BuildDefaultTrue,
+		"frameworks/native/libs/nativebase":                  Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/opengl/tests/gl2_cameraeye":       Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/gl2_java":            Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/testLatency":         Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/testPauseResume":     Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/testViewport":        Bp2BuildDefaultTrue,
+		"frameworks/proto_logging/stats/stats_log_api_gen":   Bp2BuildDefaultTrueRecursively,
+
+		"hardware/interfaces":                          Bp2BuildDefaultTrue,
+		"hardware/interfaces/configstore/1.0":          Bp2BuildDefaultTrue,
+		"hardware/interfaces/configstore/1.1":          Bp2BuildDefaultTrue,
+		"hardware/interfaces/configstore/utils":        Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/2.0":   Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/3.0":   Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/allocator/4.0":   Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/bufferqueue/1.0": Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/bufferqueue/2.0": Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/1.0":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/1.1":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/common/1.2":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/2.0":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/2.1":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/3.0":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/graphics/mapper/4.0":      Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/1.0":                Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/bufferpool/2.0":     Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/c2/1.0":             Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/c2/1.1":             Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/c2/1.2":             Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/omx/1.0":            Bp2BuildDefaultTrue,
+		"hardware/interfaces/neuralnetworks/1.0":       Bp2BuildDefaultTrue,
+		"hardware/interfaces/neuralnetworks/1.1":       Bp2BuildDefaultTrue,
+		"hardware/interfaces/neuralnetworks/1.2":       Bp2BuildDefaultTrue,
+		"hardware/interfaces/neuralnetworks/1.3":       Bp2BuildDefaultTrue,
+
+		"libnativehelper": Bp2BuildDefaultTrueRecursively,
+
+		"packages/apps/DevCamera":                          Bp2BuildDefaultTrue,
+		"packages/apps/HTMLViewer":                         Bp2BuildDefaultTrue,
+		"packages/apps/Protips":                            Bp2BuildDefaultTrue,
+		"packages/apps/WallpaperPicker":                    Bp2BuildDefaultTrue,
+		"packages/modules/StatsD/lib/libstatssocket":       Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb":                             Bp2BuildDefaultTrue,
+		"packages/modules/adb/apex":                        Bp2BuildDefaultTrue,
+		"packages/modules/adb/crypto":                      Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/libs":                        Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/pairing_auth":                Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/pairing_connection":          Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/proto":                       Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/tls":                         Bp2BuildDefaultTrueRecursively,
+		"packages/providers/MediaProvider/tools/dialogs":   Bp2BuildDefaultFalse, // TODO(b/242834374)
+		"packages/screensavers/Basic":                      Bp2BuildDefaultTrue,
+		"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
+
+		"prebuilts/clang/host/linux-x86":           Bp2BuildDefaultTrueRecursively,
+		"prebuilts/runtime/mainline/platform/sdk":  Bp2BuildDefaultTrueRecursively,
+		"prebuilts/sdk/current/extras/app-toolkit": Bp2BuildDefaultTrue,
+		"prebuilts/sdk/current/support":            Bp2BuildDefaultTrue,
+		"prebuilts/tools/common/m2":                Bp2BuildDefaultTrue,
+
 		"system/apex":                                            Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
 		"system/apex/apexer":                                     Bp2BuildDefaultTrue,
 		"system/apex/libs":                                       Bp2BuildDefaultTrueRecursively,
@@ -203,11 +247,24 @@
 		"system/libartpalette":                                   Bp2BuildDefaultTrueRecursively,
 		"system/libbase":                                         Bp2BuildDefaultTrueRecursively,
 		"system/libfmq":                                          Bp2BuildDefaultTrue,
+		"system/libhidl/libhidlmemory":                           Bp2BuildDefaultTrue,
+		"system/libhidl/transport":                               Bp2BuildDefaultTrue,
+		"system/libhidl/transport/allocator/1.0":                 Bp2BuildDefaultTrue,
+		"system/libhidl/transport/base/1.0":                      Bp2BuildDefaultTrue,
+		"system/libhidl/transport/manager/1.0":                   Bp2BuildDefaultTrue,
+		"system/libhidl/transport/manager/1.1":                   Bp2BuildDefaultTrue,
+		"system/libhidl/transport/manager/1.2":                   Bp2BuildDefaultTrue,
+		"system/libhidl/transport/memory/1.0":                    Bp2BuildDefaultTrue,
+		"system/libhidl/transport/memory/token/1.0":              Bp2BuildDefaultTrue,
+		"system/libhidl/transport/safe_union/1.0":                Bp2BuildDefaultTrue,
+		"system/libhidl/transport/token/1.0":                     Bp2BuildDefaultTrue,
+		"system/libhidl/transport/token/1.0/utils":               Bp2BuildDefaultTrue,
 		"system/libhwbinder":                                     Bp2BuildDefaultTrueRecursively,
 		"system/libprocinfo":                                     Bp2BuildDefaultTrue,
 		"system/libziparchive":                                   Bp2BuildDefaultTrueRecursively,
 		"system/logging/liblog":                                  Bp2BuildDefaultTrueRecursively,
 		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
+		"system/media/audio_utils":                               Bp2BuildDefaultTrueRecursively,
 		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
 		"system/memory/libmemunreachable":                        Bp2BuildDefaultTrueRecursively,
 		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
@@ -215,35 +272,22 @@
 		"system/timezone/output_data":                            Bp2BuildDefaultTrueRecursively,
 		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/unwinding/libunwindstack":                        Bp2BuildDefaultTrueRecursively,
-		"tools/apksig":                                           Bp2BuildDefaultTrue,
-		"tools/platform-compat/java/android/compat":              Bp2BuildDefaultTrueRecursively,
+
+		"tools/apksig": Bp2BuildDefaultTrue,
+		"tools/platform-compat/java/android/compat":  Bp2BuildDefaultTrueRecursively,
+		"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
 	}
 
 	Bp2buildKeepExistingBuildFile = map[string]bool{
 		// This is actually build/bazel/build.BAZEL symlinked to ./BUILD
 		".":/*recursive = */ false,
 
-		// build/bazel/examples/apex/... BUILD files should be generated, so
-		// build/bazel is not recursive. Instead list each subdirectory under
-		// build/bazel explicitly.
-		"build/bazel":/* recursive = */ false,
-		"build/bazel/ci/dist":/* recursive = */ false,
-		"build/bazel/examples/android_app":/* recursive = */ true,
-		"build/bazel/examples/java":/* recursive = */ true,
-		"build/bazel/examples/partitions":/* recursive = */ true,
-		"build/bazel/bazel_skylib":/* recursive = */ true,
-		"build/bazel/rules":/* recursive = */ true,
-		"build/bazel/rules_cc":/* recursive = */ true,
-		"build/bazel/scripts":/* recursive = */ true,
-		"build/bazel/tests":/* recursive = */ true,
-		"build/bazel/platforms":/* recursive = */ true,
-		"build/bazel/product_config":/* recursive = */ true,
-		"build/bazel/product_variables":/* recursive = */ true,
-		"build/bazel/vendor/google":/* recursive = */ true,
+		"build/bazel":/* recursive = */ true,
 		"build/bazel_common_rules":/* recursive = */ true,
 		// 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,
 
 		// 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
@@ -255,16 +299,14 @@
 
 		"packages/apps/Music":/* recursive = */ true,
 		"packages/apps/QuickSearchBox":/* recursive = */ true,
-		"packages/apps/WallpaperPicker":/* recursive = */ false,
 
 		"prebuilts/bazel":/* recursive = */ true,
 		"prebuilts/bundletool":/* recursive = */ true,
 		"prebuilts/gcc":/* recursive = */ true,
 		"prebuilts/build-tools":/* recursive = */ true,
 		"prebuilts/jdk/jdk11":/* recursive = */ false,
+		"prebuilts/misc":/* recursive = */ false, // not recursive because we need bp2build converted build files in prebuilts/misc/common/asm
 		"prebuilts/sdk":/* recursive = */ false,
-		"prebuilts/sdk/current/extras/app-toolkit":/* recursive = */ false,
-		"prebuilts/sdk/current/support":/* recursive = */ false,
 		"prebuilts/sdk/tools":/* recursive = */ false,
 		"prebuilts/r8":/* recursive = */ false,
 	}
@@ -288,7 +330,9 @@
 		"libandroid_runtime_lazy",
 		"libandroid_runtime_vm_headers",
 		"libaudioclient_aidl_conversion_util",
-		"libaudioutils_fixedfft",
+		"libbinder",
+		"libbinder_device_interface_sources",
+		"libbinder_aidl",
 		"libbinder_headers",
 		"libbinder_headers_platform_shared",
 		"libbluetooth-types-header",
@@ -310,6 +354,8 @@
 		"libpdx_headers",
 		"libprocpartition",
 		"libruy_static",
+		"libandroidio",
+		"libandroidio_srcs",
 		"libserviceutils",
 		"libstagefright_enc_common",
 		"libstagefright_foundation_headers",
@@ -332,6 +378,13 @@
 		"server_configurable_flags",
 		"tensorflow_headers",
 
+		// fastboot
+		"bootimg_headers",
+		"fastboot",
+		"libfastboot",
+		"liblp",
+		"libstorage_literals_headers",
+
 		//external/avb
 		"avbtool",
 		"libavb",
@@ -363,12 +416,27 @@
 		"car-ui-androidx-core-common-nodeps",
 		"car-ui-androidx-lifecycle-common-nodeps",
 		"car-ui-androidx-constraintlayout-solver-nodeps",
+
+		//system/libhidl
+		// needed by cc_hidl_library
+		"libhidlbase",
+
+		//frameworks/native
+		"framework_native_aidl_binder",
+		"framework_native_aidl_gui",
+
+		//frameworks/native/libs/input
+		"inputconstants_aidl",
+
+		// needed for aidl_interface's ndk backend
+		"libbinder_ndk",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
 		"linker_config",
 		"java_import",
 		"java_import_host",
+		"aidl_interface_headers",
 	}
 
 	Bp2buildModuleDoNotConvertList = []string{
@@ -377,15 +445,15 @@
 		"gen-kotlin-build-file.py",                  // TODO(b/198619163) module has same name as source
 		"libgtest_ndk_c++", "libgtest_main_ndk_c++", // TODO(b/201816222): Requires sdk_version support.
 		"linkerconfig", "mdnsd", // TODO(b/202876379): has arch-variant static_executable
-		"linker",            // TODO(b/228316882): cc_binary uses link_crt
-		"libdebuggerd",      // TODO(b/228314770): support product variable-specific header_libs
-		"versioner",         // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
-		"libspeexresampler", // TODO(b/231995978): Filter out unknown cflags
-		"libjpeg", "libvpx", // TODO(b/233948256): Convert .asm files
+		"linker",                 // TODO(b/228316882): cc_binary uses link_crt
+		"libdebuggerd",           // TODO(b/228314770): support product variable-specific header_libs
+		"versioner",              // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
+		"libvpx",                 // TODO(b/240756936): Arm neon variant not supported
 		"art_libartbase_headers", // TODO(b/236268577): Header libraries do not support export_shared_libs_headers
 		"apexer_test",            // Requires aapt2
 		"apexer_test_host_tools",
 		"host_apex_verifier",
+		"tjbench", // TODO(b/240563612): Stem property
 
 		// java bugs
 		"libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
@@ -447,15 +515,16 @@
 		"generated_android_icu4j_test_resources",                     // depends on unconverted modules: android_icu4j_srcgen_binary, soong_zip
 		"host-libprotobuf-java-nano",                                 // b/220869005, depends on libprotobuf-java-nano
 		"libadb_host",                                                // depends on unconverted modules: AdbWinApi, libopenscreen-discovery, libopenscreen-platform-impl, libusb
+		"libapexutil",                                                // depends on unconverted modules: apex-info-list-tinyxml
 		"libart",                                                     // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
 		"libart-runtime-gtest",                                       // depends on unconverted modules: libgtest_isolated, libart-compiler, libdexfile, libprofile, libartbase, libartbase-art-gtest
 		"libart_headers",                                             // depends on unconverted modules: art_libartbase_headers
+		"libartbase-art-gtest",                                       // depends on unconverted modules: libgtest_isolated, libart, libart-compiler, libdexfile, libprofile
+		"libartbased-art-gtest",                                      // depends on unconverted modules: libgtest_isolated, libartd, libartd-compiler, libdexfiled, libprofiled
 		"libartd",                                                    // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api
 		"libartd-runtime-gtest",                                      // depends on unconverted modules: libgtest_isolated, libartd-compiler, libdexfiled, libprofiled, libartbased, libartbased-art-gtest
 		"libdebuggerd_handler",                                       // depends on unconverted module libdebuggerd_handler_core
 		"libdebuggerd_handler_core", "libdebuggerd_handler_fallback", // depends on unconverted module libdebuggerd
-		"libdexfile",                                              // depends on unconverted modules: dexfile_operator_srcs, libartbase, libartpalette,
-		"libdexfile_static",                                       // depends on unconverted modules: libartbase, libdexfile
 		"libdexfiled",                                             // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette
 		"libfastdeploy_host",                                      // depends on unconverted modules: libandroidfw, libusb, AdbWinApi
 		"libgmock_main_ndk",                                       // depends on unconverted modules: libgtest_ndk_c++
@@ -463,7 +532,7 @@
 		"libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libnativetesthelper_jni, libgmock_ndk
 		"libnativetesthelper_jni",   // depends on unconverted modules: libgtest_ndk_c++
 		"libprotobuf-java-nano",     // b/220869005, depends on non-public_current SDK
-		"libstatslog",               // depends on unconverted modules: libstatspull, statsd-aidl-ndk, libbinder_ndk
+		"libstatslog",               // depends on unconverted modules: libstatspull, statsd-aidl-ndk
 		"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
@@ -472,15 +541,35 @@
 		"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
-		"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
-		"libartbase-art-gtest",  // depends on unconverted modules: libgtest_isolated, libart, libart-compiler, libdexfile, libprofile
-		"libartbased-art-gtest", // depends on unconverted modules: libgtest_isolated, libartd, libartd-compiler, libdexfiled, libprofiled
+		"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
 
 		// b/215723302; awaiting tz{data,_version} to then rename targets conflicting with srcs
 		"tzdata",
 		"tz_version",
+
+		// '//bionic/libc:libc_bp2build_cc_library_static' is duplicated in the 'deps' attribute of rule
+		"toybox-static",
+
+		// Do not convert the following modules because of duplicate labels checking in Bazel.
+		// See b/241283350. They should be removed from this list once the bug is fixed.
+		"libartpalette",
+		"libartbase",
+		"libdexfile",
+		"libartbased",
+		"libdexfile_static",
+		"libartbase-testing",
+		"libartbased-testing",
+		"libdexfile_support",
+		"libunwindstack",
+		"libunwindstack_local",
+		"libfdtrack",
+		"libc_malloc_debug",
+		"libutilscallstack",
+		"libunwindstack_utils",
+		"unwind_for_offline",
 	}
 
 	Bp2buildCcLibraryStaticOnlyList = []string{}
@@ -526,5 +615,35 @@
 		"simpleperf_ndk",
 		"toybox-static",
 		"zlib_bench",
+
+		// java_import[_host] issues
+		// tradefed prebuilts depend on libprotobuf
+		"prebuilt_tradefed",
+		"prebuilt_tradefed-test-framework",
+		// handcrafted BUILD.bazel files in //prebuilts/...
+		"prebuilt_r8lib-prebuilt",
+		"prebuilt_sdk-core-lambda-stubs",
+		"prebuilt_android-support-collections-nodeps",
+		"prebuilt_android-arch-core-common-nodeps",
+		"prebuilt_android-arch-lifecycle-common-java8-nodeps",
+		"prebuilt_android-arch-lifecycle-common-nodeps",
+		"prebuilt_android-support-annotations-nodeps",
+		"prebuilt_android-arch-paging-common-nodeps",
+		"prebuilt_android-arch-room-common-nodeps",
+		// TODO(b/217750501) exclude_dirs property not supported
+		"prebuilt_kotlin-reflect",
+		"prebuilt_kotlin-stdlib",
+		"prebuilt_kotlin-stdlib-jdk7",
+		"prebuilt_kotlin-stdlib-jdk8",
+		"prebuilt_kotlin-test",
+		// TODO(b/217750501) exclude_files property not supported
+		"prebuilt_platform-robolectric-4.4-prebuilt",
+		"prebuilt_platform-robolectric-4.5.1-prebuilt",
+		"prebuilt_currysrc_org.eclipse",
+	}
+
+	ProdMixedBuildsEnabledList = []string{
+		// This list left intentionally empty for now. Add specific module names
+		// to have them built by Bazel in Prod Mixed Builds mode.
 	}
 )
diff --git a/android/apex.go b/android/apex.go
index c53ceb3..00b7241 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -454,6 +454,8 @@
 	}
 	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))
 }
 
@@ -710,8 +712,8 @@
 
 // NewApexContents creates and initializes an ApexContents that is suitable
 // for use with an apex module.
-// * contents is a map from a module name to information about its membership within
-//   the apex.
+//   - contents is a map from a module name to information about its membership within
+//     the apex.
 func NewApexContents(contents map[string]ApexMembership) *ApexContents {
 	return &ApexContents{
 		contents: contents,
diff --git a/android/api_levels.go b/android/api_levels.go
index da50b19..bf7b317 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -307,24 +307,25 @@
 func getFinalCodenamesMap(config Config) map[string]int {
 	return config.Once(finalCodenamesMapKey, func() interface{} {
 		apiLevelsMap := map[string]int{
-			"G":     9,
-			"I":     14,
-			"J":     16,
-			"J-MR1": 17,
-			"J-MR2": 18,
-			"K":     19,
-			"L":     21,
-			"L-MR1": 22,
-			"M":     23,
-			"N":     24,
-			"N-MR1": 25,
-			"O":     26,
-			"O-MR1": 27,
-			"P":     28,
-			"Q":     29,
-			"R":     30,
-			"S":     31,
-			"S-V2":  32,
+			"G":        9,
+			"I":        14,
+			"J":        16,
+			"J-MR1":    17,
+			"J-MR2":    18,
+			"K":        19,
+			"L":        21,
+			"L-MR1":    22,
+			"M":        23,
+			"N":        24,
+			"N-MR1":    25,
+			"O":        26,
+			"O-MR1":    27,
+			"P":        28,
+			"Q":        29,
+			"R":        30,
+			"S":        31,
+			"S-V2":     32,
+			"Tiramisu": 33,
 		}
 
 		// TODO: Differentiate "current" and "future".
@@ -351,24 +352,25 @@
 func GetApiLevelsMap(config Config) map[string]int {
 	return config.Once(apiLevelsMapKey, func() interface{} {
 		apiLevelsMap := map[string]int{
-			"G":     9,
-			"I":     14,
-			"J":     16,
-			"J-MR1": 17,
-			"J-MR2": 18,
-			"K":     19,
-			"L":     21,
-			"L-MR1": 22,
-			"M":     23,
-			"N":     24,
-			"N-MR1": 25,
-			"O":     26,
-			"O-MR1": 27,
-			"P":     28,
-			"Q":     29,
-			"R":     30,
-			"S":     31,
-			"S-V2":  32,
+			"G":        9,
+			"I":        14,
+			"J":        16,
+			"J-MR1":    17,
+			"J-MR2":    18,
+			"K":        19,
+			"L":        21,
+			"L-MR1":    22,
+			"M":        23,
+			"N":        24,
+			"N-MR1":    25,
+			"O":        26,
+			"O-MR1":    27,
+			"P":        28,
+			"Q":        29,
+			"R":        30,
+			"S":        31,
+			"S-V2":     32,
+			"Tiramisu": 33,
 		}
 		for i, codename := range config.PlatformVersionActiveCodenames() {
 			apiLevelsMap[codename] = previewAPILevelBase + i
diff --git a/android/arch.go b/android/arch.go
index 6acc8ad..1952b17 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -393,54 +393,6 @@
 	}
 }
 
-func registerBp2buildArchPathDepsMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("bp2build-arch-pathdeps", bp2buildArchPathDepsMutator).Parallel()
-}
-
-// add dependencies for architecture specific properties tagged with `android:"path"`
-func bp2buildArchPathDepsMutator(ctx BottomUpMutatorContext) {
-	var module Module
-	module = ctx.Module()
-
-	m := module.base()
-	if !m.ArchSpecific() {
-		return
-	}
-
-	// addPathDepsForProps does not descend into sub structs, so we need to descend into the
-	// arch-specific properties ourselves
-	var properties []interface{}
-	for _, archProperties := range m.archProperties {
-		for _, archProps := range archProperties {
-			archPropValues := reflect.ValueOf(archProps).Elem()
-			// there are three "arch" variations, descend into each
-			for _, variant := range []string{"Arch", "Multilib", "Target"} {
-				// The properties are an interface, get the value (a pointer) that it points to
-				archProps := archPropValues.FieldByName(variant).Elem()
-				if archProps.IsNil() {
-					continue
-				}
-				// And then a pointer to a struct
-				archProps = archProps.Elem()
-				for i := 0; i < archProps.NumField(); i += 1 {
-					f := archProps.Field(i)
-					// If the value of the field is a struct (as opposed to a pointer to a struct) then step
-					// into the BlueprintEmbed field.
-					if f.Kind() == reflect.Struct {
-						f = f.FieldByName("BlueprintEmbed")
-					}
-					if f.IsZero() {
-						continue
-					}
-					props := f.Interface().(interface{})
-					properties = append(properties, props)
-				}
-			}
-		}
-	}
-	addPathDepsForProps(ctx, properties)
-}
-
 // osMutator splits an arch-specific module into a variant for each OS that is enabled for the
 // module.  It uses the HostOrDevice value passed to InitAndroidArchModule and the
 // device_supported and host_supported properties to determine which OsTypes are enabled for this
@@ -572,26 +524,29 @@
 // archMutator splits a module into a variant for each Target requested by the module.  Target selection
 // for a module is in three levels, OsClass, multilib, and then Target.
 // OsClass selection is determined by:
-//    - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
-//      whether the module type can compile for host, device or both.
-//    - The host_supported and device_supported properties on the module.
+//   - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
+//     whether the module type can compile for host, device or both.
+//   - The host_supported and device_supported properties on the module.
+//
 // If host is supported for the module, the Host and HostCross OsClasses are selected.  If device is supported
 // for the module, the Device OsClass is selected.
 // Within each selected OsClass, the multilib selection is determined by:
-//    - The compile_multilib property if it set (which may be overridden by target.android.compile_multilib or
-//      target.host.compile_multilib).
-//    - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
+//   - The compile_multilib property if it set (which may be overridden by target.android.compile_multilib or
+//     target.host.compile_multilib).
+//   - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
+//
 // Valid multilib values include:
-//    "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
-//    "first": compile for only a single preferred Target supported by the OsClass.  This is generally x86_64 or arm64,
-//        but may be arm for a 32-bit only build.
-//    "32": compile for only a single 32-bit Target supported by the OsClass.
-//    "64": compile for only a single 64-bit Target supported by the OsClass.
-//    "common": compile a for a single Target that will work on all Targets supported by the OsClass (for example Java).
-//    "common_first": compile a for a Target that will work on all Targets supported by the OsClass
-//        (same as "common"), plus a second Target for the preferred Target supported by the OsClass
-//        (same as "first").  This is used for java_binary that produces a common .jar and a wrapper
-//        executable script.
+//
+//	"both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
+//	"first": compile for only a single preferred Target supported by the OsClass.  This is generally x86_64 or arm64,
+//	    but may be arm for a 32-bit only build.
+//	"32": compile for only a single 32-bit Target supported by the OsClass.
+//	"64": compile for only a single 64-bit Target supported by the OsClass.
+//	"common": compile a for a single Target that will work on all Targets supported by the OsClass (for example Java).
+//	"common_first": compile a for a Target that will work on all Targets supported by the OsClass
+//	    (same as "common"), plus a second Target for the preferred Target supported by the OsClass
+//	    (same as "first").  This is used for java_binary that produces a common .jar and a wrapper
+//	    executable script.
 //
 // Once the list of Targets is determined, the module is split into a variant for each Target.
 //
@@ -664,6 +619,12 @@
 		mctx.ModuleErrorf("%s", err.Error())
 	}
 
+	// If there are no supported targets disable the module.
+	if len(targets) == 0 {
+		base.Disable()
+		return
+	}
+
 	// If the module is using extraMultilib, decode the extraMultilib selection into
 	// a separate list of Targets.
 	var multiTargets []Target
@@ -672,6 +633,7 @@
 		if err != nil {
 			mctx.ModuleErrorf("%s", err.Error())
 		}
+		multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
 	}
 
 	// Recovery is always the primary architecture, filter out any other architectures.
@@ -808,6 +770,18 @@
 	return targets
 }
 
+// filterHostCross takes a list of Targets and a hostCross value, and returns a modified list
+// that contains only Targets that have the specified HostCross.
+func filterHostCross(targets []Target, hostCross bool) []Target {
+	for i := 0; i < len(targets); i++ {
+		if targets[i].HostCross != hostCross {
+			targets = append(targets[:i], targets[i+1:]...)
+			i--
+		}
+	}
+	return targets
+}
+
 // archPropRoot is a struct type used as the top level of the arch-specific properties.  It
 // contains the "arch", "multilib", and "target" property structs.  It is used to split up the
 // property structs to limit how much is allocated when a single arch-specific property group is
@@ -998,19 +972,13 @@
 		if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
 			panic(fmt.Errorf("unexpected tag format %q", field.Tag))
 		}
-		// don't delete path tag as it is needed for bp2build
 		// these tags don't need to be present in the runtime generated struct type.
-		values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend"})
-		if len(values) > 0 && values[0] != "path" {
+		values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
+		if len(values) > 0 {
 			panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
-		} else if len(values) == 1 {
-			// FIXME(b/200678898): This assumes that the only tag type when there's
-			// `android:"arch_variant"` is `android` itself and thus clobbers others
-			field.Tag = reflect.StructTag(`android:"` + strings.Join(values, ",") + `"`)
-		} else {
-			field.Tag = ``
 		}
 
+		field.Tag = ``
 		return true, field
 	}
 	return false, field
@@ -1269,11 +1237,13 @@
 
 // Returns the struct containing the properties specific to the given
 // architecture type. These look like this in Blueprint files:
-// arch: {
-//     arm64: {
-//         key: value,
-//     },
-// },
+//
+//	arch: {
+//	    arm64: {
+//	        key: value,
+//	    },
+//	},
+//
 // This struct will also contain sub-structs containing to the architecture/CPU
 // variants and features that themselves contain properties specific to those.
 func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
@@ -1285,11 +1255,12 @@
 
 // Returns the struct containing the properties specific to a given multilib
 // value. These look like this in the Blueprint file:
-// multilib: {
-//     lib32: {
-//         key: value,
-//     },
-// },
+//
+//	multilib: {
+//	    lib32: {
+//	        key: value,
+//	    },
+//	},
 func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
 	archPropValues := reflect.ValueOf(archProperties).Elem()
 	multilibProp := archPropValues.FieldByName("Multilib").Elem()
@@ -1843,20 +1814,23 @@
 }
 
 // FirstTarget takes a list of Targets and a list of multilib values and returns a list of Targets
-// that contains zero or one Target for each OsType, selecting the one that matches the earliest
-// filter.
+// that contains zero or one Target for each OsType and HostCross, selecting the one that matches
+// the earliest filter.
 func FirstTarget(targets []Target, filters ...string) []Target {
 	// find the first target from each OS
 	var ret []Target
-	hasHost := false
-	set := make(map[OsType]bool)
+	type osHostCross struct {
+		os        OsType
+		hostCross bool
+	}
+	set := make(map[osHostCross]bool)
 
 	for _, filter := range filters {
 		buildTargets := filterMultilibTargets(targets, filter)
 		for _, t := range buildTargets {
-			if _, found := set[t.Os]; !found {
-				hasHost = hasHost || (t.Os.Class == Host)
-				set[t.Os] = true
+			key := osHostCross{t.Os, t.HostCross}
+			if _, found := set[key]; !found {
+				set[key] = true
 				ret = append(ret, t)
 			}
 		}
@@ -2064,9 +2038,10 @@
 // arch-variant properties correspond to the values of the properties of the 'propertySet' struct
 // that are specific to that axis/configuration. Each axis is independent, containing
 // non-overlapping configs that correspond to the various "arch-variant" support, at this time:
-//    arches (including multilib)
-//    oses
-//    arch+os combinations
+//
+//	arches (including multilib)
+//	oses
+//	arch+os combinations
 //
 // For example, passing a struct { Foo bool, Bar string } will return an interface{} that can be
 // type asserted back into the same struct, containing the config-specific property value specified
@@ -2219,17 +2194,21 @@
 
 // Returns a struct matching the propertySet interface, containing properties specific to the targetName
 // For example, given these arguments:
-//    propertySet = BaseCompilerProperties
-//    targetName = "android_arm"
+//
+//	propertySet = BaseCompilerProperties
+//	targetName = "android_arm"
+//
 // And given this Android.bp fragment:
-//    target:
-//       android_arm: {
-//          srcs: ["foo.c"],
-//       }
-//       android_arm64: {
-//          srcs: ["bar.c"],
-//      }
-//    }
+//
+//	target:
+//	   android_arm: {
+//	      srcs: ["foo.c"],
+//	   }
+//	   android_arm64: {
+//	      srcs: ["bar.c"],
+//	  }
+//	}
+//
 // This would return a BaseCompilerProperties with BaseCompilerProperties.Srcs = ["foo.c"]
 func getTargetStructs(ctx ArchVariantContext, archProperties []interface{}, targetName string) []reflect.Value {
 	var propertyStructs []reflect.Value
diff --git a/android/arch_test.go b/android/arch_test.go
index dd0b115..6814f8a 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -66,9 +66,9 @@
 			}{},
 			out: &struct {
 				A *string
-				B *string `android:"path"`
-				C *string `android:"path"`
-				D *string `android:"path"`
+				B *string
+				C *string
+				D *string
 			}{},
 			filtered: true,
 		},
@@ -259,6 +259,27 @@
 	}
 }
 
+func (m *archTestMultiTargetsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (m *archTestMultiTargetsModule) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
+}
+
+func archTestMultiTargetsModuleFactory() Module {
+	m := &archTestMultiTargetsModule{}
+	m.AddProperties(&m.props)
+	InitAndroidMultiTargetsArchModule(m, HostAndDeviceSupported, MultilibCommon)
+	return m
+}
+
+type archTestMultiTargetsModule struct {
+	ModuleBase
+	props struct {
+		Deps []string
+	}
+}
+
 func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 }
 
@@ -277,19 +298,27 @@
 	PrepareForTestWithArchMutator,
 	FixtureRegisterWithContext(func(ctx RegistrationContext) {
 		ctx.RegisterModuleType("module", archTestModuleFactory)
+		ctx.RegisterModuleType("multi_targets_module", archTestMultiTargetsModuleFactory)
 	}),
 )
 
 func TestArchMutator(t *testing.T) {
 	var buildOSVariants []string
+	var buildOS64Variants []string
 	var buildOS32Variants []string
+	var buildOSCommonVariant string
+
 	switch runtime.GOOS {
 	case "linux":
 		buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"}
+		buildOS64Variants = []string{"linux_glibc_x86_64"}
 		buildOS32Variants = []string{"linux_glibc_x86"}
+		buildOSCommonVariant = "linux_glibc_common"
 	case "darwin":
 		buildOSVariants = []string{"darwin_x86_64"}
+		buildOS64Variants = []string{"darwin_x86_64"}
 		buildOS32Variants = nil
+		buildOSCommonVariant = "darwin_common"
 	}
 
 	bp := `
@@ -312,24 +341,46 @@
 			host_supported: true,
 			compile_multilib: "32",
 		}
+
+		module {
+			name: "first",
+			host_supported: true,
+			compile_multilib: "first",
+		}
+
+		multi_targets_module {
+			name: "multi_targets",
+			host_supported: true,
+		}
 	`
 
 	testCases := []struct {
-		name        string
-		preparer    FixturePreparer
-		fooVariants []string
-		barVariants []string
-		bazVariants []string
-		quxVariants []string
+		name          string
+		preparer      FixturePreparer
+		fooVariants   []string
+		barVariants   []string
+		bazVariants   []string
+		quxVariants   []string
+		firstVariants []string
+
+		multiTargetVariants    []string
+		multiTargetVariantsMap map[string][]string
+
+		goOS string
 	}{
 		{
-			name:        "normal",
-			preparer:    nil,
-			fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
-			barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
-			bazVariants: nil,
-			quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"),
-		},
+			name:                "normal",
+			preparer:            nil,
+			fooVariants:         []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
+			barVariants:         append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"),
+			bazVariants:         nil,
+			quxVariants:         append(buildOS32Variants, "android_arm_armv7-a-neon"),
+			firstVariants:       append(buildOS64Variants, "android_arm64_armv8-a"),
+			multiTargetVariants: []string{buildOSCommonVariant, "android_common"},
+			multiTargetVariantsMap: map[string][]string{
+				buildOSCommonVariant: buildOS64Variants,
+				"android_common":     {"android_arm64_armv8-a"},
+			}},
 		{
 			name: "host-only",
 			preparer: FixtureModifyConfig(func(config Config) {
@@ -337,10 +388,33 @@
 				config.BuildOSCommonTarget = Target{}
 				config.Targets[Android] = nil
 			}),
-			fooVariants: nil,
-			barVariants: buildOSVariants,
-			bazVariants: nil,
-			quxVariants: buildOS32Variants,
+			fooVariants:         nil,
+			barVariants:         buildOSVariants,
+			bazVariants:         nil,
+			quxVariants:         buildOS32Variants,
+			firstVariants:       buildOS64Variants,
+			multiTargetVariants: []string{buildOSCommonVariant},
+			multiTargetVariantsMap: map[string][]string{
+				buildOSCommonVariant: buildOS64Variants,
+			},
+		},
+		{
+			name: "same arch host and host cross",
+			preparer: FixtureModifyConfig(func(config Config) {
+				modifyTestConfigForMusl(config)
+				modifyTestConfigForMuslArm64HostCross(config)
+			}),
+			fooVariants:         []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"},
+			barVariants:         []string{"linux_musl_x86_64", "linux_musl_arm64", "linux_musl_x86", "android_arm64_armv8-a", "android_arm_armv7-a-neon"},
+			bazVariants:         nil,
+			quxVariants:         []string{"linux_musl_x86", "android_arm_armv7-a-neon"},
+			firstVariants:       []string{"linux_musl_x86_64", "linux_musl_arm64", "android_arm64_armv8-a"},
+			multiTargetVariants: []string{"linux_musl_common", "android_common"},
+			multiTargetVariantsMap: map[string][]string{
+				"linux_musl_common": {"linux_musl_x86_64"},
+				"android_common":    {"android_arm64_armv8-a"},
+			},
+			goOS: "linux",
 		},
 	}
 
@@ -356,8 +430,21 @@
 		return ret
 	}
 
+	moduleMultiTargets := func(ctx *TestContext, name string, variant string) []string {
+		var ret []string
+		targets := ctx.ModuleForTests(name, variant).Module().MultiTargets()
+		for _, t := range targets {
+			ret = append(ret, t.String())
+		}
+		return ret
+	}
+
 	for _, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
+			if tt.goOS != runtime.GOOS {
+				t.Skipf("requries runtime.GOOS %s", tt.goOS)
+			}
+
 			result := GroupFixturePreparers(
 				prepareForArchTest,
 				// Test specific preparer
@@ -381,6 +468,20 @@
 			if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) {
 				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
 			}
+			if g, w := enabledVariants(ctx, "first"), tt.firstVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want first variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "multi_targets"), tt.multiTargetVariants; !reflect.DeepEqual(w, g) {
+				t.Fatalf("want multi_target variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			for _, variant := range tt.multiTargetVariants {
+				targets := moduleMultiTargets(ctx, "multi_targets", variant)
+				if g, w := targets, tt.multiTargetVariantsMap[variant]; !reflect.DeepEqual(w, g) {
+					t.Errorf("want ctx.MultiTarget() for %q:\n%q\ngot:\n%q\n", variant, w, g)
+				}
+			}
 		})
 	}
 }
diff --git a/android/bazel.go b/android/bazel.go
index 40f2917..15729c1 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -35,6 +35,26 @@
 	Bp2BuildTopLevel = "."
 )
 
+// Bp2buildAidlLibrary describes a filegroup module that are converted to aidl_library
+type Bp2buildAidlLibrary interface {
+	ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool
+	GetAidlLibraryLabel(ctx BazelConversionPathContext) string
+}
+
+type BazelConversionStatus struct {
+	// Information about _all_ bp2build targets generated by this module. Multiple targets are
+	// supported as Soong handles some things within a single target that we may choose to split into
+	// multiple targets, e.g. renderscript, protos, yacc within a cc module.
+	Bp2buildInfo []bp2buildInfo `blueprint:"mutated"`
+
+	// UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
+	// Bazel
+	UnconvertedDeps []string `blueprint:"mutated"`
+
+	// MissingBp2buildDep stores the module names of direct dependency that were not found
+	MissingDeps []string `blueprint:"mutated"`
+}
+
 type bazelModuleProperties struct {
 	// The label of the Bazel target replacing this Soong module. When run in conversion mode, this
 	// will import the handcrafted build target into the autogenerated file. Note: this may result in
@@ -191,7 +211,7 @@
 	return "" // no label for unconverted module
 }
 
-type bp2BuildConversionAllowlist struct {
+type Bp2BuildConversionAllowlist struct {
 	// Configure modules in these directories to enable bp2build_available: true or false by default.
 	defaultConfig allowlists.Bp2BuildConfig
 
@@ -199,46 +219,47 @@
 	// in the synthetic Bazel workspace.
 	keepExistingBuildFile map[string]bool
 
-	// Per-module allowlist to always opt modules in of both bp2build and mixed builds.
-	// These modules are usually in directories with many other modules that are not ready for
-	// conversion.
+	// Per-module allowlist to always opt modules into both bp2build and Bazel Dev Mode mixed
+	// builds. These modules are usually in directories with many other modules that are not ready
+	// for conversion.
 	//
 	// A module can either be in this list or its directory allowlisted entirely
 	// in bp2buildDefaultConfig, but not both at the same time.
 	moduleAlwaysConvert map[string]bool
 
-	// Per-module-type allowlist to always opt modules in to both bp2build and mixed builds
-	// when they have the same type as one listed.
+	// Per-module-type allowlist to always opt modules in to both bp2build and
+	// Bazel Dev Mode mixed builds when they have the same type as one listed.
 	moduleTypeAlwaysConvert map[string]bool
 
-	// Per-module denylist to always opt modules out of both bp2build and mixed builds.
+	// Per-module denylist to always opt modules out of bp2build conversion.
 	moduleDoNotConvert map[string]bool
 
 	// Per-module denylist of cc_library modules to only generate the static
 	// variant if their shared variant isn't ready or buildable by Bazel.
 	ccLibraryStaticOnly map[string]bool
-
-	// Per-module denylist to opt modules out of mixed builds. Such modules will
-	// still be generated via bp2build.
-	mixedBuildsDisabled map[string]bool
 }
 
-// NewBp2BuildAllowlist creates a new, empty bp2BuildConversionAllowlist
+// GenerateCcLibraryStaticOnly returns whether a cc_library module should only
+// generate a static version of itself based on the current global configuration.
+func (a Bp2BuildConversionAllowlist) GenerateCcLibraryStaticOnly(moduleName string) bool {
+	return a.ccLibraryStaticOnly[moduleName]
+}
+
+// NewBp2BuildAllowlist creates a new, empty Bp2BuildConversionAllowlist
 // which can be populated using builder pattern Set* methods
-func NewBp2BuildAllowlist() bp2BuildConversionAllowlist {
-	return bp2BuildConversionAllowlist{
+func NewBp2BuildAllowlist() Bp2BuildConversionAllowlist {
+	return Bp2BuildConversionAllowlist{
 		allowlists.Bp2BuildConfig{},
 		map[string]bool{},
 		map[string]bool{},
 		map[string]bool{},
 		map[string]bool{},
 		map[string]bool{},
-		map[string]bool{},
 	}
 }
 
 // SetDefaultConfig copies the entries from defaultConfig into the allowlist
-func (a bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.Bp2BuildConfig) bp2BuildConversionAllowlist {
+func (a Bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.Bp2BuildConfig) Bp2BuildConversionAllowlist {
 	if a.defaultConfig == nil {
 		a.defaultConfig = allowlists.Bp2BuildConfig{}
 	}
@@ -250,7 +271,7 @@
 }
 
 // SetKeepExistingBuildFile copies the entries from keepExistingBuildFile into the allowlist
-func (a bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildFile map[string]bool) bp2BuildConversionAllowlist {
+func (a Bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildFile map[string]bool) Bp2BuildConversionAllowlist {
 	if a.keepExistingBuildFile == nil {
 		a.keepExistingBuildFile = map[string]bool{}
 	}
@@ -262,7 +283,7 @@
 }
 
 // SetModuleAlwaysConvertList copies the entries from moduleAlwaysConvert into the allowlist
-func (a bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConvert []string) bp2BuildConversionAllowlist {
+func (a Bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConvert []string) Bp2BuildConversionAllowlist {
 	if a.moduleAlwaysConvert == nil {
 		a.moduleAlwaysConvert = map[string]bool{}
 	}
@@ -274,7 +295,7 @@
 }
 
 // SetModuleTypeAlwaysConvertList copies the entries from moduleTypeAlwaysConvert into the allowlist
-func (a bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAlwaysConvert []string) bp2BuildConversionAllowlist {
+func (a Bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAlwaysConvert []string) Bp2BuildConversionAllowlist {
 	if a.moduleTypeAlwaysConvert == nil {
 		a.moduleTypeAlwaysConvert = map[string]bool{}
 	}
@@ -286,7 +307,7 @@
 }
 
 // SetModuleDoNotConvertList copies the entries from moduleDoNotConvert into the allowlist
-func (a bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConvert []string) bp2BuildConversionAllowlist {
+func (a Bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConvert []string) Bp2BuildConversionAllowlist {
 	if a.moduleDoNotConvert == nil {
 		a.moduleDoNotConvert = map[string]bool{}
 	}
@@ -298,7 +319,7 @@
 }
 
 // SetCcLibraryStaticOnlyList copies the entries from ccLibraryStaticOnly into the allowlist
-func (a bp2BuildConversionAllowlist) SetCcLibraryStaticOnlyList(ccLibraryStaticOnly []string) bp2BuildConversionAllowlist {
+func (a Bp2BuildConversionAllowlist) SetCcLibraryStaticOnlyList(ccLibraryStaticOnly []string) Bp2BuildConversionAllowlist {
 	if a.ccLibraryStaticOnly == nil {
 		a.ccLibraryStaticOnly = map[string]bool{}
 	}
@@ -309,52 +330,15 @@
 	return a
 }
 
-// SetMixedBuildsDisabledList copies the entries from mixedBuildsDisabled into the allowlist
-func (a bp2BuildConversionAllowlist) SetMixedBuildsDisabledList(mixedBuildsDisabled []string) bp2BuildConversionAllowlist {
-	if a.mixedBuildsDisabled == nil {
-		a.mixedBuildsDisabled = map[string]bool{}
-	}
-	for _, m := range mixedBuildsDisabled {
-		a.mixedBuildsDisabled[m] = true
-	}
-
-	return a
-}
-
-var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist")
-var bp2buildAllowlist OncePer
-
-func getBp2BuildAllowList() bp2BuildConversionAllowlist {
-	return bp2buildAllowlist.Once(bp2BuildAllowListKey, func() interface{} {
-		return NewBp2BuildAllowlist().SetDefaultConfig(allowlists.Bp2buildDefaultConfig).
-			SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile).
-			SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList).
-			SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList).
-			SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList).
-			SetCcLibraryStaticOnlyList(allowlists.Bp2buildCcLibraryStaticOnlyList).
-			SetMixedBuildsDisabledList(allowlists.MixedBuildsDisabledList)
-	}).(bp2BuildConversionAllowlist)
-}
-
-// GenerateCcLibraryStaticOnly returns whether a cc_library module should only
-// generate a static version of itself based on the current global configuration.
-func GenerateCcLibraryStaticOnly(moduleName string) bool {
-	return getBp2BuildAllowList().ccLibraryStaticOnly[moduleName]
-}
-
 // ShouldKeepExistingBuildFileForDir returns whether an existing BUILD file should be
 // added to the build symlink forest based on the current global configuration.
-func ShouldKeepExistingBuildFileForDir(dir string) bool {
-	return shouldKeepExistingBuildFileForDir(getBp2BuildAllowList(), dir)
-}
-
-func shouldKeepExistingBuildFileForDir(allowlist bp2BuildConversionAllowlist, dir string) bool {
-	if _, ok := allowlist.keepExistingBuildFile[dir]; ok {
+func (a Bp2BuildConversionAllowlist) ShouldKeepExistingBuildFileForDir(dir string) bool {
+	if _, ok := a.keepExistingBuildFile[dir]; ok {
 		// Exact dir match
 		return true
 	}
 	// Check if subtree match
-	for prefix, recursive := range allowlist.keepExistingBuildFile {
+	for prefix, recursive := range a.keepExistingBuildFile {
 		if recursive {
 			if strings.HasPrefix(dir, prefix+"/") {
 				return true
@@ -365,6 +349,20 @@
 	return false
 }
 
+var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist")
+var bp2buildAllowlist OncePer
+
+func GetBp2BuildAllowList() Bp2BuildConversionAllowlist {
+	return bp2buildAllowlist.Once(bp2BuildAllowListKey, func() interface{} {
+		return NewBp2BuildAllowlist().SetDefaultConfig(allowlists.Bp2buildDefaultConfig).
+			SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile).
+			SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList).
+			SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList).
+			SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList).
+			SetCcLibraryStaticOnlyList(allowlists.Bp2buildCcLibraryStaticOnlyList)
+	}).(Bp2BuildConversionAllowlist)
+}
+
 // MixedBuildsEnabled returns true if a module is ready to be replaced by a
 // converted or handcrafted Bazel target. As a side effect, calling this
 // method will also log whether this module is mixed build enabled for
@@ -385,20 +383,10 @@
 	if !ctx.Module().Enabled() {
 		return false
 	}
-	if !ctx.Config().BazelContext.BazelEnabled() {
-		return false
-	}
 	if !convertedToBazel(ctx, ctx.Module()) {
 		return false
 	}
-
-	if GenerateCcLibraryStaticOnly(ctx.Module().Name()) {
-		// Don't use partially-converted cc_library targets in mixed builds,
-		// since mixed builds would generally rely on both static and shared
-		// variants of a cc_library.
-		return false
-	}
-	return !getBp2BuildAllowList().mixedBuildsDisabled[ctx.Module().Name()]
+	return ctx.Config().BazelContext.BazelAllowlisted(ctx.Module().Name())
 }
 
 // ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
@@ -439,7 +427,7 @@
 	}
 
 	moduleName := module.Name()
-	allowlist := ctx.Config().bp2buildPackageConfig
+	allowlist := ctx.Config().Bp2buildPackageConfig
 	moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName]
 	moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[ctx.OtherModuleType(module)]
 	allowlistConvert := moduleNameAllowed || moduleTypeAllowed
@@ -455,14 +443,6 @@
 		return false
 	}
 
-	if allowlistConvert && shouldKeepExistingBuildFileForDir(allowlist, packagePath) {
-		if moduleNameAllowed {
-			ctx.ModuleErrorf("A module cannot be in a directory listed in keepExistingBuildFile"+
-				" and also be in moduleAlwaysConvert. Directory: '%s'", packagePath)
-			return false
-		}
-	}
-
 	// This is a tristate value: true, false, or unset.
 	if ok, directoryPath := bp2buildDefaultTrueRecursively(packagePath, allowlist.defaultConfig); ok {
 		if moduleNameAllowed {
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 5804a46..93b6779 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -27,8 +27,10 @@
 	"strings"
 	"sync"
 
+	"android/soong/android/allowlists"
 	"android/soong/bazel/cquery"
 	"android/soong/shared"
+
 	"github.com/google/blueprint"
 
 	"android/soong/bazel"
@@ -54,7 +56,7 @@
 }
 
 func RegisterMixedBuildsMutator(ctx RegistrationContext) {
-	ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
+	ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
 		ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
 	})
 }
@@ -141,8 +143,11 @@
 	// queued in the BazelContext.
 	InvokeBazel(config Config) error
 
-	// Returns true if bazel is enabled for the given configuration.
-	BazelEnabled() bool
+	// Returns true if Bazel handling is enabled for the module with the given name.
+	// Note that this only implies "bazel mixed build" allowlisting. The caller
+	// should independently verify the module is eligible for Bazel handling
+	// (for example, that it is MixedBuildBuildable).
+	BazelAllowlisted(moduleName string) bool
 
 	// Returns the bazel output base (the root directory for all bazel intermediate outputs).
 	OutputBase() string
@@ -182,6 +187,17 @@
 
 	// Depsets which should be used for Bazel's build statements.
 	depsets []bazel.AqueryDepset
+
+	// Per-module allowlist/denylist functionality to control whether analysis of
+	// modules are handled by Bazel. For modules which do not have a Bazel definition
+	// (or do not sufficiently support bazel handling via MixedBuildBuildable),
+	// this allowlist will have no effect, even if the module is explicitly allowlisted here.
+	// Per-module denylist to opt modules out of bazel handling.
+	bazelDisabledModules map[string]bool
+	// Per-module allowlist to opt modules in to bazel handling.
+	bazelEnabledModules map[string]bool
+	// If true, modules are bazel-enabled by default, unless present in bazelDisabledModules.
+	modulesDefaultToBazel bool
 }
 
 var _ BazelContext = &bazelContext{}
@@ -228,7 +244,7 @@
 	panic("unimplemented")
 }
 
-func (m MockBazelContext) BazelEnabled() bool {
+func (m MockBazelContext) BazelAllowlisted(moduleName string) bool {
 	return true
 }
 
@@ -314,7 +330,7 @@
 	return ""
 }
 
-func (n noopBazelContext) BazelEnabled() bool {
+func (n noopBazelContext) BazelAllowlisted(moduleName string) bool {
 	return false
 }
 
@@ -327,9 +343,30 @@
 }
 
 func NewBazelContext(c *config) (BazelContext, error) {
-	// TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
-	// are production ready.
-	if !c.IsEnvTrue("USE_BAZEL_ANALYSIS") {
+	var modulesDefaultToBazel bool
+	disabledModules := map[string]bool{}
+	enabledModules := map[string]bool{}
+
+	switch c.BuildMode {
+	case BazelProdMode:
+		modulesDefaultToBazel = false
+
+		for _, enabledProdModule := range allowlists.ProdMixedBuildsEnabledList {
+			enabledModules[enabledProdModule] = true
+		}
+	case BazelDevMode:
+		modulesDefaultToBazel = true
+
+		// Don't use partially-converted cc_library targets in mixed builds,
+		// since mixed builds would generally rely on both static and shared
+		// variants of a cc_library.
+		for staticOnlyModule, _ := range GetBp2BuildAllowList().ccLibraryStaticOnly {
+			disabledModules[staticOnlyModule] = true
+		}
+		for _, disabledDevModule := range allowlists.MixedBuildsDisabledList {
+			disabledModules[disabledDevModule] = true
+		}
+	default:
 		return noopBazelContext{}, nil
 	}
 
@@ -337,10 +374,14 @@
 	if err != nil {
 		return nil, err
 	}
+
 	return &bazelContext{
-		bazelRunner: &builtinBazelRunner{},
-		paths:       p,
-		requests:    make(map[cqueryKey]bool),
+		bazelRunner:           &builtinBazelRunner{},
+		paths:                 p,
+		requests:              make(map[cqueryKey]bool),
+		modulesDefaultToBazel: modulesDefaultToBazel,
+		bazelEnabledModules:   enabledModules,
+		bazelDisabledModules:  disabledModules,
 	}, nil
 }
 
@@ -385,8 +426,14 @@
 	return p.metricsDir
 }
 
-func (context *bazelContext) BazelEnabled() bool {
-	return true
+func (context *bazelContext) BazelAllowlisted(moduleName string) bool {
+	if context.bazelDisabledModules[moduleName] {
+		return false
+	}
+	if context.bazelEnabledModules[moduleName] {
+		return true
+	}
+	return context.modulesDefaultToBazel
 }
 
 func pwdPrefix() string {
@@ -766,9 +813,9 @@
 	cqueryOutput, cqueryErr, err := context.issueBazelCommand(context.paths, bazel.CqueryBuildRootRunName, cqueryCmd,
 		"--output=starlark", "--starlark:file="+absolutePath(cqueryFileRelpath))
 	if err != nil {
-		_ = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666)
+		return err
 	}
-	if err != nil {
+	if err = ioutil.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryOutput), 0666); err != nil {
 		return err
 	}
 
@@ -850,7 +897,7 @@
 
 func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
 	// bazelSingleton is a no-op if mixed-soong-bazel-builds are disabled.
-	if !ctx.Config().BazelContext.BazelEnabled() {
+	if !ctx.Config().IsMixedBuildsEnabled() {
 		return
 	}
 
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index c030aa8..bbdae96 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -221,9 +221,13 @@
 // Transform a path (if necessary) to acknowledge package boundaries
 //
 // e.g. something like
-//   async_safe/include/async_safe/CHECK.h
+//
+//	async_safe/include/async_safe/CHECK.h
+//
 // might become
-//   //bionic/libc/async_safe:include/async_safe/CHECK.h
+//
+//	//bionic/libc/async_safe:include/async_safe/CHECK.h
+//
 // if the "async_safe" directory is actually a package and not just a directory.
 //
 // In particular, paths that extend into packages are transformed into absolute labels beginning with //.
@@ -303,20 +307,21 @@
 // directory and Bazel target labels, excluding those included in the excludes argument (which
 // should already be expanded to resolve references to Soong-modules). Valid elements of paths
 // include:
-// * filepath, relative to local module directory, resolves as a filepath relative to the local
-//   source directory
-// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
-//    module directory. Because Soong does not have a concept of crossing package boundaries, the
-//    glob as computed by Soong may contain paths that cross package-boundaries that would be
-//    unknowingly omitted if the glob were handled by Bazel. To allow identification and detect
-//    (within Bazel) use of paths that cross package boundaries, we expand globs within Soong rather
-//    than converting Soong glob syntax to Bazel glob syntax. **Invalid for excludes.**
-// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-//    or OutputFileProducer. These resolve as a Bazel label for a target. If the Bazel target is in
-//    the local module directory, it will be returned relative to the current package (e.g.
-//    ":<target>"). Otherwise, it will be returned as an absolute Bazel label (e.g.
-//    "//path/to/dir:<target>"). If the reference to another module cannot be resolved,the function
-//    will panic.
+//   - filepath, relative to local module directory, resolves as a filepath relative to the local
+//     source directory
+//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
+//     module directory. Because Soong does not have a concept of crossing package boundaries, the
+//     glob as computed by Soong may contain paths that cross package-boundaries that would be
+//     unknowingly omitted if the glob were handled by Bazel. To allow identification and detect
+//     (within Bazel) use of paths that cross package boundaries, we expand globs within Soong rather
+//     than converting Soong glob syntax to Bazel glob syntax. **Invalid for excludes.**
+//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
+//     or OutputFileProducer. These resolve as a Bazel label for a target. If the Bazel target is in
+//     the local module directory, it will be returned relative to the current package (e.g.
+//     ":<target>"). Otherwise, it will be returned as an absolute Bazel label (e.g.
+//     "//path/to/dir:<target>"). If the reference to another module cannot be resolved,the function
+//     will panic.
+//
 // Properties passed as the paths or excludes argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on other modules will have already been handled by the
 // path_deps mutator.
diff --git a/android/bazel_test.go b/android/bazel_test.go
index e14649e..b578cca 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
@@ -158,7 +158,7 @@
 
 type TestBazelConversionContext struct {
 	omc       bazel.OtherModuleTestContext
-	allowlist bp2BuildConversionAllowlist
+	allowlist Bp2BuildConversionAllowlist
 	errors    []string
 }
 
@@ -183,7 +183,7 @@
 func (bcc *TestBazelConversionContext) Config() Config {
 	return Config{
 		&config{
-			bp2buildPackageConfig: bcc.allowlist,
+			Bp2buildPackageConfig: bcc.allowlist,
 		},
 	}
 }
@@ -202,7 +202,7 @@
 		shouldConvert  bool
 		expectedErrors []string
 		module         TestBazelModule
-		allowlist      bp2BuildConversionAllowlist
+		allowlist      Bp2BuildConversionAllowlist
 	}{
 		{
 			description:   "allowlist enables module",
@@ -215,7 +215,7 @@
 				},
 				BazelModuleBase: bazelableBazelModuleBase,
 			},
-			allowlist: bp2BuildConversionAllowlist{
+			allowlist: Bp2BuildConversionAllowlist{
 				moduleAlwaysConvert: map[string]bool{
 					"foo": true,
 				},
@@ -233,7 +233,7 @@
 				},
 				BazelModuleBase: bazelableBazelModuleBase,
 			},
-			allowlist: bp2BuildConversionAllowlist{
+			allowlist: Bp2BuildConversionAllowlist{
 				moduleAlwaysConvert: map[string]bool{
 					"foo": true,
 				},
@@ -254,7 +254,7 @@
 				},
 				BazelModuleBase: bazelableBazelModuleBase,
 			},
-			allowlist: bp2BuildConversionAllowlist{
+			allowlist: Bp2BuildConversionAllowlist{
 				moduleAlwaysConvert: map[string]bool{
 					"foo": true,
 				},
@@ -264,27 +264,6 @@
 			},
 		},
 		{
-			description:    "module in allowlist and existing BUILD file",
-			shouldConvert:  false,
-			expectedErrors: []string{"A module cannot be in a directory listed in keepExistingBuildFile and also be in moduleAlwaysConvert. Directory: 'existing/build/dir'"},
-			module: TestBazelModule{
-				TestModuleInfo: bazel.TestModuleInfo{
-					ModuleName: "foo",
-					Typ:        "rule1",
-					Dir:        "existing/build/dir",
-				},
-				BazelModuleBase: bazelableBazelModuleBase,
-			},
-			allowlist: bp2BuildConversionAllowlist{
-				moduleAlwaysConvert: map[string]bool{
-					"foo": true,
-				},
-				keepExistingBuildFile: map[string]bool{
-					"existing/build/dir": true,
-				},
-			},
-		},
-		{
 			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'"},
@@ -296,7 +275,7 @@
 				},
 				BazelModuleBase: bazelableBazelModuleBase,
 			},
-			allowlist: bp2BuildConversionAllowlist{
+			allowlist: Bp2BuildConversionAllowlist{
 				moduleAlwaysConvert: map[string]bool{
 					"foo": true,
 				},
@@ -317,7 +296,7 @@
 				},
 				BazelModuleBase: bazelableBazelModuleBase,
 			},
-			allowlist: bp2BuildConversionAllowlist{
+			allowlist: Bp2BuildConversionAllowlist{
 				moduleAlwaysConvert: map[string]bool{
 					"foo": true,
 				},
@@ -344,7 +323,7 @@
 					},
 				},
 			},
-			allowlist: bp2BuildConversionAllowlist{
+			allowlist: Bp2BuildConversionAllowlist{
 				moduleAlwaysConvert: map[string]bool{
 					"foo": true,
 				},
@@ -389,7 +368,7 @@
 }
 
 func TestBp2buildAllowList(t *testing.T) {
-	allowlist := getBp2BuildAllowList()
+	allowlist := GetBp2BuildAllowList()
 	for k, v := range allowlists.Bp2buildDefaultConfig {
 		if allowlist.defaultConfig[k] != v {
 			t.Errorf("bp2build default config of %s: expected: %v, got: %v", k, v, allowlist.defaultConfig[k])
@@ -415,9 +394,4 @@
 			t.Errorf("bp2build cc library static only of %s: expected: true, got: %v", k, allowlist.ccLibraryStaticOnly[k])
 		}
 	}
-	for _, k := range allowlists.MixedBuildsDisabledList {
-		if !allowlist.mixedBuildsDisabled[k] {
-			t.Errorf("bp2build mix build disabled of %s: expected: true, got: %v", k, allowlist.mixedBuildsDisabled[k])
-		}
-	}
 }
diff --git a/android/config.go b/android/config.go
index 8c7d789..745410f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -18,8 +18,8 @@
 // product variables necessary for soong_build's operation.
 
 import (
+	"bytes"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -68,6 +68,37 @@
 	*config
 }
 
+type SoongBuildMode int
+
+// Build modes that soong_build can run as.
+const (
+	// Don't use bazel at all during module analysis.
+	AnalysisNoBazel SoongBuildMode = iota
+
+	// Bp2build mode: Generate BUILD files from blueprint files and exit.
+	Bp2build
+
+	// Generate BUILD files which faithfully represent the dependency graph of
+	// blueprint modules. Individual BUILD targets will not, however, faitfhully
+	// express build semantics.
+	GenerateQueryView
+
+	// Create a JSON representation of the module graph and exit.
+	GenerateModuleGraph
+
+	// Generate a documentation file for module type definitions and exit.
+	GenerateDocFile
+
+	// Use bazel during analysis of many allowlisted build modules. The allowlist
+	// is considered a "developer mode" allowlist, as some modules may be
+	// allowlisted on an experimental basis.
+	BazelDevMode
+
+	// Use bazel during analysis of build modules from an allowlist carefully
+	// curated by the build team to be proven stable.
+	BazelProdMode
+)
+
 // SoongOutDir returns the build output directory for the configuration.
 func (c Config) SoongOutDir() string {
 	return c.soongOutDir
@@ -157,8 +188,8 @@
 	fs         pathtools.FileSystem
 	mockBpList string
 
-	runningAsBp2Build              bool
-	bp2buildPackageConfig          bp2BuildConversionAllowlist
+	BuildMode                      SoongBuildMode
+	Bp2buildPackageConfig          Bp2BuildConversionAllowlist
 	Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
 
 	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
@@ -171,6 +202,12 @@
 
 	OncePer
 
+	// These fields are only used for metrics collection. A module should be added
+	// to these maps only if its implementation supports Bazel handling in mixed
+	// builds. A module being in the "enabled" list indicates that there is a
+	// variant of that module for which bazel-handling actually took place.
+	// A module being in the "disabled" list indicates that there is a variant of
+	// that module for which bazel-handling was denied.
 	mixedBuildsLock           sync.Mutex
 	mixedBuildEnabledModules  map[string]struct{}
 	mixedBuildDisabledModules map[string]struct{}
@@ -305,6 +342,9 @@
 	if err != nil {
 		return fmt.Errorf("cannot marshal config data: %s", err.Error())
 	}
+	// The backslashes need to be escaped because this text is going to be put
+	// inside a Starlark string literal.
+	configJson = bytes.ReplaceAll(configJson, []byte("\\"), []byte("\\\\"))
 
 	bzl := []string{
 		bazel.GeneratedBazelFileWarning,
@@ -317,11 +357,11 @@
 arch_variant_product_var_constraints = _arch_variant_product_var_constraints
 `,
 	}
-	err = ioutil.WriteFile(filepath.Join(dir, "product_variables.bzl"), []byte(strings.Join(bzl, "\n")), 0644)
+	err = os.WriteFile(filepath.Join(dir, "product_variables.bzl"), []byte(strings.Join(bzl, "\n")), 0644)
 	if err != nil {
 		return fmt.Errorf("Could not write .bzl config file %s", err)
 	}
-	err = ioutil.WriteFile(filepath.Join(dir, "BUILD"), []byte(bazel.GeneratedBazelFileWarning), 0644)
+	err = os.WriteFile(filepath.Join(dir, "BUILD"), []byte(bazel.GeneratedBazelFileWarning), 0644)
 	if err != nil {
 		return fmt.Errorf("Could not write BUILD config file %s", err)
 	}
@@ -341,126 +381,9 @@
 	}
 }
 
-// TestConfig returns a Config object for testing.
-func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
-	envCopy := make(map[string]string)
-	for k, v := range env {
-		envCopy[k] = v
-	}
-
-	// Copy the real PATH value to the test environment, it's needed by
-	// NonHermeticHostSystemTool() used in x86_darwin_host.go
-	envCopy["PATH"] = os.Getenv("PATH")
-
-	config := &config{
-		productVariables: productVariables{
-			DeviceName:                          stringPtr("test_device"),
-			DeviceProduct:                       stringPtr("test_product"),
-			Platform_sdk_version:                intPtr(30),
-			Platform_sdk_codename:               stringPtr("S"),
-			Platform_base_sdk_extension_version: intPtr(1),
-			Platform_version_active_codenames:   []string{"S", "Tiramisu"},
-			DeviceSystemSdkVersions:             []string{"14", "15"},
-			Platform_systemsdk_versions:         []string{"29", "30"},
-			AAPTConfig:                          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
-			AAPTPreferredConfig:                 stringPtr("xhdpi"),
-			AAPTCharacteristics:                 stringPtr("nosdcard"),
-			AAPTPrebuiltDPI:                     []string{"xhdpi", "xxhdpi"},
-			UncompressPrivAppDex:                boolPtr(true),
-			ShippingApiLevel:                    stringPtr("30"),
-		},
-
-		outDir:       buildDir,
-		soongOutDir:  filepath.Join(buildDir, "soong"),
-		captureBuild: true,
-		env:          envCopy,
-
-		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
-		// passed to PathForSource or PathForModuleSrc.
-		TestAllowNonExistentPaths: true,
-
-		BazelContext:              noopBazelContext{},
-		mixedBuildDisabledModules: make(map[string]struct{}),
-		mixedBuildEnabledModules:  make(map[string]struct{}),
-	}
-	config.deviceConfig = &deviceConfig{
-		config: config,
-	}
-	config.TestProductVariables = &config.productVariables
-
-	config.mockFileSystem(bp, fs)
-
-	determineBuildOS(config)
-
-	return Config{config}
-}
-
-func modifyTestConfigToSupportArchMutator(testConfig Config) {
-	config := testConfig.config
-
-	config.Targets = map[OsType][]Target{
-		Android: []Target{
-			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
-			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
-		},
-		config.BuildOS: []Target{
-			{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
-			{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
-		},
-	}
-
-	if runtime.GOOS == "darwin" {
-		config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
-	}
-
-	config.BuildOSTarget = config.Targets[config.BuildOS][0]
-	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
-	config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
-	config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
-	config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
-	config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
-	config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
-	config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
-}
-
-func modifyTestConfigForMusl(config Config) {
-	delete(config.Targets, config.BuildOS)
-	config.productVariables.HostMusl = boolPtr(true)
-	determineBuildOS(config.config)
-	config.Targets[config.BuildOS] = []Target{
-		{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
-		{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
-	}
-
-	config.BuildOSTarget = config.Targets[config.BuildOS][0]
-	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
-}
-
-// TestArchConfig returns a Config object suitable for using for tests that
-// need to run the arch mutator.
-func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
-	testConfig := TestConfig(buildDir, env, bp, fs)
-	modifyTestConfigToSupportArchMutator(testConfig)
-	return testConfig
-}
-
-// ConfigForAdditionalRun is a config object which is "reset" for another
-// bootstrap run. Only per-run data is reset. Data which needs to persist across
-// multiple runs in the same program execution is carried over (such as Bazel
-// context or environment deps).
-func ConfigForAdditionalRun(c Config) (Config, error) {
-	newConfig, err := NewConfig(c.moduleListFile, c.runGoTests, c.outDir, c.soongOutDir, c.env)
-	if err != nil {
-		return Config{}, err
-	}
-	newConfig.BazelContext = c.BazelContext
-	newConfig.envDeps = c.envDeps
-	return newConfig, nil
-}
-
 // NewConfig creates a new Config object. The srcDir argument specifies the path
 // to the root source directory. It also loads the config file, if found.
-func NewConfig(moduleListFile string, runGoTests bool, outDir, soongOutDir string, availableEnv map[string]string) (Config, error) {
+func NewConfig(moduleListFile string, buildMode SoongBuildMode, runGoTests bool, outDir, soongOutDir string, availableEnv map[string]string) (Config, error) {
 	// Make a config with default options.
 	config := &config{
 		ProductVariablesFileName: filepath.Join(soongOutDir, productVariablesFileName),
@@ -557,8 +480,9 @@
 		config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
 	}
 
+	config.BuildMode = buildMode
 	config.BazelContext, err = NewBazelContext(config)
-	config.bp2buildPackageConfig = getBp2BuildAllowList()
+	config.Bp2buildPackageConfig = GetBp2BuildAllowList()
 
 	return Config{config}, err
 }
@@ -593,6 +517,12 @@
 	c.mockBpList = blueprint.MockModuleListFile
 }
 
+// Returns true if "Bazel builds" is enabled. In this mode, part of build
+// analysis is handled by Bazel.
+func (c *config) IsMixedBuildsEnabled() bool {
+	return c.BuildMode == BazelProdMode || c.BuildMode == BazelDevMode
+}
+
 func (c *config) SetAllowMissingDependencies() {
 	c.productVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
 }
@@ -739,8 +669,7 @@
 // DeviceProduct returns the current product target. There could be multiple of
 // these per device type.
 //
-// NOTE: Do not base conditional logic on this value. It may break product
-//       inheritance.
+// NOTE: Do not base conditional logic on this value. It may break product inheritance.
 func (c *config) DeviceProduct() string {
 	return *c.productVariables.DeviceProduct
 }
@@ -761,6 +690,10 @@
 	return uncheckedFinalApiLevel(*c.productVariables.Platform_sdk_version)
 }
 
+func (c *config) PlatformSdkFinal() bool {
+	return Bool(c.productVariables.Platform_sdk_final)
+}
+
 func (c *config) PlatformSdkCodename() string {
 	return String(c.productVariables.Platform_sdk_codename)
 }
@@ -798,7 +731,7 @@
 }
 
 func (c *config) MinSupportedSdkVersion() ApiLevel {
-	return uncheckedFinalApiLevel(19)
+	return uncheckedFinalApiLevel(21)
 }
 
 func (c *config) FinalApiLevels() []ApiLevel {
@@ -907,6 +840,15 @@
 	return PathForSource(ctx, filepath.Dir(defaultCert))
 }
 
+// Certificate for the NetworkStack sepolicy context
+func (c *config) MainlineSepolicyDevCertificatesDir(ctx ModuleContext) SourcePath {
+	cert := String(c.productVariables.MainlineSepolicyDevCertificates)
+	if cert != "" {
+		return PathForSource(ctx, cert)
+	}
+	return c.DefaultAppCertificateDir(ctx)
+}
+
 // AllowMissingDependencies configures Blueprint/Soong to not fail when modules
 // are configured to depend on non-existent modules. Note that this does not
 // affect missing input dependencies at the Ninja level.
@@ -1677,6 +1619,10 @@
 	return uncheckedFinalApiLevel(apiLevel)
 }
 
+func (c *deviceConfig) BuildBrokenClangProperty() bool {
+	return c.config.productVariables.BuildBrokenClangProperty
+}
+
 func (c *deviceConfig) BuildBrokenEnforceSyspropOwner() bool {
 	return c.config.productVariables.BuildBrokenEnforceSyspropOwner
 }
@@ -1729,316 +1675,6 @@
 	return c.productVariables.IgnorePrefer32OnDevice
 }
 
-// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
-// Such lists are used in the build system for things like bootclasspath jars or system server jars.
-// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
-// module name. The pairs come from Make product variables as a list of colon-separated strings.
-//
-// Examples:
-//   - "com.android.art:core-oj"
-//   - "platform:framework"
-//   - "system_ext:foo"
-//
-type ConfiguredJarList struct {
-	// A list of apex components, which can be an apex name,
-	// or special names like "platform" or "system_ext".
-	apexes []string
-
-	// A list of jar module name components.
-	jars []string
-}
-
-// Len returns the length of the list of jars.
-func (l *ConfiguredJarList) Len() int {
-	return len(l.jars)
-}
-
-// Jar returns the idx-th jar component of (apex, jar) pairs.
-func (l *ConfiguredJarList) Jar(idx int) string {
-	return l.jars[idx]
-}
-
-// Apex returns the idx-th apex component of (apex, jar) pairs.
-func (l *ConfiguredJarList) Apex(idx int) string {
-	return l.apexes[idx]
-}
-
-// ContainsJar returns true if the (apex, jar) pairs contains a pair with the
-// given jar module name.
-func (l *ConfiguredJarList) ContainsJar(jar string) bool {
-	return InList(jar, l.jars)
-}
-
-// If the list contains the given (apex, jar) pair.
-func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
-	for i := 0; i < l.Len(); i++ {
-		if apex == l.apexes[i] && jar == l.jars[i] {
-			return true
-		}
-	}
-	return false
-}
-
-// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
-// an empty string if not found.
-func (l *ConfiguredJarList) ApexOfJar(jar string) string {
-	if idx := IndexList(jar, l.jars); idx != -1 {
-		return l.Apex(IndexList(jar, l.jars))
-	}
-	return ""
-}
-
-// IndexOfJar returns the first pair with the given jar name on the list, or -1
-// if not found.
-func (l *ConfiguredJarList) IndexOfJar(jar string) int {
-	return IndexList(jar, l.jars)
-}
-
-func copyAndAppend(list []string, item string) []string {
-	// Create the result list to be 1 longer than the input.
-	result := make([]string, len(list)+1)
-
-	// Copy the whole input list into the result.
-	count := copy(result, list)
-
-	// Insert the extra item at the end.
-	result[count] = item
-
-	return result
-}
-
-// Append an (apex, jar) pair to the list.
-func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
-	// Create a copy of the backing arrays before appending to avoid sharing backing
-	// arrays that are mutated across instances.
-	apexes := copyAndAppend(l.apexes, apex)
-	jars := copyAndAppend(l.jars, jar)
-
-	return ConfiguredJarList{apexes, jars}
-}
-
-// Append a list of (apex, jar) pairs to the list.
-func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
-	apexes := make([]string, 0, l.Len()+other.Len())
-	jars := make([]string, 0, l.Len()+other.Len())
-
-	apexes = append(apexes, l.apexes...)
-	jars = append(jars, l.jars...)
-
-	apexes = append(apexes, other.apexes...)
-	jars = append(jars, other.jars...)
-
-	return ConfiguredJarList{apexes, jars}
-}
-
-// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
-func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
-	apexes := make([]string, 0, l.Len())
-	jars := make([]string, 0, l.Len())
-
-	for i, jar := range l.jars {
-		apex := l.apexes[i]
-		if !list.containsApexJarPair(apex, jar) {
-			apexes = append(apexes, apex)
-			jars = append(jars, jar)
-		}
-	}
-
-	return ConfiguredJarList{apexes, jars}
-}
-
-// Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
-// and any remaining jars that are not on this list.
-func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
-	var apexes []string
-	var jars []string
-
-	for i, jar := range l.jars {
-		if InList(jar, jarsToKeep) {
-			apexes = append(apexes, l.apexes[i])
-			jars = append(jars, jar)
-		}
-	}
-
-	return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
-}
-
-// CopyOfJars returns a copy of the list of strings containing jar module name
-// components.
-func (l *ConfiguredJarList) CopyOfJars() []string {
-	return CopyOf(l.jars)
-}
-
-// CopyOfApexJarPairs returns a copy of the list of strings with colon-separated
-// (apex, jar) pairs.
-func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
-	pairs := make([]string, 0, l.Len())
-
-	for i, jar := range l.jars {
-		apex := l.apexes[i]
-		pairs = append(pairs, apex+":"+jar)
-	}
-
-	return pairs
-}
-
-// BuildPaths returns a list of build paths based on the given directory prefix.
-func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
-	paths := make(WritablePaths, l.Len())
-	for i, jar := range l.jars {
-		paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
-	}
-	return paths
-}
-
-// BuildPathsByModule returns a map from module name to build paths based on the given directory
-// prefix.
-func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
-	paths := map[string]WritablePath{}
-	for _, jar := range l.jars {
-		paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
-	}
-	return paths
-}
-
-// UnmarshalJSON converts JSON configuration from raw bytes into a
-// ConfiguredJarList structure.
-func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
-	// Try and unmarshal into a []string each item of which contains a pair
-	// <apex>:<jar>.
-	var list []string
-	err := json.Unmarshal(b, &list)
-	if err != nil {
-		// Did not work so return
-		return err
-	}
-
-	apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
-	if err != nil {
-		return err
-	}
-	l.apexes = apexes
-	l.jars = jars
-	return nil
-}
-
-func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) {
-	if len(l.apexes) != len(l.jars) {
-		return nil, errors.New(fmt.Sprintf("Inconsistent ConfiguredJarList: apexes: %q, jars: %q", l.apexes, l.jars))
-	}
-
-	list := make([]string, 0, len(l.apexes))
-
-	for i := 0; i < len(l.apexes); i++ {
-		list = append(list, l.apexes[i]+":"+l.jars[i])
-	}
-
-	return json.Marshal(list)
-}
-
-// ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
-//
-// TODO(b/139391334): hard coded until we find a good way to query the stem of a
-// module before any other mutators are run.
-func ModuleStem(module string) string {
-	if module == "framework-minus-apex" {
-		return "framework"
-	}
-	return module
-}
-
-// DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
-// based on the operating system.
-func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
-	paths := make([]string, l.Len())
-	for i, jar := range l.jars {
-		apex := l.apexes[i]
-		name := ModuleStem(jar) + ".jar"
-
-		var subdir string
-		if apex == "platform" {
-			subdir = "system/framework"
-		} else if apex == "system_ext" {
-			subdir = "system_ext/framework"
-		} else {
-			subdir = filepath.Join("apex", apex, "javalib")
-		}
-
-		if ostype.Class == Host {
-			paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
-		} else {
-			paths[i] = filepath.Join("/", subdir, name)
-		}
-	}
-	return paths
-}
-
-func (l *ConfiguredJarList) String() string {
-	var pairs []string
-	for i := 0; i < l.Len(); i++ {
-		pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
-	}
-	return strings.Join(pairs, ",")
-}
-
-func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
-	// Now we need to populate this list by splitting each item in the slice of
-	// pairs and appending them to the appropriate list of apexes or jars.
-	apexes := make([]string, len(list))
-	jars := make([]string, len(list))
-
-	for i, apexjar := range list {
-		apex, jar, err := splitConfiguredJarPair(apexjar)
-		if err != nil {
-			return nil, nil, err
-		}
-		apexes[i] = apex
-		jars[i] = jar
-	}
-
-	return apexes, jars, nil
-}
-
-// Expected format for apexJarValue = <apex name>:<jar name>
-func splitConfiguredJarPair(str string) (string, string, error) {
-	pair := strings.SplitN(str, ":", 2)
-	if len(pair) == 2 {
-		apex := pair[0]
-		jar := pair[1]
-		if apex == "" {
-			return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
-		}
-		return apex, jar, nil
-	} else {
-		return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
-	}
-}
-
-// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
-func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
-	// Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
-	// a json list of strings and then unmarshalling into a ConfiguredJarList instance.
-	b, err := json.Marshal(list)
-	if err != nil {
-		panic(err)
-	}
-
-	var jarList ConfiguredJarList
-	err = json.Unmarshal(b, &jarList)
-	if err != nil {
-		panic(err)
-	}
-
-	return jarList
-}
-
-// EmptyConfiguredJarList returns an empty jar list.
-func EmptyConfiguredJarList() ConfiguredJarList {
-	return ConfiguredJarList{}
-}
-
-var earlyBootJarsKey = NewOnceKey("earlyBootJars")
-
 func (c *config) BootJars() []string {
 	return c.Once(earlyBootJarsKey, func() interface{} {
 		list := c.productVariables.BootJars.CopyOfJars()
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index 748be62..d6b2bcf 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -240,10 +240,12 @@
 // ExportedVariableReferenceDictVariables is a mapping from variable names to a
 // dictionary which references previously defined variables. This is used to
 // create a Starlark output such as:
-// 		string_var1 = "string1
-// 		var_ref_dict_var1 = {
-// 			"key1": string_var1
-// 		}
+//
+//	string_var1 = "string1
+//	var_ref_dict_var1 = {
+//		"key1": string_var1
+//	}
+//
 // This type of variable collection must be expanded last so that it recognizes
 // previously defined variables.
 type ExportedVariableReferenceDictVariables map[string]map[string]string
diff --git a/android/configured_jars.go b/android/configured_jars.go
new file mode 100644
index 0000000..53fef05
--- /dev/null
+++ b/android/configured_jars.go
@@ -0,0 +1,314 @@
+// 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 (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"path/filepath"
+	"strings"
+)
+
+// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
+// Such lists are used in the build system for things like bootclasspath jars or system server jars.
+// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
+// module name. The pairs come from Make product variables as a list of colon-separated strings.
+//
+// Examples:
+//   - "com.android.art:core-oj"
+//   - "platform:framework"
+//   - "system_ext:foo"
+type ConfiguredJarList struct {
+	// A list of apex components, which can be an apex name,
+	// or special names like "platform" or "system_ext".
+	apexes []string
+
+	// A list of jar module name components.
+	jars []string
+}
+
+// Len returns the length of the list of jars.
+func (l *ConfiguredJarList) Len() int {
+	return len(l.jars)
+}
+
+// Jar returns the idx-th jar component of (apex, jar) pairs.
+func (l *ConfiguredJarList) Jar(idx int) string {
+	return l.jars[idx]
+}
+
+// Apex returns the idx-th apex component of (apex, jar) pairs.
+func (l *ConfiguredJarList) Apex(idx int) string {
+	return l.apexes[idx]
+}
+
+// ContainsJar returns true if the (apex, jar) pairs contains a pair with the
+// given jar module name.
+func (l *ConfiguredJarList) ContainsJar(jar string) bool {
+	return InList(jar, l.jars)
+}
+
+// If the list contains the given (apex, jar) pair.
+func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
+	for i := 0; i < l.Len(); i++ {
+		if apex == l.apexes[i] && jar == l.jars[i] {
+			return true
+		}
+	}
+	return false
+}
+
+// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
+// an empty string if not found.
+func (l *ConfiguredJarList) ApexOfJar(jar string) string {
+	if idx := IndexList(jar, l.jars); idx != -1 {
+		return l.Apex(IndexList(jar, l.jars))
+	}
+	return ""
+}
+
+// IndexOfJar returns the first pair with the given jar name on the list, or -1
+// if not found.
+func (l *ConfiguredJarList) IndexOfJar(jar string) int {
+	return IndexList(jar, l.jars)
+}
+
+func copyAndAppend(list []string, item string) []string {
+	// Create the result list to be 1 longer than the input.
+	result := make([]string, len(list)+1)
+
+	// Copy the whole input list into the result.
+	count := copy(result, list)
+
+	// Insert the extra item at the end.
+	result[count] = item
+
+	return result
+}
+
+// Append an (apex, jar) pair to the list.
+func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
+	// Create a copy of the backing arrays before appending to avoid sharing backing
+	// arrays that are mutated across instances.
+	apexes := copyAndAppend(l.apexes, apex)
+	jars := copyAndAppend(l.jars, jar)
+
+	return ConfiguredJarList{apexes, jars}
+}
+
+// Append a list of (apex, jar) pairs to the list.
+func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
+	apexes := make([]string, 0, l.Len()+other.Len())
+	jars := make([]string, 0, l.Len()+other.Len())
+
+	apexes = append(apexes, l.apexes...)
+	jars = append(jars, l.jars...)
+
+	apexes = append(apexes, other.apexes...)
+	jars = append(jars, other.jars...)
+
+	return ConfiguredJarList{apexes, jars}
+}
+
+// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
+func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
+	apexes := make([]string, 0, l.Len())
+	jars := make([]string, 0, l.Len())
+
+	for i, jar := range l.jars {
+		apex := l.apexes[i]
+		if !list.containsApexJarPair(apex, jar) {
+			apexes = append(apexes, apex)
+			jars = append(jars, jar)
+		}
+	}
+
+	return ConfiguredJarList{apexes, jars}
+}
+
+// Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
+// and any remaining jars that are not on this list.
+func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
+	var apexes []string
+	var jars []string
+
+	for i, jar := range l.jars {
+		if InList(jar, jarsToKeep) {
+			apexes = append(apexes, l.apexes[i])
+			jars = append(jars, jar)
+		}
+	}
+
+	return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
+}
+
+// CopyOfJars returns a copy of the list of strings containing jar module name
+// components.
+func (l *ConfiguredJarList) CopyOfJars() []string {
+	return CopyOf(l.jars)
+}
+
+// CopyOfApexJarPairs returns a copy of the list of strings with colon-separated
+// (apex, jar) pairs.
+func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
+	pairs := make([]string, 0, l.Len())
+
+	for i, jar := range l.jars {
+		apex := l.apexes[i]
+		pairs = append(pairs, apex+":"+jar)
+	}
+
+	return pairs
+}
+
+// BuildPaths returns a list of build paths based on the given directory prefix.
+func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
+	paths := make(WritablePaths, l.Len())
+	for i, jar := range l.jars {
+		paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
+	}
+	return paths
+}
+
+// BuildPathsByModule returns a map from module name to build paths based on the given directory
+// prefix.
+func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
+	paths := map[string]WritablePath{}
+	for _, jar := range l.jars {
+		paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
+	}
+	return paths
+}
+
+// UnmarshalJSON converts JSON configuration from raw bytes into a
+// ConfiguredJarList structure.
+func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
+	// Try and unmarshal into a []string each item of which contains a pair
+	// <apex>:<jar>.
+	var list []string
+	err := json.Unmarshal(b, &list)
+	if err != nil {
+		// Did not work so return
+		return err
+	}
+
+	apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
+	if err != nil {
+		return err
+	}
+	l.apexes = apexes
+	l.jars = jars
+	return nil
+}
+
+func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) {
+	if len(l.apexes) != len(l.jars) {
+		return nil, errors.New(fmt.Sprintf("Inconsistent ConfiguredJarList: apexes: %q, jars: %q", l.apexes, l.jars))
+	}
+
+	list := make([]string, 0, len(l.apexes))
+
+	for i := 0; i < len(l.apexes); i++ {
+		list = append(list, l.apexes[i]+":"+l.jars[i])
+	}
+
+	return json.Marshal(list)
+}
+
+// ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
+//
+// TODO(b/139391334): hard coded until we find a good way to query the stem of a
+// module before any other mutators are run.
+func ModuleStem(module string) string {
+	if module == "framework-minus-apex" {
+		return "framework"
+	}
+	return module
+}
+
+// DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
+// based on the operating system.
+func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
+	paths := make([]string, l.Len())
+	for i, jar := range l.jars {
+		apex := l.apexes[i]
+		name := ModuleStem(jar) + ".jar"
+
+		var subdir string
+		if apex == "platform" {
+			subdir = "system/framework"
+		} else if apex == "system_ext" {
+			subdir = "system_ext/framework"
+		} else {
+			subdir = filepath.Join("apex", apex, "javalib")
+		}
+
+		if ostype.Class == Host {
+			paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
+		} else {
+			paths[i] = filepath.Join("/", subdir, name)
+		}
+	}
+	return paths
+}
+
+func (l *ConfiguredJarList) String() string {
+	var pairs []string
+	for i := 0; i < l.Len(); i++ {
+		pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
+	}
+	return strings.Join(pairs, ",")
+}
+
+func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
+	// Now we need to populate this list by splitting each item in the slice of
+	// pairs and appending them to the appropriate list of apexes or jars.
+	apexes := make([]string, len(list))
+	jars := make([]string, len(list))
+
+	for i, apexjar := range list {
+		apex, jar, err := splitConfiguredJarPair(apexjar)
+		if err != nil {
+			return nil, nil, err
+		}
+		apexes[i] = apex
+		jars[i] = jar
+	}
+
+	return apexes, jars, nil
+}
+
+// Expected format for apexJarValue = <apex name>:<jar name>
+func splitConfiguredJarPair(str string) (string, string, error) {
+	pair := strings.SplitN(str, ":", 2)
+	if len(pair) == 2 {
+		apex := pair[0]
+		jar := pair[1]
+		if apex == "" {
+			return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
+		}
+		return apex, jar, nil
+	} else {
+		return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
+	}
+}
+
+// EmptyConfiguredJarList returns an empty jar list.
+func EmptyConfiguredJarList() ConfiguredJarList {
+	return ConfiguredJarList{}
+}
+
+var earlyBootJarsKey = NewOnceKey("earlyBootJars")
diff --git a/android/defaults.go b/android/defaults.go
index 54f44bc..7906e94 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -151,12 +151,12 @@
 // retrieve the values it is necessary to iterate over properties(). E.g. to get
 // the commonProperties instance that have the real values:
 //
-//   d := myModule.(Defaults)
-//   for _, props := range d.properties() {
-//     if cp, ok := props.(*commonProperties); ok {
-//       ... access property values in cp ...
-//     }
-//   }
+//	d := myModule.(Defaults)
+//	for _, props := range d.properties() {
+//	  if cp, ok := props.(*commonProperties); ok {
+//	    ... access property values in cp ...
+//	  }
+//	}
 //
 // The rationale is that the properties on a defaults module apply to the
 // defaultable modules using it, not to the defaults module itself. E.g. setting
@@ -448,7 +448,7 @@
 	}
 
 	for _, defaults := range defaultsList {
-		if ctx.Config().runningAsBp2Build {
+		if ctx.Config().BuildMode == Bp2build {
 			applyNamespacedVariableDefaults(defaults, ctx)
 		}
 
diff --git a/android/defs.go b/android/defs.go
index 362b382..2a28e98 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -68,7 +68,7 @@
 
 	CpExecutable = pctx.AndroidStaticRule("CpExecutable",
 		blueprint.RuleParams{
-			Command:     "rm -f $out && cp $cpPreserveSymlinks $cpFlags $in $out && chmod +x $out$extraCmds",
+			Command:     "rm -f $out && cp $cpFlags $in $out && chmod +x $out$extraCmds",
 			Description: "cp $out",
 		},
 		"cpFlags", "extraCmds")
diff --git a/android/filegroup.go b/android/filegroup.go
index 9e5769a..e609f63 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,6 +15,8 @@
 package android
 
 import (
+	"path/filepath"
+	"regexp"
 	"strings"
 
 	"android/soong/bazel"
@@ -36,11 +38,44 @@
 	return ctx.OtherModuleType(m) == "filegroup"
 }
 
+var (
+	// ignoring case, checks for proto or protos as an independent word in the name, whether at the
+	// beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
+	filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
+	filegroupLikelyAidlPattern  = regexp.MustCompile("(?i)(^|[^a-z])aidl([^a-z]|$)")
+
+	ProtoSrcLabelPartition = bazel.LabelPartition{
+		Extensions:  []string{".proto"},
+		LabelMapper: isFilegroupWithPattern(filegroupLikelyProtoPattern),
+	}
+	AidlSrcLabelPartition = bazel.LabelPartition{
+		Extensions:  []string{".aidl"},
+		LabelMapper: isFilegroupWithPattern(filegroupLikelyAidlPattern),
+	}
+)
+
+func isFilegroupWithPattern(pattern *regexp.Regexp) bazel.LabelMapper {
+	return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+		m, exists := ctx.ModuleFromName(label.OriginalModuleName)
+		labelStr := label.Label
+		if !exists || !IsFilegroup(ctx, m) {
+			return labelStr, false
+		}
+		likelyMatched := pattern.MatchString(label.OriginalModuleName)
+		return labelStr, likelyMatched
+	}
+}
+
 // https://docs.bazel.build/versions/master/be/general.html#filegroup
 type bazelFilegroupAttributes struct {
 	Srcs bazel.LabelListAttribute
 }
 
+type bazelAidlLibraryAttributes struct {
+	Srcs                bazel.LabelListAttribute
+	Strip_import_prefix *string
+}
+
 // ConvertWithBp2build performs bp2build conversion of filegroup
 func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
 	srcs := bazel.MakeLabelListAttribute(
@@ -66,16 +101,33 @@
 		}
 	}
 
-	attrs := &bazelFilegroupAttributes{
-		Srcs: srcs,
-	}
+	// Convert module that has only AIDL files to aidl_library
+	// If the module has a mixed bag of AIDL and non-AIDL files, split the filegroup manually
+	// and then convert
+	if fg.ShouldConvertToAidlLibrary(ctx) {
+		attrs := &bazelAidlLibraryAttributes{
+			Srcs:                srcs,
+			Strip_import_prefix: fg.properties.Path,
+		}
 
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "filegroup",
-		Bzl_load_location: "//build/bazel/rules:filegroup.bzl",
-	}
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class:        "aidl_library",
+			Bzl_load_location: "//build/bazel/rules/aidl:library.bzl",
+		}
 
-	ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
+		ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
+	} else {
+		attrs := &bazelFilegroupAttributes{
+			Srcs: srcs,
+		}
+
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class:        "filegroup",
+			Bzl_load_location: "//build/bazel/rules:filegroup.bzl",
+		}
+
+		ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
+	}
 }
 
 type fileGroupProperties struct {
@@ -98,12 +150,14 @@
 type fileGroup struct {
 	ModuleBase
 	BazelModuleBase
+	Bp2buildAidlLibrary
 	properties fileGroupProperties
 	srcs       Paths
 }
 
 var _ MixedBuildBuildable = (*fileGroup)(nil)
 var _ SourceFileProducer = (*fileGroup)(nil)
+var _ Bp2buildAidlLibrary = (*fileGroup)(nil)
 
 // filegroup contains a list of files that are referenced by other modules
 // properties (such as "srcs") using the syntax ":<name>". filegroup are
@@ -164,12 +218,17 @@
 }
 
 func (fg *fileGroup) ProcessBazelQueryResponse(ctx ModuleContext) {
-	fg.srcs = PathsForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)
+	bazelCtx := ctx.Config().BazelContext
+	// This is a short-term solution because we rely on info from Android.bp to handle
+	// a converted module. This will block when we want to remove Android.bp for all
+	// converted modules at some point.
+	// TODO(b/242847534): Implement a long-term solution in which we don't need to rely
+	// on info form Android.bp for modules that are already converted to Bazel
+	relativeRoot := ctx.ModuleDir()
 	if fg.properties.Path != nil {
-		fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
+		relativeRoot = filepath.Join(relativeRoot, *fg.properties.Path)
 	}
 
-	bazelCtx := ctx.Config().BazelContext
 	filePaths, err := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{Common.String(), CommonOS})
 	if err != nil {
 		ctx.ModuleErrorf(err.Error())
@@ -178,8 +237,40 @@
 
 	bazelOuts := make(Paths, 0, len(filePaths))
 	for _, p := range filePaths {
-		bazelOuts = append(bazelOuts, PathForBazelOutRelative(ctx, ctx.ModuleDir(), p))
+		bazelOuts = append(bazelOuts, PathForBazelOutRelative(ctx, relativeRoot, p))
 	}
-
 	fg.srcs = bazelOuts
 }
+
+func (fg *fileGroup) ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool {
+	if len(fg.properties.Srcs) == 0 || !fg.ShouldConvertWithBp2build(ctx) {
+		return false
+	}
+	for _, src := range fg.properties.Srcs {
+		if !strings.HasSuffix(src, ".aidl") {
+			return false
+		}
+	}
+	return true
+}
+
+func (fg *fileGroup) GetAidlLibraryLabel(ctx BazelConversionPathContext) string {
+	if ctx.OtherModuleDir(fg.module) == ctx.ModuleDir() {
+		return ":" + fg.Name()
+	} else {
+		return fg.GetBazelLabel(ctx, fg)
+	}
+}
+
+// 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 module, ok := ctx.ModuleFromName(name); ok {
+		if IsFilegroup(ctx, module) {
+			if fg, ok := module.(Bp2buildAidlLibrary); ok {
+				return fg.ShouldConvertToAidlLibrary(ctx)
+			}
+		}
+	}
+	return false
+}
diff --git a/android/filegroup_test.go b/android/filegroup_test.go
new file mode 100644
index 0000000..a7ea805
--- /dev/null
+++ b/android/filegroup_test.go
@@ -0,0 +1,58 @@
+package android
+
+import (
+	"path/filepath"
+	"testing"
+)
+
+func TestFileGroupWithPathProp(t *testing.T) {
+	outBaseDir := "outputbase"
+	pathPrefix := outBaseDir + "/execroot/__main__"
+	expectedOutputfile := filepath.Join(pathPrefix, "a/b/c/d/test.aidl")
+
+	testCases := []struct {
+		bp  string
+		rel string
+	}{
+		{
+			bp: `
+	filegroup {
+		name: "baz",
+		srcs: ["a/b/c/d/test.aidl"],
+		path: "a/b",
+		bazel_module: { label: "//:baz" },
+	}
+`,
+			rel: "c/d/test.aidl",
+		},
+		{
+			bp: `
+	filegroup {
+		name: "baz",
+		srcs: ["a/b/c/d/test.aidl"],
+		bazel_module: { label: "//:baz" },
+	}
+`,
+			rel: "a/b/c/d/test.aidl",
+		},
+	}
+
+	for _, testCase := range testCases {
+		outBaseDir := "outputbase"
+		result := GroupFixturePreparers(
+			PrepareForTestWithFilegroup,
+			FixtureModifyConfig(func(config Config) {
+				config.BazelContext = MockBazelContext{
+					OutputBaseDir: outBaseDir,
+					LabelToOutputFiles: map[string][]string{
+						"//:baz": []string{"a/b/c/d/test.aidl"},
+					},
+				}
+			}),
+		).RunTestWithBp(t, testCase.bp)
+
+		fg := result.Module("baz", "").(*fileGroup)
+		AssertStringEquals(t, "src relativeRoot", testCase.rel, fg.srcs[0].Rel())
+		AssertStringEquals(t, "src full path", expectedOutputfile, fg.srcs[0].String())
+	}
+}
diff --git a/android/fixture.go b/android/fixture.go
index 0690a5a..f33e718 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -420,11 +420,13 @@
 // instances.
 //
 // base      - a list of already flattened and deduped preparers that will be applied first before
-//             the list of additional preparers. Any duplicates of these in the additional preparers
-//             will be ignored.
+//
+//	the list of additional preparers. Any duplicates of these in the additional preparers
+//	will be ignored.
 //
 // preparers - a list of additional unflattened, undeduped preparers that will be applied after the
-//             base preparers.
+//
+//	base preparers.
 //
 // Returns a deduped and flattened list of the preparers starting with the ones in base with any
 // additional ones from the preparers list added afterwards.
@@ -498,10 +500,10 @@
 // FixtureErrorHandler determines how to respond to errors reported by the code under test.
 //
 // Some possible responses:
-// * Fail the test if any errors are reported, see FixtureExpectsNoErrors.
-// * Fail the test if at least one error that matches a pattern is not reported see
-//   FixtureExpectsAtLeastOneErrorMatchingPattern
-// * Fail the test if any unexpected errors are reported.
+//   - Fail the test if any errors are reported, see FixtureExpectsNoErrors.
+//   - Fail the test if at least one error that matches a pattern is not reported see
+//     FixtureExpectsAtLeastOneErrorMatchingPattern
+//   - Fail the test if any unexpected errors are reported.
 //
 // Although at the moment all the error handlers are implemented as simply a wrapper around a
 // function this is defined as an interface to allow future enhancements, e.g. provide different
@@ -640,6 +642,20 @@
 	NinjaDeps []string
 }
 
+type TestPathContext struct {
+	*TestResult
+}
+
+var _ PathContext = &TestPathContext{}
+
+func (t *TestPathContext) Config() Config {
+	return t.TestResult.Config
+}
+
+func (t *TestPathContext) AddNinjaFileDeps(deps ...string) {
+	panic("unimplemented")
+}
+
 func createFixture(t *testing.T, buildDir string, preparers []*simpleFixturePreparer) Fixture {
 	config := TestConfig(buildDir, nil, "", nil)
 	ctx := NewTestContext(config)
@@ -866,10 +882,12 @@
 // that produced this result.
 //
 // e.g. assuming that this result was created by running:
-//     GroupFixturePreparers(preparer1, preparer2, preparer3).RunTest(t)
+//
+//	GroupFixturePreparers(preparer1, preparer2, preparer3).RunTest(t)
 //
 // Then this method will be equivalent to running:
-//     GroupFixturePreparers(preparer1, preparer2, preparer3)
+//
+//	GroupFixturePreparers(preparer1, preparer2, preparer3)
 //
 // This is intended for use by tests whose output is Android.bp files to verify that those files
 // are valid, e.g. tests of the snapshots produced by the sdk module type.
diff --git a/android/module.go b/android/module.go
index 4dbfdd3..5908233 100644
--- a/android/module.go
+++ b/android/module.go
@@ -35,10 +35,6 @@
 var (
 	DeviceSharedLibrary = "shared_library"
 	DeviceStaticLibrary = "static_library"
-	DeviceExecutable    = "executable"
-	HostSharedLibrary   = "host_shared_library"
-	HostStaticLibrary   = "host_static_library"
-	HostExecutable      = "host_executable"
 )
 
 type BuildParams struct {
@@ -909,17 +905,8 @@
 	// constants in image.go, but can also be set to a custom value by individual module types.
 	ImageVariation string `blueprint:"mutated"`
 
-	// Information about _all_ bp2build targets generated by this module. Multiple targets are
-	// supported as Soong handles some things within a single target that we may choose to split into
-	// multiple targets, e.g. renderscript, protos, yacc within a cc module.
-	Bp2buildInfo []bp2buildInfo `blueprint:"mutated"`
-
-	// UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
-	// Bazel
-	UnconvertedBp2buildDeps []string `blueprint:"mutated"`
-
-	// MissingBp2buildDep stores the module names of direct dependency that were not found
-	MissingBp2buildDeps []string `blueprint:"mutated"`
+	// Bazel conversion status
+	BazelConversionStatus BazelConversionStatus `blueprint:"mutated"`
 }
 
 // CommonAttributes represents the common Bazel attributes from which properties
@@ -949,6 +936,27 @@
 	Dists []Dist `android:"arch_variant"`
 }
 
+// CommonTestOptions represents the common `test_options` properties in
+// Android.bp.
+type CommonTestOptions struct {
+	// If the test is a hostside (no device required) unittest that shall be run
+	// during presubmit check.
+	Unit_test *bool
+
+	// Tags provide additional metadata to customize test execution by downstream
+	// test runners. The tags have no special meaning to Soong.
+	Tags []string
+}
+
+// SetAndroidMkEntries sets AndroidMkEntries according to the value of base
+// `test_options`.
+func (t *CommonTestOptions) SetAndroidMkEntries(entries *AndroidMkEntries) {
+	entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(t.Unit_test))
+	if len(t.Tags) > 0 {
+		entries.AddStrings("LOCAL_TEST_OPTIONS_TAGS", t.Tags...)
+	}
+}
+
 // The key to use in TaggedDistFiles when a Dist structure does not specify a
 // tag property. This intentionally does not use "" as the default because that
 // would mean that an empty tag would have a different meaning when used in a dist
@@ -989,8 +997,8 @@
 }
 
 func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles {
-	for _, path := range paths {
-		if path == nil {
+	for _, p := range paths {
+		if p == nil {
 			panic("The path to a dist file cannot be nil.")
 		}
 	}
@@ -1014,7 +1022,6 @@
 	MultilibFirst       Multilib = "first"
 	MultilibCommon      Multilib = "common"
 	MultilibCommonFirst Multilib = "common_first"
-	MultilibDefault     Multilib = ""
 )
 
 type HostOrDeviceSupported int
@@ -1109,7 +1116,7 @@
 // property structs for architecture-specific versions of generic properties tagged with
 // `android:"arch_variant"`.
 //
-//  InitAndroidModule should not be called if InitAndroidArchModule was called.
+//	InitAndroidModule should not be called if InitAndroidArchModule was called.
 func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
 	InitAndroidModule(m)
 
@@ -1158,23 +1165,17 @@
 
 func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext,
 	enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes {
-	// Assert passed-in attributes include Name
-	name := attrs.Name
-	if len(name) == 0 {
-		ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
-	}
 
 	mod := ctx.Module().base()
-	props := &mod.commonProperties
+	// Assert passed-in attributes include Name
+	if len(attrs.Name) == 0 {
+		ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
+	}
 
 	depsToLabelList := func(deps []string) bazel.LabelListAttribute {
 		return bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, deps))
 	}
 
-	data := &attrs.Data
-
-	archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
-
 	var enabledProperty bazel.BoolAttribute
 
 	onlyAndroid := false
@@ -1202,11 +1203,11 @@
 			neitherHostNorDevice = true
 		}
 
-		for _, os := range OsTypeList() {
-			if os.Class == Host {
-				osSupport[os.Name] = moduleSupportsHost
-			} else if os.Class == Device {
-				osSupport[os.Name] = moduleSupportsDevice
+		for _, osType := range OsTypeList() {
+			if osType.Class == Host {
+				osSupport[osType.Name] = moduleSupportsHost
+			} else if osType.Class == Device {
+				osSupport[osType.Name] = moduleSupportsDevice
 			}
 		}
 	}
@@ -1214,25 +1215,26 @@
 	if neitherHostNorDevice {
 		// we can't build this, disable
 		enabledProperty.Value = proptools.BoolPtr(false)
-	} else if props.Enabled != nil {
-		enabledProperty.SetValue(props.Enabled)
-		if !*props.Enabled {
-			for os, enabled := range osSupport {
-				if val := enabledProperty.SelectValue(bazel.OsConfigurationAxis, os); enabled && val != nil && *val {
+	} else if mod.commonProperties.Enabled != nil {
+		enabledProperty.SetValue(mod.commonProperties.Enabled)
+		if !*mod.commonProperties.Enabled {
+			for oss, enabled := range osSupport {
+				if val := enabledProperty.SelectValue(bazel.OsConfigurationAxis, oss); enabled && val != nil && *val {
 					// if this should be disabled by default, clear out any enabling we've done
-					enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, os, nil)
+					enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, oss, nil)
 				}
 			}
 		}
 	}
 
-	required := depsToLabelList(props.Required)
+	required := depsToLabelList(mod.commonProperties.Required)
+	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 name == "apexer" {
+				if attrs.Name == "apexer" {
 					requiredFiltered = make([]string, 0, len(archProps.Required))
 					for _, req := range archProps.Required {
 						if req != "aapt2" && req != "apexer" {
@@ -1287,7 +1289,7 @@
 	})
 
 	platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute(
-		bazel.LabelList{[]bazel.Label{bazel.Label{Label: "@platforms//:incompatible"}}, nil},
+		bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil},
 		bazel.LabelList{[]bazel.Label{}, nil})
 	if err != nil {
 		ctx.ModuleErrorf("Error processing platform enabled attribute: %s", err)
@@ -1300,15 +1302,13 @@
 		platformEnabledAttribute.Add(&l)
 	}
 
-	data.Append(required)
+	attrs.Data.Append(required)
 
-	constraints := constraintAttributes{}
 	moduleEnableConstraints := bazel.LabelListAttribute{}
 	moduleEnableConstraints.Append(platformEnabledAttribute)
 	moduleEnableConstraints.Append(productConfigEnabledAttribute)
-	constraints.Target_compatible_with = moduleEnableConstraints
 
-	return constraints
+	return constraintAttributes{Target_compatible_with: moduleEnableConstraints}
 }
 
 // Check product variables for `enabled: true` flag override.
@@ -1357,30 +1357,30 @@
 //
 // For example:
 //
-//     import (
-//         "android/soong/android"
-//     )
+//	import (
+//	    "android/soong/android"
+//	)
 //
-//     type myModule struct {
-//         android.ModuleBase
-//         properties struct {
-//             MyProperty string
-//         }
-//     }
+//	type myModule struct {
+//	    android.ModuleBase
+//	    properties struct {
+//	        MyProperty string
+//	    }
+//	}
 //
-//     func NewMyModule() android.Module {
-//         m := &myModule{}
-//         m.AddProperties(&m.properties)
-//         android.InitAndroidModule(m)
-//         return m
-//     }
+//	func NewMyModule() android.Module {
+//	    m := &myModule{}
+//	    m.AddProperties(&m.properties)
+//	    android.InitAndroidModule(m)
+//	    return m
+//	}
 //
-//     func (m *myModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-//         // Get the CPU architecture for the current build variant.
-//         variantArch := ctx.Arch()
+//	func (m *myModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+//	    // Get the CPU architecture for the current build variant.
+//	    variantArch := ctx.Arch()
 //
-//         // ...
-//     }
+//	    // ...
+//	}
 type ModuleBase struct {
 	// Putting the curiously recurring thing pointing to the thing that contains
 	// the thing pattern to good use.
@@ -1489,40 +1489,40 @@
 }
 
 func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
-	m.commonProperties.Bp2buildInfo = append(m.commonProperties.Bp2buildInfo, info)
+	m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info)
 }
 
 // IsConvertedByBp2build returns whether this module was converted via bp2build.
 func (m *ModuleBase) IsConvertedByBp2build() bool {
-	return len(m.commonProperties.Bp2buildInfo) > 0
+	return len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0
 }
 
 // Bp2buildTargets returns the Bazel targets bp2build generated for this module.
 func (m *ModuleBase) Bp2buildTargets() []bp2buildInfo {
-	return m.commonProperties.Bp2buildInfo
+	return m.commonProperties.BazelConversionStatus.Bp2buildInfo
 }
 
 // AddUnconvertedBp2buildDep stores module name of a dependency that was not converted to Bazel.
 func (b *baseModuleContext) AddUnconvertedBp2buildDep(dep string) {
-	unconvertedDeps := &b.Module().base().commonProperties.UnconvertedBp2buildDeps
+	unconvertedDeps := &b.Module().base().commonProperties.BazelConversionStatus.UnconvertedDeps
 	*unconvertedDeps = append(*unconvertedDeps, dep)
 }
 
 // AddMissingBp2buildDep stores module name of a dependency that was not found in a Android.bp file.
 func (b *baseModuleContext) AddMissingBp2buildDep(dep string) {
-	missingDeps := &b.Module().base().commonProperties.MissingBp2buildDeps
+	missingDeps := &b.Module().base().commonProperties.BazelConversionStatus.MissingDeps
 	*missingDeps = append(*missingDeps, dep)
 }
 
 // GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that
 // were not converted to Bazel.
 func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string {
-	return FirstUniqueStrings(m.commonProperties.UnconvertedBp2buildDeps)
+	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.UnconvertedDeps)
 }
 
 // GetMissingBp2buildDeps eturns the list of module names that were not found in Android.bp files.
 func (m *ModuleBase) GetMissingBp2buildDeps() []string {
-	return FirstUniqueStrings(m.commonProperties.MissingBp2buildDeps)
+	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.MissingDeps)
 }
 
 func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1651,7 +1651,7 @@
 	// transformSourceToObj, and should only affects unit tests.
 	vars := m.VariablesForTests()
 	buildParams := append([]BuildParams(nil), m.buildParams...)
-	for i, _ := range buildParams {
+	for i := range buildParams {
 		newArgs := make(map[string]string)
 		for k, v := range buildParams[i].Args {
 			newArgs[k] = v
@@ -2296,7 +2296,7 @@
 
 	// Some common property checks for properties that will be used later in androidmk.go
 	checkDistProperties(ctx, "dist", &m.distProperties.Dist)
-	for i, _ := range m.distProperties.Dists {
+	for i := range m.distProperties.Dists {
 		checkDistProperties(ctx, fmt.Sprintf("dists[%d]", i), &m.distProperties.Dists[i])
 	}
 
@@ -2374,9 +2374,6 @@
 }
 
 func (m *ModuleBase) isHandledByBazel(ctx ModuleContext) (MixedBuildBuildable, bool) {
-	if !ctx.Config().BazelContext.BazelEnabled() {
-		return nil, false
-	}
 	if mixedBuildMod, ok := m.module.(MixedBuildBuildable); ok {
 		if mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx) {
 			return mixedBuildMod, true
@@ -3474,14 +3471,6 @@
 	return sourceOrOutputDependencyTag{moduleName: moduleName, tag: tag}
 }
 
-// IsSourceDepTag returns true if the supplied blueprint.DependencyTag is one that was used to add
-// dependencies by either ExtractSourceDeps, ExtractSourcesDeps or automatically for properties
-// tagged with `android:"path"`.
-func IsSourceDepTag(depTag blueprint.DependencyTag) bool {
-	_, ok := depTag.(sourceOrOutputDependencyTag)
-	return ok
-}
-
 // IsSourceDepTagWithOutputTag returns true if the supplied blueprint.DependencyTag is one that was
 // used to add dependencies by either ExtractSourceDeps, ExtractSourcesDeps or automatically for
 // properties tagged with `android:"path"` AND it was added using a module reference of
@@ -3608,14 +3597,14 @@
 // be tagged with `android:"path" to support automatic source module dependency resolution.
 //
 // Deprecated: use PathForModuleSrc instead.
-func (m *moduleContext) ExpandSource(srcFile, prop string) Path {
+func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
 	return PathForModuleSrc(m, srcFile)
 }
 
 // Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
 // the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module
 // dependency resolution.
-func (m *moduleContext) ExpandOptionalSource(srcFile *string, prop string) OptionalPath {
+func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
 	if srcFile != nil {
 		return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
 	}
diff --git a/android/module_test.go b/android/module_test.go
index 77ef146..0580bef 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -911,3 +911,70 @@
 		})
 	}
 }
+
+func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) {
+	tests := []struct {
+		name        string
+		testOptions CommonTestOptions
+		expected    map[string][]string
+	}{
+		{
+			name:        "empty",
+			testOptions: CommonTestOptions{},
+			expected:    map[string][]string{},
+		},
+		{
+			name: "is unit test",
+			testOptions: CommonTestOptions{
+				Unit_test: boolPtr(true),
+			},
+			expected: map[string][]string{
+				"LOCAL_IS_UNIT_TEST": []string{"true"},
+			},
+		},
+		{
+			name: "is not unit test",
+			testOptions: CommonTestOptions{
+				Unit_test: boolPtr(false),
+			},
+			expected: map[string][]string{},
+		},
+		{
+			name: "empty tag",
+			testOptions: CommonTestOptions{
+				Tags: []string{},
+			},
+			expected: map[string][]string{},
+		},
+		{
+			name: "single tag",
+			testOptions: CommonTestOptions{
+				Tags: []string{"tag1"},
+			},
+			expected: map[string][]string{
+				"LOCAL_TEST_OPTIONS_TAGS": []string{"tag1"},
+			},
+		},
+		{
+			name: "multiple tag",
+			testOptions: CommonTestOptions{
+				Tags: []string{"tag1", "tag2", "tag3"},
+			},
+			expected: map[string][]string{
+				"LOCAL_TEST_OPTIONS_TAGS": []string{"tag1", "tag2", "tag3"},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			actualEntries := AndroidMkEntries{
+				EntryMap: map[string][]string{},
+			}
+			tt.testOptions.SetAndroidMkEntries(&actualEntries)
+			actual := actualEntries.EntryMap
+			t.Logf("actual: %v", actual)
+			t.Logf("expected: %v", tt.expected)
+			AssertDeepEquals(t, "TestProcessCommonTestOptions ", tt.expected, actual)
+		})
+	}
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index aa47bca..00078a0 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -212,11 +212,16 @@
 }
 
 func createMakefileGoalRules() []Rule {
+	allowlist := []string{
+		// libwifi_hal uses makefile_goal for its dependencies
+		"frameworks/opt/net/wifi/libwifi_hal",
+	}
 	return []Rule{
 		NeverAllow().
 			ModuleType("makefile_goal").
 			WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
-			Because("Only boot images may be imported as a makefile goal."),
+			NotIn(allowlist...).
+			Because("Only boot images may be imported as a makefile goal if not in allowed projects"),
 	}
 }
 
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 86f1a37..4772799 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -324,7 +324,32 @@
 			`),
 		},
 		expectedErrors: []string{
-			"Only boot images may be imported as a makefile goal.",
+			"Only boot images.* may be imported as a makefile goal",
+		},
+	},
+	{
+		name: "disallowed makefile_goal outside external",
+		fs: map[string][]byte{
+			"project/Android.bp": []byte(`
+				makefile_goal {
+					name: "foo",
+					product_out_path: "obj/EXE/foo",
+				}
+			`),
+		},
+		expectedErrors: []string{
+			"not in allowed projects",
+		},
+	},
+	{
+		name: "allow makefile_goal within external",
+		fs: map[string][]byte{
+			"frameworks/opt/net/wifi/libwifi_hal/Android.bp": []byte(`
+				makefile_goal {
+					name: "foo",
+					product_out_path: "obj/EXE/foo",
+				}
+			`),
 		},
 	},
 	// Tests for the rule prohibiting the use of framework
diff --git a/android/paths.go b/android/paths.go
index f8e7018..1f69125 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -387,20 +387,21 @@
 }
 
 // PathsForModuleSrc returns a Paths{} containing the resolved references in paths:
-// * filepath, relative to local module directory, resolves as a filepath relative to the local
-//   source directory
-// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
-//  source directory.
-// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-//    or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
-//    filepath.
+//   - filepath, relative to local module directory, resolves as a filepath relative to the local
+//     source directory
+//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
+//     source directory.
+//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
+//     or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
+//     filepath.
+//
 // Properties passed as the paths argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
 // path_deps mutator.
 // If a requested module is not found as a dependency:
-//   * if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
+//   - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
 //     missing dependencies
-//   * otherwise, a ModuleError is thrown.
+//   - otherwise, a ModuleError is thrown.
 func PathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) Paths {
 	return PathsForModuleSrcExcludes(ctx, paths, nil)
 }
@@ -414,21 +415,22 @@
 
 // PathsForModuleSrcExcludes returns a Paths{} containing the resolved references in paths, minus
 // those listed in excludes. Elements of paths and excludes are resolved as:
-// * filepath, relative to local module directory, resolves as a filepath relative to the local
-//   source directory
-// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
-//  source directory. Not valid in excludes.
-// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-//    or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
-//    filepath.
+//   - filepath, relative to local module directory, resolves as a filepath relative to the local
+//     source directory
+//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
+//     source directory. Not valid in excludes.
+//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
+//     or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
+//     filepath.
+//
 // excluding the items (similarly resolved
 // Properties passed as the paths argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
 // path_deps mutator.
 // If a requested module is not found as a dependency:
-//   * if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
+//   - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
 //     missing dependencies
-//   * otherwise, a ModuleError is thrown.
+//   - otherwise, a ModuleError is thrown.
 func PathsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) Paths {
 	return PathsRelativeToModuleSourceDir(SourceInput{
 		Context:      ctx,
@@ -548,13 +550,14 @@
 
 // PathsAndMissingDepsForModuleSrcExcludes returns a Paths{} containing the resolved references in
 // paths, minus those listed in excludes. Elements of paths and excludes are resolved as:
-// * filepath, relative to local module directory, resolves as a filepath relative to the local
-//   source directory
-// * glob, relative to the local module directory, resolves as filepath(s), relative to the local
-//  source directory. Not valid in excludes.
-// * other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-//    or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
-//    filepath.
+//   - filepath, relative to local module directory, resolves as a filepath relative to the local
+//     source directory
+//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
+//     source directory. Not valid in excludes.
+//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
+//     or OutputFileProducer. These resolve as a filepath to an output filepath or generated source
+//     filepath.
+//
 // and a list of the module names of missing module dependencies are returned as the second return.
 // Properties passed as the paths argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
@@ -1975,6 +1978,18 @@
 	return testPath{basePath{path: p, rel: p}}
 }
 
+func PathForTestingWithRel(path, rel string) Path {
+	p, err := validateSafePath(path, rel)
+	if err != nil {
+		panic(err)
+	}
+	r, err := validatePath(rel)
+	if err != nil {
+		panic(err)
+	}
+	return testPath{basePath{path: p, rel: r}}
+}
+
 // PathsForTesting returns a Path constructed from each element in strs. It should only be used from within tests.
 func PathsForTesting(strs ...string) Paths {
 	p := make(Paths, len(strs))
diff --git a/android/proto.go b/android/proto.go
index c3759f8..8ad16a6 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/bazel"
-	"regexp"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -27,14 +26,6 @@
 	canonicalPathFromRootDefault = true
 )
 
-var (
-	// ignoring case, checks for proto or protos as an independent word in the name, whether at the
-	// beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
-	filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
-
-	ProtoSrcLabelPartition = bazel.LabelPartition{Extensions: []string{".proto"}, LabelMapper: isProtoFilegroup}
-)
-
 // TODO(ccross): protos are often used to communicate between multiple modules.  If the only
 // way to convert a proto to source is to reference it as a source file, and external modules cannot
 // reference source files in other modules, then every module that owns a proto file will need to
@@ -213,13 +204,3 @@
 
 	return info, true
 }
-
-func isProtoFilegroup(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
-	m, exists := ctx.ModuleFromName(label.OriginalModuleName)
-	labelStr := label.Label
-	if !exists || !IsFilegroup(ctx, m) {
-		return labelStr, false
-	}
-	likelyProtos := filegroupLikelyProtoPattern.MatchString(label.OriginalModuleName)
-	return labelStr, likelyProtos
-}
diff --git a/android/register.go b/android/register.go
index 4ff8fff..d4ce5f1 100644
--- a/android/register.go
+++ b/android/register.go
@@ -164,10 +164,6 @@
 	return ctx
 }
 
-func (ctx *Context) SetRunningAsBp2build() {
-	ctx.config.runningAsBp2Build = true
-}
-
 // RegisterForBazelConversion registers an alternate shadow pipeline of
 // singletons, module types and mutators to register for converting Blueprint
 // files to semantically equivalent BUILD files.
@@ -258,20 +254,20 @@
 
 // Used to register build components from an init() method, e.g.
 //
-// init() {
-//   RegisterBuildComponents(android.InitRegistrationContext)
-// }
+//	init() {
+//	  RegisterBuildComponents(android.InitRegistrationContext)
+//	}
 //
-// func RegisterBuildComponents(ctx android.RegistrationContext) {
-//   ctx.RegisterModuleType(...)
-//   ...
-// }
+//	func RegisterBuildComponents(ctx android.RegistrationContext) {
+//	  ctx.RegisterModuleType(...)
+//	  ...
+//	}
 //
 // Extracting the actual registration into a separate RegisterBuildComponents(ctx) function
 // allows it to be used to initialize test context, e.g.
 //
-//   ctx := android.NewTestContext(config)
-//   RegisterBuildComponents(ctx)
+//	ctx := android.NewTestContext(config)
+//	RegisterBuildComponents(ctx)
 var InitRegistrationContext RegistrationContext = &initRegistrationContext{
 	moduleTypes:       make(map[string]ModuleFactory),
 	singletonTypes:    make(map[string]SingletonFactory),
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 11da36c..155fbdf 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -1031,7 +1031,8 @@
 // be also added to the dependencies returned by RuleBuilder.Tools.
 //
 // It is equivalent to:
-//  cmd.Tool(ctx.Config().HostToolPath(ctx, tool))
+//
+//	cmd.Tool(ctx.Config().HostToolPath(ctx, tool))
 func (c *RuleBuilderCommand) BuiltTool(tool string) *RuleBuilderCommand {
 	if c.rule.ctx.Config().UseHostMusl() {
 		// If the host is using musl, assume that the tool was built against musl libc and include
@@ -1053,7 +1054,8 @@
 // dependencies returned by RuleBuilder.Tools.
 //
 // It is equivalent to:
-//  cmd.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
+//
+//	cmd.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
 func (c *RuleBuilderCommand) PrebuiltBuildTool(ctx PathContext, tool string) *RuleBuilderCommand {
 	return c.Tool(ctx.Config().PrebuiltBuildTool(ctx, tool))
 }
diff --git a/android/sdk.go b/android/sdk.go
index a71f7f2..a477cba 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -430,13 +430,13 @@
 // required for some members but not others. Traits can cause additional information to be output
 // to the sdk snapshot or replace the default information exported for a member with something else.
 // e.g.
-// * By default cc libraries only export the default image variants to the SDK. However, for some
-//   members it may be necessary to export specific image variants, e.g. vendor, or recovery.
-// * By default cc libraries export all the configured architecture variants except for the native
-//   bridge architecture variants. However, for some members it may be necessary to export the
-//   native bridge architecture variants as well.
-// * By default cc libraries export the platform variant (i.e. sdk:). However, for some members it
-//   may be necessary to export the sdk variant (i.e. sdk:sdk).
+//   - By default cc libraries only export the default image variants to the SDK. However, for some
+//     members it may be necessary to export specific image variants, e.g. vendor, or recovery.
+//   - By default cc libraries export all the configured architecture variants except for the native
+//     bridge architecture variants. However, for some members it may be necessary to export the
+//     native bridge architecture variants as well.
+//   - By default cc libraries export the platform variant (i.e. sdk:). However, for some members it
+//     may be necessary to export the sdk variant (i.e. sdk:sdk).
 //
 // A sdk can request a module to provide no traits, one trait or a collection of traits. The exact
 // behavior of a trait is determined by how SdkMemberType implementations handle the traits. A trait
@@ -447,17 +447,17 @@
 // SdkPropertyName(). Each property contains a list of modules that are required to have that trait.
 // e.g. something like this:
 //
-//   sdk {
-//     name: "sdk",
-//     ...
-//     traits: {
-//       recovery_image: ["module1", "module4", "module5"],
-//       native_bridge: ["module1", "module2"],
-//       native_sdk: ["module1", "module3"],
-//       ...
-//     },
-//     ...
-//   }
+//	sdk {
+//	  name: "sdk",
+//	  ...
+//	  traits: {
+//	    recovery_image: ["module1", "module4", "module5"],
+//	    native_bridge: ["module1", "module2"],
+//	    native_sdk: ["module1", "module3"],
+//	    ...
+//	  },
+//	  ...
+//	}
 type SdkMemberTrait interface {
 	// SdkPropertyName returns the name of the traits property on an sdk module.
 	SdkPropertyName() string
@@ -639,20 +639,19 @@
 // The basic implementation should look something like this, where ModuleType is
 // the name of the module type being supported.
 //
-//    type moduleTypeSdkMemberType struct {
-//        android.SdkMemberTypeBase
-//    }
+//	type moduleTypeSdkMemberType struct {
+//	    android.SdkMemberTypeBase
+//	}
 //
-//    func init() {
-//        android.RegisterSdkMemberType(&moduleTypeSdkMemberType{
-//            SdkMemberTypeBase: android.SdkMemberTypeBase{
-//                PropertyName: "module_types",
-//            },
-//        }
-//    }
+//	func init() {
+//	    android.RegisterSdkMemberType(&moduleTypeSdkMemberType{
+//	        SdkMemberTypeBase: android.SdkMemberTypeBase{
+//	            PropertyName: "module_types",
+//	        },
+//	    }
+//	}
 //
-//    ...methods...
-//
+//	...methods...
 type SdkMemberType interface {
 	// SdkPropertyName returns the name of the member type property on an sdk module.
 	SdkPropertyName() string
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index bd73645..cd36ae0 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -190,77 +190,78 @@
 //
 // Each soong_config_variable supports an additional value `conditions_default`. The properties
 // specified in `conditions_default` will only be used under the following conditions:
-//   bool variable: the variable is unspecified or not set to a true value
-//   value variable: the variable is unspecified
-//   string variable: the variable is unspecified or the variable is set to a string unused in the
-//                    given module. For example, string variable `test` takes values: "a" and "b",
-//                    if the module contains a property `a` and `conditions_default`, when test=b,
-//                    the properties under `conditions_default` will be used. To specify that no
-//                    properties should be amended for `b`, you can set `b: {},`.
+//
+//	bool variable: the variable is unspecified or not set to a true value
+//	value variable: the variable is unspecified
+//	string variable: the variable is unspecified or the variable is set to a string unused in the
+//	                 given module. For example, string variable `test` takes values: "a" and "b",
+//	                 if the module contains a property `a` and `conditions_default`, when test=b,
+//	                 the properties under `conditions_default` will be used. To specify that no
+//	                 properties should be amended for `b`, you can set `b: {},`.
 //
 // For example, an Android.bp file could have:
 //
-//     soong_config_module_type {
-//         name: "acme_cc_defaults",
-//         module_type: "cc_defaults",
-//         config_namespace: "acme",
-//         variables: ["board"],
-//         bool_variables: ["feature"],
-//         value_variables: ["width"],
-//         properties: ["cflags", "srcs"],
-//     }
+//	    soong_config_module_type {
+//	        name: "acme_cc_defaults",
+//	        module_type: "cc_defaults",
+//	        config_namespace: "acme",
+//	        variables: ["board"],
+//	        bool_variables: ["feature"],
+//	        value_variables: ["width"],
+//	        properties: ["cflags", "srcs"],
+//	    }
 //
-//     soong_config_string_variable {
-//         name: "board",
-//         values: ["soc_a", "soc_b"],
-//     }
+//	    soong_config_string_variable {
+//	        name: "board",
+//	        values: ["soc_a", "soc_b"],
+//	    }
 //
-//     acme_cc_defaults {
-//         name: "acme_defaults",
-//         cflags: ["-DGENERIC"],
-//         soong_config_variables: {
-//             board: {
-//                 soc_a: {
-//                     cflags: ["-DSOC_A"],
-//                 },
-//                 soc_b: {
-//                     cflags: ["-DSOC_B"],
-//                 },
-//                 conditions_default: {
-//                     cflags: ["-DSOC_DEFAULT"],
-//                 },
-//             },
-//             feature: {
-//                 cflags: ["-DFEATURE"],
-//                 conditions_default: {
-//                     cflags: ["-DFEATURE_DEFAULT"],
-//                 },
-//             },
-//             width: {
-//	               cflags: ["-DWIDTH=%s"],
-//                 conditions_default: {
-//                     cflags: ["-DWIDTH=DEFAULT"],
-//                 },
-//             },
-//         },
-//     }
+//	    acme_cc_defaults {
+//	        name: "acme_defaults",
+//	        cflags: ["-DGENERIC"],
+//	        soong_config_variables: {
+//	            board: {
+//	                soc_a: {
+//	                    cflags: ["-DSOC_A"],
+//	                },
+//	                soc_b: {
+//	                    cflags: ["-DSOC_B"],
+//	                },
+//	                conditions_default: {
+//	                    cflags: ["-DSOC_DEFAULT"],
+//	                },
+//	            },
+//	            feature: {
+//	                cflags: ["-DFEATURE"],
+//	                conditions_default: {
+//	                    cflags: ["-DFEATURE_DEFAULT"],
+//	                },
+//	            },
+//	            width: {
+//		               cflags: ["-DWIDTH=%s"],
+//	                conditions_default: {
+//	                    cflags: ["-DWIDTH=DEFAULT"],
+//	                },
+//	            },
+//	        },
+//	    }
 //
-//     cc_library {
-//         name: "libacme_foo",
-//         defaults: ["acme_defaults"],
-//         srcs: ["*.cpp"],
-//     }
+//	    cc_library {
+//	        name: "libacme_foo",
+//	        defaults: ["acme_defaults"],
+//	        srcs: ["*.cpp"],
+//	    }
 //
 // If an acme BoardConfig.mk file contained:
 //
-//     SOONG_CONFIG_NAMESPACES += acme
-//     SOONG_CONFIG_acme += \
-//         board \
-//         feature \
+//	SOONG_CONFIG_NAMESPACES += acme
+//	SOONG_CONFIG_acme += \
+//	    board \
+//	    feature \
 //
-//     SOONG_CONFIG_acme_board := soc_a
-//     SOONG_CONFIG_acme_feature := true
-//     SOONG_CONFIG_acme_width := 200
+//	SOONG_CONFIG_acme_board := soc_a
+//	SOONG_CONFIG_acme_feature := true
+//	SOONG_CONFIG_acme_width := 200
 //
 // Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
 func SoongConfigModuleTypeFactory() Module {
@@ -381,7 +382,7 @@
 		defer r.Close()
 
 		mtDef, errs := soongconfig.Parse(r, from)
-		if ctx.Config().runningAsBp2Build {
+		if ctx.Config().BuildMode == Bp2build {
 			ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(*mtDef)
 		}
 
@@ -397,7 +398,7 @@
 		for name, moduleType := range mtDef.ModuleTypes {
 			factory := globalModuleTypes[moduleType.BaseModuleType]
 			if factory != nil {
-				factories[name] = configModuleFactory(factory, moduleType, ctx.Config().runningAsBp2Build)
+				factories[name] = configModuleFactory(factory, moduleType, ctx.Config().BuildMode == Bp2build)
 			} else {
 				reportErrors(ctx, from,
 					fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 212b752..7d21b75 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -343,23 +343,26 @@
 //
 // For example, the acme_cc_defaults example above would
 // produce a reflect.Value whose type is:
-// *struct {
-//     Soong_config_variables struct {
-//         Board struct {
-//             Soc_a interface{}
-//             Soc_b interface{}
-//         }
-//     }
-// }
+//
+//	*struct {
+//	    Soong_config_variables struct {
+//	        Board struct {
+//	            Soc_a interface{}
+//	            Soc_b interface{}
+//	        }
+//	    }
+//	}
+//
 // And whose value is:
-// &{
-//     Soong_config_variables: {
-//         Board: {
-//             Soc_a: (*struct{ Cflags []string })(nil),
-//             Soc_b: (*struct{ Cflags []string })(nil),
-//         },
-//     },
-// }
+//
+//	&{
+//	    Soong_config_variables: {
+//	        Board: {
+//	            Soc_a: (*struct{ Cflags []string })(nil),
+//	            Soc_b: (*struct{ Cflags []string })(nil),
+//	        },
+//	    },
+//	}
 func CreateProperties(factory blueprint.ModuleFactory, moduleType *ModuleType) reflect.Value {
 	var fields []reflect.StructField
 
diff --git a/android/test_config.go b/android/test_config.go
new file mode 100644
index 0000000..0f88d51
--- /dev/null
+++ b/android/test_config.go
@@ -0,0 +1,150 @@
+// 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 (
+	"encoding/json"
+	"os"
+	"path/filepath"
+	"runtime"
+
+	"github.com/google/blueprint/proptools"
+)
+
+// TestConfig returns a Config object for testing.
+func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+	envCopy := make(map[string]string)
+	for k, v := range env {
+		envCopy[k] = v
+	}
+
+	// Copy the real PATH value to the test environment, it's needed by
+	// NonHermeticHostSystemTool() used in x86_darwin_host.go
+	envCopy["PATH"] = os.Getenv("PATH")
+
+	config := &config{
+		productVariables: productVariables{
+			DeviceName:                          stringPtr("test_device"),
+			DeviceProduct:                       stringPtr("test_product"),
+			Platform_sdk_version:                intPtr(30),
+			Platform_sdk_codename:               stringPtr("S"),
+			Platform_base_sdk_extension_version: intPtr(1),
+			Platform_version_active_codenames:   []string{"S", "Tiramisu"},
+			DeviceSystemSdkVersions:             []string{"14", "15"},
+			Platform_systemsdk_versions:         []string{"29", "30"},
+			AAPTConfig:                          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+			AAPTPreferredConfig:                 stringPtr("xhdpi"),
+			AAPTCharacteristics:                 stringPtr("nosdcard"),
+			AAPTPrebuiltDPI:                     []string{"xhdpi", "xxhdpi"},
+			UncompressPrivAppDex:                boolPtr(true),
+			ShippingApiLevel:                    stringPtr("30"),
+		},
+
+		outDir:       buildDir,
+		soongOutDir:  filepath.Join(buildDir, "soong"),
+		captureBuild: true,
+		env:          envCopy,
+
+		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
+		// passed to PathForSource or PathForModuleSrc.
+		TestAllowNonExistentPaths: true,
+
+		BazelContext:              noopBazelContext{},
+		mixedBuildDisabledModules: make(map[string]struct{}),
+		mixedBuildEnabledModules:  make(map[string]struct{}),
+	}
+	config.deviceConfig = &deviceConfig{
+		config: config,
+	}
+	config.TestProductVariables = &config.productVariables
+
+	config.mockFileSystem(bp, fs)
+
+	determineBuildOS(config)
+
+	return Config{config}
+}
+
+func modifyTestConfigToSupportArchMutator(testConfig Config) {
+	config := testConfig.config
+
+	config.Targets = map[OsType][]Target{
+		Android: []Target{
+			{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
+			{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
+		},
+		config.BuildOS: []Target{
+			{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
+			{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
+		},
+	}
+
+	if runtime.GOOS == "darwin" {
+		config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
+	}
+
+	config.BuildOSTarget = config.Targets[config.BuildOS][0]
+	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
+	config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
+	config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
+	config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
+	config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
+	config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
+	config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
+}
+
+func modifyTestConfigForMusl(config Config) {
+	delete(config.Targets, config.BuildOS)
+	config.productVariables.HostMusl = boolPtr(true)
+	determineBuildOS(config.config)
+	config.Targets[config.BuildOS] = []Target{
+		{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
+		{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
+	}
+
+	config.BuildOSTarget = config.Targets[config.BuildOS][0]
+	config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
+}
+
+func modifyTestConfigForMuslArm64HostCross(config Config) {
+	config.Targets[LinuxMusl] = append(config.Targets[LinuxMusl],
+		Target{config.BuildOS, Arch{ArchType: Arm64}, NativeBridgeDisabled, "", "", true})
+}
+
+// TestArchConfig returns a Config object suitable for using for tests that
+// need to run the arch mutator.
+func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
+	testConfig := TestConfig(buildDir, env, bp, fs)
+	modifyTestConfigToSupportArchMutator(testConfig)
+	return testConfig
+}
+
+// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
+func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
+	// Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
+	// a json list of strings and then unmarshalling into a ConfiguredJarList instance.
+	b, err := json.Marshal(list)
+	if err != nil {
+		panic(err)
+	}
+
+	var jarList ConfiguredJarList
+	err = json.Unmarshal(b, &jarList)
+	if err != nil {
+		panic(err)
+	}
+
+	return jarList
+}
diff --git a/android/testing.go b/android/testing.go
index 85bdca4..3708501 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -213,8 +213,8 @@
 	ctx.finalDeps = append(ctx.finalDeps, f)
 }
 
-func (ctx *TestContext) RegisterBp2BuildConfig(config bp2BuildConversionAllowlist) {
-	ctx.config.bp2buildPackageConfig = config
+func (ctx *TestContext) RegisterBp2BuildConfig(config Bp2BuildConversionAllowlist) {
+	ctx.config.Bp2buildPackageConfig = config
 }
 
 // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
@@ -457,7 +457,7 @@
 
 // RegisterForBazelConversion prepares a test context for bp2build conversion.
 func (ctx *TestContext) RegisterForBazelConversion() {
-	ctx.SetRunningAsBp2build()
+	ctx.config.BuildMode = Bp2build
 	RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch)
 }
 
@@ -688,17 +688,17 @@
 //
 // The parts of this structure which are changed are:
 // * BuildParams
-//   * Args
-//   * All Path, Paths, WritablePath and WritablePaths fields.
+//   - Args
+//   - All Path, Paths, WritablePath and WritablePaths fields.
 //
 // * RuleParams
-//   * Command
-//   * Depfile
-//   * Rspfile
-//   * RspfileContent
-//   * SymlinkOutputs
-//   * CommandDeps
-//   * CommandOrderOnly
+//   - Command
+//   - Depfile
+//   - Rspfile
+//   - RspfileContent
+//   - SymlinkOutputs
+//   - CommandDeps
+//   - CommandOrderOnly
 //
 // See PathRelativeToTop for more details.
 //
diff --git a/android/variable.go b/android/variable.go
index 874b69d..7a080fe 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -249,7 +249,8 @@
 	AAPTPreferredConfig *string  `json:",omitempty"`
 	AAPTPrebuiltDPI     []string `json:",omitempty"`
 
-	DefaultAppCertificate *string `json:",omitempty"`
+	DefaultAppCertificate           *string `json:",omitempty"`
+	MainlineSepolicyDevCertificates *string `json:",omitempty"`
 
 	AppsDefaultVersionName *string `json:",omitempty"`
 
@@ -429,6 +430,7 @@
 
 	ShippingApiLevel *string `json:",omitempty"`
 
+	BuildBrokenClangProperty           bool     `json:",omitempty"`
 	BuildBrokenDepfile                 *bool    `json:",omitempty"`
 	BuildBrokenEnforceSyspropOwner     bool     `json:",omitempty"`
 	BuildBrokenTrebleSyspropNeverallow bool     `json:",omitempty"`
@@ -701,20 +703,20 @@
 //
 // If the ProductConfigProperties map contains these items, as parsed from the .bp file:
 //
-// library_linking_strategy: {
-//     prefer_static: {
-//         static_libs: [
-//             "lib_a",
-//             "lib_b",
-//         ],
-//     },
-//     conditions_default: {
-//         shared_libs: [
-//             "lib_a",
-//             "lib_b",
-//         ],
-//     },
-// },
+//	library_linking_strategy: {
+//	    prefer_static: {
+//	        static_libs: [
+//	            "lib_a",
+//	            "lib_b",
+//	        ],
+//	    },
+//	    conditions_default: {
+//	        shared_libs: [
+//	            "lib_a",
+//	            "lib_b",
+//	        ],
+//	    },
+//	},
 //
 // Static_libs {Library_linking_strategy ANDROID prefer_static} [lib_a lib_b]
 // Shared_libs {Library_linking_strategy ANDROID conditions_default} [lib_a lib_b]
@@ -727,13 +729,13 @@
 // instead of putting lib_a and lib_b directly into dynamic_deps without a
 // select:
 //
-// dynamic_deps = select({
-//     "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
-//     "//conditions:default": [
-//         "//foo/bar:lib_a",
-//         "//foo/bar:lib_b",
-//     ],
-// }),
+//	dynamic_deps = select({
+//	    "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+//	    "//conditions:default": [
+//	        "//foo/bar:lib_a",
+//	        "//foo/bar:lib_b",
+//	    ],
+//	}),
 func (props *ProductConfigProperties) zeroValuesForNamespacedVariables() {
 	// A map of product config properties to the zero values of their respective
 	// property value.
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 280dae8..f646742 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -166,9 +166,10 @@
 		}
 	} else {
 		llvmStrip := config.ClangPath(ctx, "bin/llvm-strip")
-		llvmLib := config.ClangPath(ctx, "lib64/libc++.so.1")
+		llvmLib64 := config.ClangPath(ctx, "lib64/libc++.so.1")
+		llvmLib := config.ClangPath(ctx, "lib/libc++.so.1")
 		for _, strip := range s.properties.Strip_files {
-			cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib)
+			cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib64).ImplicitTool(llvmLib)
 			if !ctx.Windows() {
 				cmd.Flag("-x")
 			}
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index aaafdc7..2e8810f 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -421,9 +421,9 @@
 // For example, if prefix is "foo" and name is "bar" with a value of "baz", then
 // the following variable will be generated:
 //
-// foo {
-//   bar: "baz"
-// }
+//	foo {
+//	  bar: "baz"
+//	}
 //
 // If prefix is the empty string and name is "foo" with a value of "bar", the
 // following variable will be generated (if it is a property):
diff --git a/androidmk/parser/make_strings.go b/androidmk/parser/make_strings.go
index 8afbe7e..be36859 100644
--- a/androidmk/parser/make_strings.go
+++ b/androidmk/parser/make_strings.go
@@ -38,10 +38,10 @@
 // For example, "$(FOO)/bar/baz" will be represented as the
 // following lists:
 //
-// {
-//   Strings: ["", "/bar/baz"],
-//   Variables: ["FOO"]
-// }
+//	{
+//	  Strings: ["", "/bar/baz"],
+//	  Variables: ["FOO"]
+//	}
 type MakeString struct {
 	StringPos Pos
 	Strings   []string
diff --git a/apex/apex.go b/apex/apex.go
index 09a5784..949809a 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -192,6 +192,10 @@
 	// with the tool to sign payload contents.
 	Custom_sign_tool *string
 
+	// Whether this is a dynamic common lib apex, if so the native shared libs will be placed
+	// in a special way that include the digest of the lib file under /lib(64)?
+	Dynamic_common_lib_apex *bool
+
 	// Canonical name of this APEX bundle. Used to determine the path to the
 	// activated APEX on device (i.e. /apex/<apexVariationName>), and used for the
 	// apex mutator variations. For override_apex modules, this is the name of the
@@ -1472,6 +1476,11 @@
 	return proptools.Bool(a.properties.Test_only_force_compression)
 }
 
+// See the dynamic_common_lib_apex property
+func (a *apexBundle) dynamic_common_lib_apex() bool {
+	return proptools.BoolDefault(a.properties.Dynamic_common_lib_apex, false)
+}
+
 // These functions are interfacing with cc/sanitizer.go. The entire APEX (along with all of its
 // members) can be sanitized, either forcibly, or by the global configuration. For some of the
 // sanitizers, extra dependencies can be forcibly added as well.
@@ -2701,7 +2710,7 @@
 
 var _ android.ModuleWithMinSdkVersionCheck = (*apexBundle)(nil)
 
-// Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version
+// Ensures that min_sdk_version of the included modules are equal or less than the min_sdk_version
 // of this apexBundle.
 func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) {
 	if a.testApex || a.vndkApex {
@@ -3015,34 +3024,9 @@
 	//
 	// Module separator
 	//
-	m["com.android.bluetooth"] = []string{
-		"android.hardware.audio.common@5.0",
-		"android.hardware.bluetooth.a2dp@1.0",
-		"android.hardware.bluetooth.audio@2.0",
-		"android.hardware.bluetooth@1.0",
-		"android.hardware.bluetooth@1.1",
-		"android.hardware.graphics.bufferqueue@1.0",
-		"android.hardware.graphics.bufferqueue@2.0",
-		"android.hardware.graphics.common@1.0",
-		"android.hardware.graphics.common@1.1",
-		"android.hardware.graphics.common@1.2",
-		"android.hardware.media@1.0",
-		"android.hidl.safe_union@1.0",
-		"android.hidl.token@1.0",
-		"android.hidl.token@1.0-utils",
-		"avrcp-target-service",
-		"avrcp_headers",
+	m["com.android.btservices"] = []string{
 		"bluetooth-protos-lite",
-		"bluetooth.mapsapi",
-		"com.android.vcard",
-		"dnsresolver_aidl_interface-V2-java",
-		"ipmemorystore-aidl-interfaces-V5-java",
-		"ipmemorystore-aidl-interfaces-java",
 		"internal_include_headers",
-		"lib-bt-packets",
-		"lib-bt-packets-avrcp",
-		"lib-bt-packets-base",
-		"libFraunhoferAAC",
 		"libaudio-a2dp-hw-utils",
 		"libaudio-hearing-aid-hw-utils",
 		"libbluetooth",
@@ -3066,28 +3050,36 @@
 		"libbte",
 		"libbtif",
 		"libchrome",
-		"libevent",
-		"libfmq",
-		"libg722codec",
-		"libgui_headers",
-		"libmedia_headers",
-		"libmodpb64",
-		"libosi",
-		"libstagefright_foundation_headers",
-		"libstagefright_headers",
-		"libstatslog",
-		"libstatssocket",
-		"libtinyxml2",
-		"libudrv-uipc",
-		"libz",
-		"media_plugin_headers",
-		"net-utils-services-common",
-		"netd_aidl_interface-unstable-java",
-		"netd_event_listener_interface-java",
-		"netlink-client",
-		"networkstack-client",
-		"sap-api-java-static",
-		"services.net",
+	}
+	//
+	// 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
@@ -3127,258 +3119,13 @@
 	// Module separator
 	//
 	m["com.android.media"] = []string{
-		"android.frameworks.bufferhub@1.0",
-		"android.hardware.cas.native@1.0",
-		"android.hardware.cas@1.0",
-		"android.hardware.configstore-utils",
-		"android.hardware.configstore@1.0",
-		"android.hardware.configstore@1.1",
-		"android.hardware.graphics.allocator@2.0",
-		"android.hardware.graphics.allocator@3.0",
-		"android.hardware.graphics.bufferqueue@1.0",
-		"android.hardware.graphics.bufferqueue@2.0",
-		"android.hardware.graphics.common@1.0",
-		"android.hardware.graphics.common@1.1",
-		"android.hardware.graphics.common@1.2",
-		"android.hardware.graphics.mapper@2.0",
-		"android.hardware.graphics.mapper@2.1",
-		"android.hardware.graphics.mapper@3.0",
-		"android.hardware.media.omx@1.0",
-		"android.hardware.media@1.0",
-		"android.hidl.allocator@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.token@1.0",
-		"android.hidl.token@1.0-utils",
-		"bionic_libc_platform_headers",
-		"exoplayer2-extractor",
-		"exoplayer2-extractor-annotation-stubs",
-		"gl_headers",
-		"jsr305",
-		"libEGL",
-		"libEGL_blobCache",
-		"libEGL_getProcAddress",
-		"libFLAC",
-		"libFLAC-config",
-		"libFLAC-headers",
-		"libGLESv2",
-		"libaacextractor",
-		"libamrextractor",
-		"libarect",
-		"libaudio_system_headers",
-		"libaudioclient",
-		"libaudioclient_headers",
-		"libaudiofoundation",
-		"libaudiofoundation_headers",
-		"libaudiomanager",
-		"libaudiopolicy",
-		"libaudioutils",
-		"libaudioutils_fixedfft",
-		"libbluetooth-types-header",
-		"libbufferhub",
-		"libbufferhub_headers",
-		"libbufferhubqueue",
-		"libc_malloc_debug_backtrace",
-		"libcamera_client",
-		"libcamera_metadata",
-		"libdvr_headers",
-		"libexpat",
-		"libfifo",
-		"libflacextractor",
-		"libgrallocusage",
-		"libgraphicsenv",
-		"libgui",
-		"libgui_headers",
-		"libhardware_headers",
-		"libinput",
-		"liblzma",
-		"libmath",
-		"libmedia",
-		"libmedia_codeclist",
-		"libmedia_headers",
-		"libmedia_helper",
-		"libmedia_helper_headers",
-		"libmedia_midiiowrapper",
-		"libmedia_omx",
-		"libmediautils",
-		"libmidiextractor",
-		"libmkvextractor",
-		"libmp3extractor",
-		"libmp4extractor",
-		"libmpeg2extractor",
-		"libnativebase_headers",
-		"libnativewindow_headers",
-		"libnblog",
-		"liboggextractor",
-		"libpackagelistparser",
-		"libpdx",
-		"libpdx_default_transport",
-		"libpdx_headers",
-		"libpdx_uds",
-		"libprocinfo",
-		"libspeexresampler",
-		"libspeexresampler",
-		"libstagefright_esds",
-		"libstagefright_flacdec",
-		"libstagefright_flacdec",
-		"libstagefright_foundation",
-		"libstagefright_foundation_headers",
-		"libstagefright_foundation_without_imemory",
-		"libstagefright_headers",
-		"libstagefright_id3",
-		"libstagefright_metadatautils",
-		"libstagefright_mpeg2extractor",
-		"libstagefright_mpeg2support",
-		"libui",
-		"libui_headers",
-		"libunwindstack",
-		"libvibrator",
-		"libvorbisidec",
-		"libwavextractor",
-		"libwebm",
-		"media_ndk_headers",
-		"media_plugin_headers",
-		"updatable-media",
+		// empty
 	}
 	//
 	// Module separator
 	//
 	m["com.android.media.swcodec"] = []string{
-		"android.frameworks.bufferhub@1.0",
-		"android.hardware.common-ndk_platform",
-		"android.hardware.configstore-utils",
-		"android.hardware.configstore@1.0",
-		"android.hardware.configstore@1.1",
-		"android.hardware.graphics.allocator@2.0",
-		"android.hardware.graphics.allocator@3.0",
-		"android.hardware.graphics.allocator@4.0",
-		"android.hardware.graphics.bufferqueue@1.0",
-		"android.hardware.graphics.bufferqueue@2.0",
-		"android.hardware.graphics.common-ndk_platform",
-		"android.hardware.graphics.common@1.0",
-		"android.hardware.graphics.common@1.1",
-		"android.hardware.graphics.common@1.2",
-		"android.hardware.graphics.mapper@2.0",
-		"android.hardware.graphics.mapper@2.1",
-		"android.hardware.graphics.mapper@3.0",
-		"android.hardware.graphics.mapper@4.0",
-		"android.hardware.media.bufferpool@2.0",
-		"android.hardware.media.c2@1.0",
-		"android.hardware.media.c2@1.1",
-		"android.hardware.media.omx@1.0",
-		"android.hardware.media@1.0",
-		"android.hardware.media@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.safe_union@1.0",
-		"android.hidl.token@1.0",
-		"android.hidl.token@1.0-utils",
-		"libEGL",
-		"libFLAC",
-		"libFLAC-config",
-		"libFLAC-headers",
-		"libFraunhoferAAC",
-		"libLibGuiProperties",
-		"libarect",
-		"libaudio_system_headers",
-		"libaudioutils",
-		"libaudioutils",
-		"libaudioutils_fixedfft",
-		"libavcdec",
-		"libavcenc",
-		"libavservices_minijail",
-		"libavservices_minijail",
-		"libbinderthreadstateutils",
-		"libbluetooth-types-header",
-		"libbufferhub_headers",
-		"libcodec2",
-		"libcodec2_headers",
-		"libcodec2_hidl@1.0",
-		"libcodec2_hidl@1.1",
-		"libcodec2_internal",
-		"libcodec2_soft_aacdec",
-		"libcodec2_soft_aacenc",
-		"libcodec2_soft_amrnbdec",
-		"libcodec2_soft_amrnbenc",
-		"libcodec2_soft_amrwbdec",
-		"libcodec2_soft_amrwbenc",
-		"libcodec2_soft_av1dec_gav1",
-		"libcodec2_soft_avcdec",
-		"libcodec2_soft_avcenc",
-		"libcodec2_soft_common",
-		"libcodec2_soft_flacdec",
-		"libcodec2_soft_flacenc",
-		"libcodec2_soft_g711alawdec",
-		"libcodec2_soft_g711mlawdec",
-		"libcodec2_soft_gsmdec",
-		"libcodec2_soft_h263dec",
-		"libcodec2_soft_h263enc",
-		"libcodec2_soft_hevcdec",
-		"libcodec2_soft_hevcenc",
-		"libcodec2_soft_mp3dec",
-		"libcodec2_soft_mpeg2dec",
-		"libcodec2_soft_mpeg4dec",
-		"libcodec2_soft_mpeg4enc",
-		"libcodec2_soft_opusdec",
-		"libcodec2_soft_opusenc",
-		"libcodec2_soft_rawdec",
-		"libcodec2_soft_vorbisdec",
-		"libcodec2_soft_vp8dec",
-		"libcodec2_soft_vp8enc",
-		"libcodec2_soft_vp9dec",
-		"libcodec2_soft_vp9enc",
-		"libcodec2_vndk",
-		"libdvr_headers",
-		"libfmq",
-		"libfmq",
-		"libgav1",
-		"libgralloctypes",
-		"libgrallocusage",
-		"libgraphicsenv",
-		"libgsm",
-		"libgui_bufferqueue_static",
-		"libgui_headers",
-		"libhardware",
-		"libhardware_headers",
-		"libhevcdec",
-		"libhevcenc",
-		"libion",
-		"libjpeg",
-		"liblzma",
-		"libmath",
-		"libmedia_codecserviceregistrant",
-		"libmedia_headers",
-		"libmpeg2dec",
-		"libnativebase_headers",
-		"libnativewindow_headers",
-		"libpdx_headers",
-		"libscudo_wrapper",
-		"libsfplugin_ccodec_utils",
-		"libspeexresampler",
-		"libstagefright_amrnb_common",
-		"libstagefright_amrnbdec",
-		"libstagefright_amrnbenc",
-		"libstagefright_amrwbdec",
-		"libstagefright_amrwbenc",
-		"libstagefright_bufferpool@2.0.1",
-		"libstagefright_enc_common",
-		"libstagefright_flacdec",
-		"libstagefright_foundation",
-		"libstagefright_foundation_headers",
-		"libstagefright_headers",
-		"libstagefright_m4vh263dec",
-		"libstagefright_m4vh263enc",
-		"libstagefright_mp3dec",
-		"libui",
-		"libui_headers",
-		"libunwindstack",
-		"libvorbisidec",
-		"libvpx",
-		"libyuv",
-		"libyuv_static",
-		"media_ndk_headers",
-		"media_plugin_headers",
-		"mediaswcodec",
+		// empty
 	}
 	//
 	// Module separator
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 5282941..49a5d2a 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -26,6 +26,7 @@
 	"strings"
 	"testing"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -9544,6 +9545,63 @@
 	}
 }
 
+func TestApexBuildsAgainstApiSurfaceStubLibraries(t *testing.T) {
+	bp := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+			min_sdk_version: "29",
+		}
+		apex_key {
+			name: "myapex.key",
+		}
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libc"],
+			apex_available: ["myapex"],
+			min_sdk_version: "29",
+		}
+		cc_api_library {
+			name: "libc",
+			src: "libc.so",
+			min_sdk_version: "29",
+			recovery_available: true,
+		}
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libc",
+			],
+			header_libs: [],
+		}
+		`
+	result := testApex(t, bp)
+
+	hasDep := func(m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		result.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	libfooApexVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex29").Module()
+	libcApexVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared_apex29").Module()
+
+	android.AssertBoolEquals(t, "apex variant should link against API surface stub libraries", true, hasDep(libfooApexVariant, libcApexVariant))
+
+	// libfoo core variant should be buildable in the same inner tree since
+	// certain mcombo files might build system and apexes in the same inner tree
+	// libfoo core variant should link against source libc
+	libfooCoreVariant := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+	libcCoreVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared").Module()
+	android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
+}
+
 func TestMain(m *testing.M) {
 	os.Exit(m.Run())
 }
diff --git a/apex/bp2build.go b/apex/bp2build.go
index 221ab13..d28f512 100644
--- a/apex/bp2build.go
+++ b/apex/bp2build.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/apex/builder.go b/apex/builder.go
index f1b1448..b95b3bd 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -39,6 +39,7 @@
 	pctx.Import("android/soong/cc/config")
 	pctx.Import("android/soong/java")
 	pctx.HostBinToolVariable("apexer", "apexer")
+	pctx.HostBinToolVariable("apexer_with_DCLA_preprocessing", "apexer_with_DCLA_preprocessing")
 	// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
 	// projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead.
 	hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
@@ -115,7 +116,35 @@
 		Rspfile:        "${out}.copy_commands",
 		RspfileContent: "${copy_commands}",
 		Description:    "APEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
+	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
+		"opt_flags", "manifest")
+
+	DCLAApexRule = pctx.StaticRule("DCLAApexRule", blueprint.RuleParams{
+		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
+			`(. ${out}.copy_commands) && ` +
+			`APEXER_TOOL_PATH=${tool_path} ` +
+			`${apexer_with_DCLA_preprocessing} ` +
+			`--apexer ${apexer} ` +
+			`--canned_fs_config ${canned_fs_config} ` +
+			`${image_dir} ` +
+			`${out} ` +
+			`-- ` +
+			`--include_build_info ` +
+			`--force ` +
+			`--payload_type image ` +
+			`--key ${key} ` +
+			`--file_contexts ${file_contexts} ` +
+			`--manifest ${manifest} ` +
+			`${opt_flags} `,
+		CommandDeps: []string{"${apexer_with_DCLA_preprocessing}", "${apexer}", "${avbtool}", "${e2fsdroid}",
+			"${merge_zips}", "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}",
+			"${sload_f2fs}", "${make_erofs}", "${soong_zip}", "${zipalign}", "${aapt2}",
+			"prebuilts/sdk/current/public/android.jar"},
+		Rspfile:        "${out}.copy_commands",
+		RspfileContent: "${copy_commands}",
+		Description:    "APEX ${image_dir} => ${out}",
+	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
+		"opt_flags", "manifest", "is_DCLA")
 
 	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
@@ -662,22 +691,41 @@
 
 		optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
 
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        apexRule,
-			Implicits:   implicitInputs,
-			Output:      unsignedOutputFile,
-			Description: "apex (" + apexType.name() + ")",
-			Args: map[string]string{
-				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-				"image_dir":        imageDir.String(),
-				"copy_commands":    strings.Join(copyCommands, " && "),
-				"manifest":         a.manifestPbOut.String(),
-				"file_contexts":    fileContexts.String(),
-				"canned_fs_config": cannedFsConfig.String(),
-				"key":              a.privateKeyFile.String(),
-				"opt_flags":        strings.Join(optFlags, " "),
-			},
-		})
+		if a.dynamic_common_lib_apex() {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        DCLAApexRule,
+				Implicits:   implicitInputs,
+				Output:      unsignedOutputFile,
+				Description: "apex (" + apexType.name() + ")",
+				Args: map[string]string{
+					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+					"image_dir":        imageDir.String(),
+					"copy_commands":    strings.Join(copyCommands, " && "),
+					"manifest":         a.manifestPbOut.String(),
+					"file_contexts":    fileContexts.String(),
+					"canned_fs_config": cannedFsConfig.String(),
+					"key":              a.privateKeyFile.String(),
+					"opt_flags":        strings.Join(optFlags, " "),
+				},
+			})
+		} else {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        apexRule,
+				Implicits:   implicitInputs,
+				Output:      unsignedOutputFile,
+				Description: "apex (" + apexType.name() + ")",
+				Args: map[string]string{
+					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+					"image_dir":        imageDir.String(),
+					"copy_commands":    strings.Join(copyCommands, " && "),
+					"manifest":         a.manifestPbOut.String(),
+					"file_contexts":    fileContexts.String(),
+					"canned_fs_config": cannedFsConfig.String(),
+					"key":              a.privateKeyFile.String(),
+					"opt_flags":        strings.Join(optFlags, " "),
+				},
+			})
+		}
 
 		// TODO(jiyong): make the two rules below as separate functions
 		apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
diff --git a/apex/key.go b/apex/key.go
index 9c5bb05..d449589 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -105,7 +105,7 @@
 	m.keyName = pubKeyName
 }
 
-////////////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////////
 // apex_keys_text
 type apexKeysText struct {
 	output android.OutputPath
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 187e0df..172a201 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -364,16 +364,16 @@
 // While it may be possible to provide sufficient information to determine whether two prebuilt_apex
 // modules were compatible it would be a lot of work and would not provide much benefit for a couple
 // of reasons:
-// * The number of prebuilt_apex modules that will be exporting files for the same module will be
-//   low as the prebuilt_apex only exports files for the direct dependencies that require it and
-//   very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
-//   few com.android.art* apex files that contain the same contents and could export files for the
-//   same modules but only one of them needs to do so. Contrast that with source apex modules which
-//   need apex specific variants for every module that contributes code to the apex, whether direct
-//   or indirect.
-// * The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
-//   extra copying of files. Contrast that with source apex modules that has to build each variant
-//   from source.
+//   - The number of prebuilt_apex modules that will be exporting files for the same module will be
+//     low as the prebuilt_apex only exports files for the direct dependencies that require it and
+//     very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a
+//     few com.android.art* apex files that contain the same contents and could export files for the
+//     same modules but only one of them needs to do so. Contrast that with source apex modules which
+//     need apex specific variants for every module that contributes code to the apex, whether direct
+//     or indirect.
+//   - The build cost of a prebuilt_apex variant is generally low as at worst it will involve some
+//     extra copying of files. Contrast that with source apex modules that has to build each variant
+//     from source.
 func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) {
 
 	// Collect direct dependencies into contents.
@@ -703,28 +703,29 @@
 // e.g. make dex implementation jars available for java_import modules listed in exported_java_libs,
 // it does so as follows:
 //
-// 1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
-//    makes them available for use by other modules, at both Soong and ninja levels.
+//  1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
+//     makes them available for use by other modules, at both Soong and ninja levels.
 //
-// 2. It adds a dependency onto those modules and creates an apex specific variant similar to what
-//    an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
-//    dexpreopt, will work the same way from source and prebuilt.
+//  2. It adds a dependency onto those modules and creates an apex specific variant similar to what
+//     an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
+//     dexpreopt, will work the same way from source and prebuilt.
 //
-// 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
-//    itself so that they can retrieve the file paths to those files.
+//  3. The `deapexer` module adds a dependency from the modules that require the exported files onto
+//     itself so that they can retrieve the file paths to those files.
 //
 // It also creates a child module `selector` that is responsible for selecting the appropriate
 // input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
-// 1. To dedup the selection logic so it only runs in one module.
-// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
-//    `apex_set`.
 //
-//                     prebuilt_apex
-//                    /      |      \
-//                 /         |         \
-//              V            V            V
-//       selector  <---  deapexer  <---  exported java lib
+//  1. To dedup the selection logic so it only runs in one module.
 //
+//  2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
+//     `apex_set`.
+//
+//     prebuilt_apex
+//     /      |      \
+//     /         |         \
+//     V            V            V
+//     selector  <---  deapexer  <---  exported java lib
 func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
 	baseModuleName := p.BaseModuleName()
 
diff --git a/apex/testing.go b/apex/testing.go
index 337c862..69bd73e 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -24,7 +24,6 @@
 	android.MockFS{
 		// Needed by apex.
 		"system/core/rootdir/etc/public.libraries.android.txt": nil,
-		"build/soong/scripts/gen_java_usedby_apex.sh":          nil,
 		"build/soong/scripts/gen_ndk_backedby_apex.sh":         nil,
 		// Needed by prebuilt_apex.
 		"build/soong/scripts/unpack-prebuilt-apex.sh": nil,
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 418b143..05f6ed4 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -52,8 +52,9 @@
 
 // AqueryDepset is a depset definition from Bazel's aquery response. This is
 // akin to the `depSetOfFiles` in the response proto, except:
-//   * direct artifacts are enumerated by full path instead of by ID
-//   * it has a hash of the depset contents, instead of an int ID (for determinism)
+//   - direct artifacts are enumerated by full path instead of by ID
+//   - it has a hash of the depset contents, instead of an int ID (for determinism)
+//
 // A depset is a data structure for efficient transitive handling of artifact
 // paths. A single depset consists of one or more artifact paths and one or
 // more "child" depsets.
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 53056c7..5810364 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -507,11 +507,14 @@
   "depSetOfFiles": [{
     "id": 1111,
     "directArtifactIds": [3 , 4]
+  }, {
+    "id": 2222,
+    "directArtifactIds": [3]
   }],
   "actions": [{
     "targetId": 100,
     "actionKey": "x",
-    "inputDepSetIds": [1111],
+    "inputDepSetIds": [1111, 2222],
     "mnemonic": "x",
     "arguments": ["bogus", "command"],
     "outputIds": [2],
@@ -527,7 +530,7 @@
   ]
 }`
 	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements([]byte(inputString))
-	if len(actualDepsets) != 1 {
+	if len(actualDepsets) != 2 {
 		t.Errorf("expected 1 depset but found %#v", actualDepsets)
 		return
 	}
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 0ab49eb..d9b0a12 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -27,7 +27,7 @@
 	archX86_64 = "x86_64"
 
 	// OsType names in arch.go
-	osAndroid     = "android"
+	OsAndroid     = "android"
 	osDarwin      = "darwin"
 	osLinux       = "linux_glibc"
 	osLinuxMusl   = "linux_musl"
@@ -64,6 +64,9 @@
 	ConditionsDefaultSelectKey = "//conditions:default"
 
 	productVariableBazelPackage = "//build/bazel/product_variables"
+
+	AndroidAndInApex  = "android-in_apex"
+	AndroidAndNonApex = "android-non_apex"
 )
 
 var (
@@ -85,7 +88,7 @@
 	// A map of target operating systems to the Bazel label of the
 	// constraint_value for the @platforms//os:os constraint_setting
 	platformOsMap = map[string]string{
-		osAndroid:                  "//build/bazel/platforms/os:android",
+		OsAndroid:                  "//build/bazel/platforms/os:android",
 		osDarwin:                   "//build/bazel/platforms/os:darwin",
 		osLinux:                    "//build/bazel/platforms/os:linux",
 		osLinuxMusl:                "//build/bazel/platforms/os:linux_musl",
@@ -120,7 +123,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, archX86, archX86_64},
 		osLinux:       {archX86, archX86_64},
 		osLinuxMusl:   {archX86, archX86_64},
 		osDarwin:      {archArm64, archX86_64},
@@ -128,6 +131,12 @@
 		// TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
 		osWindows: {archX86, archX86_64},
 	}
+
+	osAndInApexMap = map[string]string{
+		AndroidAndInApex:           "//build/bazel/rules/apex:android-in_apex",
+		AndroidAndNonApex:          "//build/bazel/rules/apex:android-non_apex",
+		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
+	}
 )
 
 // basic configuration types
@@ -139,6 +148,7 @@
 	os
 	osArch
 	productVariables
+	osAndInApex
 )
 
 func osArchString(os string, arch string) string {
@@ -152,6 +162,7 @@
 		os:               "os",
 		osArch:           "arch_os",
 		productVariables: "product_variables",
+		osAndInApex:      "os_in_apex",
 	}[ct]
 }
 
@@ -175,6 +186,10 @@
 		}
 	case productVariables:
 		// do nothing
+	case osAndInApex:
+		if _, ok := osAndInApexMap[config]; !ok {
+			panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
+		}
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
 	}
@@ -198,6 +213,8 @@
 			return ConditionsDefaultSelectKey
 		}
 		return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
+	case osAndInApex:
+		return osAndInApexMap[config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
 	}
@@ -212,6 +229,8 @@
 	OsConfigurationAxis = ConfigurationAxis{configurationType: os}
 	// An axis for arch+os-specific configurations
 	OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
+	// An axis for os+in_apex-specific configurations
+	OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
 )
 
 // ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index d32e619..5cee6ac 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -134,13 +134,13 @@
 sharedLibraries = []
 rootSharedLibraries = []
 
-shared_info_tag = "@_builtins//:common/cc/experimental_cc_shared_library.bzl%CcSharedLibraryInfo"
+shared_info_tag = "//build/bazel/rules/cc:cc_library_shared.bzl%CcSharedLibraryOutputInfo"
+
 if shared_info_tag in providers(target):
   shared_info = providers(target)[shared_info_tag]
-  for lib in shared_info.linker_input.libraries:
-    path = lib.dynamic_library.path
-    rootSharedLibraries += [path]
-    sharedLibraries.append(path)
+  path = shared_info.output_file.path
+  sharedLibraries.append(path)
+  rootSharedLibraries += [path]
 else:
   for linker_input in linker_inputs:
     for library in linker_input.libraries:
diff --git a/bazel/properties.go b/bazel/properties.go
index e29b9e1..13e36b5 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -94,6 +94,10 @@
 	return ll.Includes == nil && ll.Excludes == nil
 }
 
+func (ll *LabelList) IsEmpty() bool {
+	return len(ll.Includes) == 0 && len(ll.Excludes) == 0
+}
+
 func (ll *LabelList) deepCopy() LabelList {
 	return LabelList{
 		Includes: ll.Includes[:],
@@ -115,7 +119,7 @@
 	return dirs
 }
 
-// Add inserts the label Label at the end of the LabelList.
+// Add inserts the label Label at the end of the LabelList.Includes.
 func (ll *LabelList) Add(label *Label) {
 	if label == nil {
 		return
@@ -123,6 +127,14 @@
 	ll.Includes = append(ll.Includes, *label)
 }
 
+// AddExclude inserts the label Label at the end of the LabelList.Excludes.
+func (ll *LabelList) AddExclude(label *Label) {
+	if label == nil {
+		return
+	}
+	ll.Excludes = append(ll.Excludes, *label)
+}
+
 // Append appends the fields of other labelList to the corresponding fields of ll.
 func (ll *LabelList) Append(other LabelList) {
 	if len(ll.Includes) > 0 || len(other.Includes) > 0 {
@@ -133,6 +145,30 @@
 	}
 }
 
+// Partition splits a LabelList into two LabelLists depending on the return value
+// of the predicate.
+// This function preserves the Includes and Excludes, but it does not provide
+// that information to the partition function.
+func (ll *LabelList) Partition(predicate func(label Label) bool) (LabelList, LabelList) {
+	predicated := LabelList{}
+	unpredicated := LabelList{}
+	for _, include := range ll.Includes {
+		if predicate(include) {
+			predicated.Add(&include)
+		} else {
+			unpredicated.Add(&include)
+		}
+	}
+	for _, exclude := range ll.Excludes {
+		if predicate(exclude) {
+			predicated.AddExclude(&exclude)
+		} else {
+			unpredicated.AddExclude(&exclude)
+		}
+	}
+	return predicated, unpredicated
+}
+
 // UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
 // the slice in a sorted order.
 func UniqueSortedBazelLabels(originalLabels []Label) []Label {
@@ -328,7 +364,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		la.Value = &value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, osAndInApex:
 		if la.ConfigurableValues == nil {
 			la.ConfigurableValues = make(configurableLabels)
 		}
@@ -344,7 +380,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return la.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, osAndInApex:
 		return la.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -420,7 +456,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		ba.Value = value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, osAndInApex:
 		if ba.ConfigurableValues == nil {
 			ba.ConfigurableValues = make(configurableBools)
 		}
@@ -536,7 +572,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return ba.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, osAndInApex:
 		if v, ok := ba.ConfigurableValues[axis][config]; ok {
 			return &v
 		} else {
@@ -672,7 +708,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, osAndInApex:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -688,8 +724,8 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables:
-		return lla.ConfigurableValues[axis][config]
+	case arch, os, osArch, productVariables, osAndInApex:
+		return (lla.ConfigurableValues[axis][config])
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
 	}
@@ -818,6 +854,29 @@
 	}
 }
 
+// Partition splits a LabelListAttribute into two LabelListAttributes depending
+// on the return value of the predicate.
+// This function preserves the Includes and Excludes, but it does not provide
+// that information to the partition function.
+func (lla LabelListAttribute) Partition(predicate func(label Label) bool) (LabelListAttribute, LabelListAttribute) {
+	predicated := LabelListAttribute{}
+	unpredicated := LabelListAttribute{}
+
+	valuePartitionTrue, valuePartitionFalse := lla.Value.Partition(predicate)
+	predicated.SetValue(valuePartitionTrue)
+	unpredicated.SetValue(valuePartitionFalse)
+
+	for axis, selectValueLabelLists := range lla.ConfigurableValues {
+		for config, labelList := range selectValueLabelLists {
+			configPredicated, configUnpredicated := labelList.Partition(predicate)
+			predicated.SetSelectValue(axis, config, configPredicated)
+			unpredicated.SetSelectValue(axis, config, configUnpredicated)
+		}
+	}
+
+	return predicated, unpredicated
+}
+
 // OtherModuleContext is a limited context that has methods with information about other modules.
 type OtherModuleContext interface {
 	ModuleFromName(name string) (blueprint.Module, bool)
@@ -956,6 +1015,146 @@
 	return ret
 }
 
+// StringAttribute corresponds to the string Bazel attribute type with
+// support for additional metadata, like configurations.
+type StringAttribute struct {
+	// The base value of the string attribute.
+	Value *string
+
+	// The configured attribute label list Values. Optional
+	// a map of independent configurability axes
+	ConfigurableValues configurableStrings
+}
+
+type configurableStrings map[ConfigurationAxis]stringSelectValues
+
+func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
+	if cs[axis] == nil {
+		cs[axis] = make(stringSelectValues)
+	}
+	var v = ""
+	if str != nil {
+		v = *str
+	}
+	cs[axis][config] = v
+}
+
+type stringSelectValues map[string]string
+
+// HasConfigurableValues returns true if the attribute contains axis-specific string values.
+func (sa StringAttribute) HasConfigurableValues() bool {
+	for _, selectValues := range sa.ConfigurableValues {
+		if len(selectValues) > 0 {
+			return true
+		}
+	}
+	return false
+}
+
+// SetSelectValue set a value for a bazel select for the given axis, config and value.
+func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
+	axis.validateConfig(config)
+	switch axis.configurationType {
+	case noConfig:
+		sa.Value = str
+	case arch, os, osArch, productVariables:
+		if sa.ConfigurableValues == nil {
+			sa.ConfigurableValues = make(configurableStrings)
+		}
+		sa.ConfigurableValues.setValueForAxis(axis, config, str)
+	default:
+		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
+	}
+}
+
+// SelectValue gets a value for a bazel select for the given axis and config.
+func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
+	axis.validateConfig(config)
+	switch axis.configurationType {
+	case noConfig:
+		return sa.Value
+	case arch, os, osArch, productVariables:
+		if v, ok := sa.ConfigurableValues[axis][config]; ok {
+			return &v
+		} else {
+			return nil
+		}
+	default:
+		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
+	}
+}
+
+// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
+func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
+	keys := make([]ConfigurationAxis, 0, len(sa.ConfigurableValues))
+	for k := range sa.ConfigurableValues {
+		keys = append(keys, k)
+	}
+
+	sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
+	return keys
+}
+
+// Collapse reduces the configurable axes of the string attribute to a single axis.
+// This is necessary for final writing to bp2build, as a configurable string
+// attribute can only be comprised by a single select.
+func (sa *StringAttribute) Collapse() error {
+	axisTypes := sa.axisTypes()
+	_, containsOs := axisTypes[os]
+	_, containsArch := axisTypes[arch]
+	_, containsOsArch := axisTypes[osArch]
+	_, containsProductVariables := axisTypes[productVariables]
+	if containsProductVariables {
+		if containsOs || containsArch || containsOsArch {
+			return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
+		}
+	}
+	if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
+		// If a bool attribute has both os and arch configuration axes, the only
+		// way to successfully union their values is to increase the granularity
+		// of the configuration criteria to os_arch.
+		for osType, supportedArchs := range osToArchMap {
+			for _, supportedArch := range supportedArchs {
+				osArch := osArchString(osType, supportedArch)
+				if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
+					// Do nothing, as the arch_os is explicitly defined already.
+				} else {
+					archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
+					osVal := sa.SelectValue(OsConfigurationAxis, osType)
+					if osVal != nil && archVal != nil {
+						// In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
+						// runs after os mutator.
+						sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
+					} else if osVal != nil && archVal == nil {
+						sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
+					} else if osVal == nil && archVal != nil {
+						sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
+					}
+				}
+			}
+		}
+		// All os_arch values are now set. Clear os and arch axes.
+		delete(sa.ConfigurableValues, ArchConfigurationAxis)
+		delete(sa.ConfigurableValues, OsConfigurationAxis)
+		// Verify post-condition; this should never fail, provided no additional
+		// axes are introduced.
+		if len(sa.ConfigurableValues) > 1 {
+			panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
+		}
+	}
+	return nil
+}
+
+func (sa *StringAttribute) axisTypes() map[configurationType]bool {
+	types := map[configurationType]bool{}
+	for k := range sa.ConfigurableValues {
+		if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
+			types[k.configurationType] = true
+		}
+	}
+	return types
+}
+
 // StringListAttribute corresponds to the string_list Bazel attribute type with
 // support for additional metadata, like configurations.
 type StringListAttribute struct {
@@ -1045,7 +1244,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sla.Value = list
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, osAndInApex:
 		if sla.ConfigurableValues == nil {
 			sla.ConfigurableValues = make(configurableStringLists)
 		}
@@ -1061,7 +1260,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sla.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, osAndInApex:
 		return sla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -1081,15 +1280,18 @@
 
 // DeduplicateAxesFromBase ensures no duplication of items between the no-configuration value and
 // configuration-specific values. For example, if we would convert this StringListAttribute as:
-// ["a", "b", "c"] + select({
-//    "//condition:one": ["a", "d"],
-//    "//conditions:default": [],
-// })
+//
+//	["a", "b", "c"] + select({
+//	   "//condition:one": ["a", "d"],
+//	   "//conditions:default": [],
+//	})
+//
 // after this function, we would convert this StringListAttribute as:
-// ["a", "b", "c"] + select({
-//    "//condition:one": ["d"],
-//    "//conditions:default": [],
-// })
+//
+//	["a", "b", "c"] + select({
+//	   "//condition:one": ["d"],
+//	   "//conditions:default": [],
+//	})
 func (sla *StringListAttribute) DeduplicateAxesFromBase() {
 	base := sla.Value
 	for axis, configToList := range sla.ConfigurableValues {
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index 7b76b74..dc4d5b0 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -310,6 +310,134 @@
 	}
 }
 
+func TestLabelListAttributePartition(t *testing.T) {
+	testCases := []struct {
+		name         string
+		input        LabelListAttribute
+		predicated   LabelListAttribute
+		unpredicated LabelListAttribute
+		predicate    func(label Label) bool
+	}{
+		{
+			name: "move all to predicated partition",
+			input: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+			)),
+			predicated: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+			)),
+			unpredicated: LabelListAttribute{},
+			predicate: func(label Label) bool {
+				return true
+			},
+		},
+		{
+			name: "move all to unpredicated partition",
+			input: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+			)),
+			predicated: LabelListAttribute{},
+			unpredicated: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+			)),
+			predicate: func(label Label) bool {
+				return false
+			},
+		},
+		{
+			name: "partition includes and excludes",
+			input: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+			)),
+			predicated: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "keep2"},
+				[]string{"keep1", "keep2"},
+			)),
+			unpredicated: MakeLabelListAttribute(makeLabelList(
+				[]string{"throw1", "throw2"},
+				[]string{"throw1", "throw2"},
+			)),
+			predicate: func(label Label) bool {
+				return strings.HasPrefix(label.Label, "keep")
+			},
+		},
+		{
+			name: "partition excludes only",
+			input: MakeLabelListAttribute(makeLabelList(
+				[]string{},
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+			)),
+			predicated: MakeLabelListAttribute(makeLabelList(
+				[]string{},
+				[]string{"keep1", "keep2"},
+			)),
+			unpredicated: MakeLabelListAttribute(makeLabelList(
+				[]string{},
+				[]string{"throw1", "throw2"},
+			)),
+			predicate: func(label Label) bool {
+				return strings.HasPrefix(label.Label, "keep")
+			},
+		},
+		{
+			name: "partition includes only",
+			input: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "throw1", "keep2", "throw2"},
+				[]string{},
+			)),
+			predicated: MakeLabelListAttribute(makeLabelList(
+				[]string{"keep1", "keep2"},
+				[]string{},
+			)),
+			unpredicated: MakeLabelListAttribute(makeLabelList(
+				[]string{"throw1", "throw2"},
+				[]string{},
+			)),
+			predicate: func(label Label) bool {
+				return strings.HasPrefix(label.Label, "keep")
+			},
+		},
+		{
+			name:         "empty partition",
+			input:        MakeLabelListAttribute(makeLabelList([]string{}, []string{})),
+			predicated:   LabelListAttribute{},
+			unpredicated: LabelListAttribute{},
+			predicate: func(label Label) bool {
+				return true
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			predicated, unpredicated := tc.input.Partition(tc.predicate)
+			if !predicated.Value.Equals(tc.predicated.Value) {
+				t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
+			}
+			for axis, configs := range predicated.ConfigurableValues {
+				tcConfigs, ok := tc.predicated.ConfigurableValues[axis]
+				if !ok || !reflect.DeepEqual(configs, tcConfigs) {
+					t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
+				}
+			}
+			if !unpredicated.Value.Equals(tc.unpredicated.Value) {
+				t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
+			}
+			for axis, configs := range unpredicated.ConfigurableValues {
+				tcConfigs, ok := tc.unpredicated.ConfigurableValues[axis]
+				if !ok || !reflect.DeepEqual(configs, tcConfigs) {
+					t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
+				}
+			}
+		})
+	}
+}
+
 // labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of
 // typ
 func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper {
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 07557d6..cb25627 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -15,6 +15,7 @@
         "conversion.go",
         "metrics.go",
         "symlink_forest.go",
+        "testing.go",
     ],
     deps: [
         "soong-android",
@@ -34,6 +35,7 @@
         "soong-ui-metrics",
     ],
     testSrcs: [
+        "aar_conversion_test.go",
         "android_app_certificate_conversion_test.go",
         "android_app_conversion_test.go",
         "apex_conversion_test.go",
@@ -49,6 +51,7 @@
         "cc_prebuilt_library_conversion_test.go",
         "cc_prebuilt_library_shared_test.go",
         "cc_prebuilt_library_static_test.go",
+        "cc_yasm_conversion_test.go",
         "conversion_test.go",
         "filegroup_conversion_test.go",
         "genrule_conversion_test.go",
@@ -66,7 +69,6 @@
         "python_library_conversion_test.go",
         "sh_conversion_test.go",
         "soong_config_module_type_conversion_test.go",
-        "testing.go",
     ],
     pluginFor: [
         "soong_build",
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
new file mode 100644
index 0000000..8e7c2b5
--- /dev/null
+++ b/bp2build/aar_conversion_test.go
@@ -0,0 +1,138 @@
+// 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/java"
+	"fmt"
+
+	"testing"
+)
+
+func TestConvertAndroidLibrary(t *testing.T) {
+	t.Helper()
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+		Description:                "Android Library - simple example",
+		ModuleTypeUnderTest:        "android_library",
+		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
+		Filesystem: map[string]string{
+			"lib.java":                     "",
+			"arm.java":                     "",
+			"x86.java":                     "",
+			"res/res.png":                  "",
+			"manifest/AndroidManifest.xml": "",
+		},
+		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
+android_library {
+        name: "TestLib",
+        srcs: ["lib.java"],
+        arch: {
+			arm: {
+				srcs: ["arm.java"],
+			},
+			x86: {
+				srcs: ["x86.java"],
+			}
+		},
+        manifest: "manifest/AndroidManifest.xml",
+        static_libs: ["static_lib_dep"],
+        java_version: "7",
+}
+`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget(
+				"android_library",
+				"TestLib",
+				AttrNameToString{
+					"srcs": `["lib.java"] + select({
+        "//build/bazel/platforms/arch:arm": ["arm.java"],
+        "//build/bazel/platforms/arch:x86": ["x86.java"],
+        "//conditions:default": [],
+    })`,
+					"manifest":       `"manifest/AndroidManifest.xml"`,
+					"resource_files": `["res/res.png"]`,
+					"deps":           `[":static_lib_dep"]`,
+					"exports":        `[":static_lib_dep"]`,
+					"javacopts":      `["-source 1.7 -target 1.7"]`,
+				}),
+		}})
+}
+
+func TestConvertAndroidLibraryWithNoSources(t *testing.T) {
+	t.Helper()
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+		Description:                "Android Library - modules with deps must have sources",
+		ModuleTypeUnderTest:        "android_library",
+		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
+		Filesystem: map[string]string{
+			"res/res.png":         "",
+			"AndroidManifest.xml": "",
+		},
+		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "lib_dep") + `
+android_library {
+        name: "TestLib",
+        srcs: [],
+        manifest: "AndroidManifest.xml",
+        libs: ["lib_dep"],
+}
+`,
+		ExpectedErr:          fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
+		ExpectedBazelTargets: []string{},
+	})
+}
+
+func TestConvertAndroidLibraryImport(t *testing.T) {
+	t.Helper()
+	RunBp2BuildTestCase(
+		t,
+		func(ctx android.RegistrationContext) {
+			ctx.RegisterModuleType("android_library", java.AndroidLibraryFactory)
+		},
+		Bp2buildTestCase{
+			Description:                "Android Library Import",
+			ModuleTypeUnderTest:        "android_library_import",
+			ModuleTypeUnderTestFactory: java.AARImportFactory,
+			Filesystem: map[string]string{
+				"import.aar": "",
+			},
+			// Bazel's aar_import can only export *_import targets, so we expect
+			// only "static_import_dep" in exports, but both "static_lib_dep" and
+			// "static_import_dep" in deps
+			Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") +
+				simpleModuleDoNotConvertBp2build("android_library_import", "static_import_dep") + `
+android_library_import {
+        name: "TestImport",
+        aars: ["import.aar"],
+        static_libs: ["static_lib_dep", "static_import_dep"],
+}
+`,
+			ExpectedBazelTargets: []string{
+				makeBazelTarget(
+					"aar_import",
+					"TestImport",
+					AttrNameToString{
+						"aar": `"import.aar"`,
+						"deps": `[
+        ":static_lib_dep",
+        ":static_import_dep",
+    ]`,
+						"exports": `[":static_import_dep"]`,
+					},
+				),
+			},
+		},
+	)
+}
diff --git a/bp2build/android_app_certificate_conversion_test.go b/bp2build/android_app_certificate_conversion_test.go
index 173b4e4..0104513 100644
--- a/bp2build/android_app_certificate_conversion_test.go
+++ b/bp2build/android_app_certificate_conversion_test.go
@@ -21,28 +21,28 @@
 	"testing"
 )
 
-func runAndroidAppCertificateTestCase(t *testing.T, tc bp2buildTestCase) {
+func runAndroidAppCertificateTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerAndroidAppCertificateModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerAndroidAppCertificateModuleTypes, tc)
 }
 
 func registerAndroidAppCertificateModuleTypes(ctx android.RegistrationContext) {
 }
 
 func TestAndroidAppCertificateSimple(t *testing.T) {
-	runAndroidAppCertificateTestCase(t, bp2buildTestCase{
-		description:                "Android app certificate - simple example",
-		moduleTypeUnderTest:        "android_app_certificate",
-		moduleTypeUnderTestFactory: java.AndroidAppCertificateFactory,
-		filesystem:                 map[string]string{},
-		blueprint: `
+	runAndroidAppCertificateTestCase(t, Bp2buildTestCase{
+		Description:                "Android app certificate - simple example",
+		ModuleTypeUnderTest:        "android_app_certificate",
+		ModuleTypeUnderTestFactory: java.AndroidAppCertificateFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
 android_app_certificate {
         name: "com.android.apogee.cert",
         certificate: "chamber_of_secrets_dir",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTargetNoRestrictions("android_app_certificate", "com.android.apogee.cert", attrNameToString{
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("android_app_certificate", "com.android.apogee.cert", AttrNameToString{
 				"certificate": `"chamber_of_secrets_dir"`,
 			}),
 		}})
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index a216c9d..a37af12 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -21,33 +21,33 @@
 	"testing"
 )
 
-func runAndroidAppTestCase(t *testing.T, tc bp2buildTestCase) {
+func runAndroidAppTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerAndroidAppModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerAndroidAppModuleTypes, tc)
 }
 
 func registerAndroidAppModuleTypes(ctx android.RegistrationContext) {
 }
 
 func TestMinimalAndroidApp(t *testing.T) {
-	runAndroidAppTestCase(t, bp2buildTestCase{
-		description:                "Android app - simple example",
-		moduleTypeUnderTest:        "android_app",
-		moduleTypeUnderTestFactory: java.AndroidAppFactory,
-		filesystem: map[string]string{
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app - simple example",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem: map[string]string{
 			"app.java":            "",
 			"res/res.png":         "",
 			"AndroidManifest.xml": "",
 		},
-		blueprint: `
+		Blueprint: `
 android_app {
         name: "TestApp",
         srcs: ["app.java"],
         sdk_version: "current",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("android_binary", "TestApp", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("android_binary", "TestApp", AttrNameToString{
 				"srcs":           `["app.java"]`,
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `["res/res.png"]`,
@@ -56,17 +56,17 @@
 }
 
 func TestAndroidAppAllSupportedFields(t *testing.T) {
-	runAndroidAppTestCase(t, bp2buildTestCase{
-		description:                "Android app - all supported fields",
-		moduleTypeUnderTest:        "android_app",
-		moduleTypeUnderTestFactory: java.AndroidAppFactory,
-		filesystem: map[string]string{
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app - all supported fields",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem: map[string]string{
 			"app.java":                     "",
 			"resa/res.png":                 "",
 			"resb/res.png":                 "",
 			"manifest/AndroidManifest.xml": "",
 		},
-		blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + `
+		Blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + `
 android_app {
         name: "TestApp",
         srcs: ["app.java"],
@@ -78,8 +78,8 @@
         java_version: "7",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("android_binary", "TestApp", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("android_binary", "TestApp", AttrNameToString{
 				"srcs":     `["app.java"]`,
 				"manifest": `"manifest/AndroidManifest.xml"`,
 				"resource_files": `[
@@ -94,17 +94,17 @@
 }
 
 func TestAndroidAppArchVariantSrcs(t *testing.T) {
-	runAndroidAppTestCase(t, bp2buildTestCase{
-		description:                "Android app - arch variant srcs",
-		moduleTypeUnderTest:        "android_app",
-		moduleTypeUnderTestFactory: java.AndroidAppFactory,
-		filesystem: map[string]string{
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android app - arch variant srcs",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem: map[string]string{
 			"arm.java":            "",
 			"x86.java":            "",
 			"res/res.png":         "",
 			"AndroidManifest.xml": "",
 		},
-		blueprint: `
+		Blueprint: `
 android_app {
         name: "TestApp",
         sdk_version: "current",
@@ -118,8 +118,8 @@
 		}
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("android_binary", "TestApp", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("android_binary", "TestApp", AttrNameToString{
 				"srcs": `select({
         "//build/bazel/platforms/arch:arm": ["arm.java"],
         "//build/bazel/platforms/arch:x86": ["x86.java"],
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 7bc379f..415e695 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -25,9 +25,9 @@
 	"testing"
 )
 
-func runApexTestCase(t *testing.T, tc bp2buildTestCase) {
+func runApexTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerApexModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerApexModuleTypes, tc)
 }
 
 func registerApexModuleTypes(ctx android.RegistrationContext) {
@@ -43,9 +43,9 @@
 	ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
 }
 
-func runOverrideApexTestCase(t *testing.T, tc bp2buildTestCase) {
+func runOverrideApexTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerOverrideApexModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerOverrideApexModuleTypes, tc)
 }
 
 func registerOverrideApexModuleTypes(ctx android.RegistrationContext) {
@@ -63,12 +63,12 @@
 }
 
 func TestApexBundleSimple(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - example with all props, file_context is a module in same Android.bp",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem:                 map[string]string{},
-		blueprint: `
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - example with all props, file_context is a module in same Android.bp",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
 apex_key {
 	name: "com.android.apogee.key",
 	public_key: "com.android.apogee.avbpubkey",
@@ -140,8 +140,8 @@
 	logging_parent: "logging.parent",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"android_manifest": `"ApogeeAndroidManifest.xml"`,
 				"binaries": `[
         ":cc_binary_1",
@@ -181,11 +181,11 @@
 }
 
 func TestApexBundleSimple_fileContextsInAnotherAndroidBp(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - file contexts is a module in another Android.bp",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - file contexts is a module in another Android.bp",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"a/b/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -196,14 +196,14 @@
 }
 `,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 	file_contexts: ":com.android.apogee-file_contexts",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"file_contexts": `"//a/b:com.android.apogee-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 			}),
@@ -211,19 +211,19 @@
 }
 
 func TestApexBundleSimple_fileContextsIsFile(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - file contexts is a file",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem:                 map[string]string{},
-		blueprint: `
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - file contexts is a file",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 	file_contexts: "file_contexts_file",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"file_contexts": `"file_contexts_file"`,
 				"manifest":      `"apex_manifest.json"`,
 			}),
@@ -231,11 +231,11 @@
 }
 
 func TestApexBundleSimple_fileContextsIsNotSpecified(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - file contexts is not specified",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - file contexts is not specified",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -246,13 +246,13 @@
 }
 `,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 			}),
@@ -260,11 +260,11 @@
 }
 
 func TestApexBundleCompileMultilibBoth(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - example with compile_multilib=both",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - example with compile_multilib=both",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -273,9 +273,9 @@
 }
 `,
 		},
-		blueprint: createMultilibBlueprint("both"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		Blueprint: createMultilibBlueprint("both"),
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `[
         ":native_shared_lib_1",
         ":native_shared_lib_3",
@@ -304,11 +304,11 @@
 }
 
 func TestApexBundleCompileMultilibFirst(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - example with compile_multilib=first",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - example with compile_multilib=first",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -317,9 +317,9 @@
 }
 `,
 		},
-		blueprint: createMultilibBlueprint("first"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		Blueprint: createMultilibBlueprint("first"),
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `select({
         "//build/bazel/platforms/arch:arm": [
             ":native_shared_lib_1",
@@ -353,11 +353,11 @@
 }
 
 func TestApexBundleCompileMultilib32(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - example with compile_multilib=32",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - example with compile_multilib=32",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -366,9 +366,9 @@
 }
 `,
 		},
-		blueprint: createMultilibBlueprint("32"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		Blueprint: createMultilibBlueprint("32"),
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_32": `[
         ":native_shared_lib_1",
         ":native_shared_lib_3",
@@ -384,11 +384,11 @@
 }
 
 func TestApexBundleCompileMultilib64(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - example with compile_multilib=64",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - example with compile_multilib=64",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -397,9 +397,9 @@
 }
 `,
 		},
-		blueprint: createMultilibBlueprint("64"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		Blueprint: createMultilibBlueprint("64"),
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_64": `select({
         "//build/bazel/platforms/arch:arm64": [
             ":native_shared_lib_1",
@@ -420,11 +420,11 @@
 }
 
 func TestApexBundleDefaultPropertyValues(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - default property values",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - default property values",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -433,13 +433,13 @@
 }
 `,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 	manifest: "apogee_manifest.json",
 }
 `,
-		expectedBazelTargets: []string{makeBazelTarget("apex", "com.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{makeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 			"manifest":      `"apogee_manifest.json"`,
 			"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 		}),
@@ -447,11 +447,11 @@
 }
 
 func TestApexBundleHasBazelModuleProps(t *testing.T) {
-	runApexTestCase(t, bp2buildTestCase{
-		description:                "apex - has bazel module props",
-		moduleTypeUnderTest:        "apex",
-		moduleTypeUnderTestFactory: apex.BundleFactory,
-		filesystem: map[string]string{
+	runApexTestCase(t, Bp2buildTestCase{
+		Description:                "apex - has bazel module props",
+		ModuleTypeUnderTest:        "apex",
+		ModuleTypeUnderTestFactory: apex.BundleFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "apogee-file_contexts",
@@ -460,14 +460,14 @@
 }
 `,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "apogee",
 	manifest: "manifest.json",
 	bazel_module: { bp2build_available: true },
 }
 `,
-		expectedBazelTargets: []string{makeBazelTarget("apex", "apogee", attrNameToString{
+		ExpectedBazelTargets: []string{makeBazelTarget("apex", "apogee", AttrNameToString{
 			"manifest":      `"manifest.json"`,
 			"file_contexts": `"//system/sepolicy/apex:apogee-file_contexts"`,
 		}),
@@ -525,12 +525,12 @@
 }
 
 func TestBp2BuildOverrideApex(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem:                 map[string]string{},
-		blueprint: `
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
 apex_key {
 	name: "com.android.apogee.key",
 	public_key: "com.android.apogee.avbpubkey",
@@ -623,8 +623,8 @@
 	compressible: true,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"android_manifest": `"ApogeeAndroidManifest.xml"`,
 				"binaries": `[
         ":cc_binary_1",
@@ -659,11 +659,11 @@
 }
 
 func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInDifferentAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - manifest of base apex is empty, base apex and override_apex is in different Android.bp",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - manifest of base apex is empty, base apex and override_apex is in different Android.bp",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -677,14 +677,14 @@
 }
 `,
 		},
-		blueprint: `
+		Blueprint: `
 override_apex {
 	name: "com.google.android.apogee",
 	base: ":com.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"//a/b:apex_manifest.json"`,
 			}),
@@ -692,11 +692,11 @@
 }
 
 func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInDifferentAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - manifest of base apex is set, base apex and override_apex is in different Android.bp",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - manifest of base apex is set, base apex and override_apex is in different Android.bp",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -711,14 +711,14 @@
 }
 `,
 		},
-		blueprint: `
+		Blueprint: `
 override_apex {
 	name: "com.google.android.apogee",
   base: ":com.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"//a/b:apogee_manifest.json"`,
 			}),
@@ -726,11 +726,11 @@
 }
 
 func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInSameAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - manifest of base apex is empty, base apex and override_apex is in same Android.bp",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - manifest of base apex is empty, base apex and override_apex is in same Android.bp",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -738,7 +738,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 	bazel_module: { bp2build_available: false },
@@ -749,8 +749,8 @@
   base: ":com.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 			}),
@@ -758,11 +758,11 @@
 }
 
 func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInSameAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - manifest of base apex is set, base apex and override_apex is in same Android.bp",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - manifest of base apex is set, base apex and override_apex is in same Android.bp",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -770,7 +770,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
   manifest: "apogee_manifest.json",
@@ -782,8 +782,8 @@
   base: ":com.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"apogee_manifest.json"`,
 			}),
@@ -791,11 +791,11 @@
 }
 
 func TestApexBundleSimple_packageNameOverride(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - override package name",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - override package name",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -803,7 +803,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 	bazel_module: { bp2build_available: false },
@@ -815,8 +815,8 @@
 	package_name: "com.google.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 				"package_name":  `"com.google.android.apogee"`,
@@ -825,11 +825,11 @@
 }
 
 func TestApexBundleSimple_NoPrebuiltsOverride(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - no override",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - no override",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -837,7 +837,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 prebuilt_etc {
 	name: "prebuilt_file",
 	bazel_module: { bp2build_available: false },
@@ -854,8 +854,8 @@
 	base: ":com.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 				"prebuilts":     `[":prebuilt_file"]`,
@@ -864,11 +864,11 @@
 }
 
 func TestApexBundleSimple_PrebuiltsOverride(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - ooverride",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - ooverride",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -876,7 +876,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 prebuilt_etc {
 	name: "prebuilt_file",
 	bazel_module: { bp2build_available: false },
@@ -899,8 +899,8 @@
     prebuilts: ["prebuilt_file2"]
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 				"prebuilts":     `[":prebuilt_file2"]`,
@@ -909,11 +909,11 @@
 }
 
 func TestApexBundleSimple_PrebuiltsOverrideEmptyList(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - override with empty list",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - override with empty list",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -921,7 +921,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 prebuilt_etc {
 	name: "prebuilt_file",
 	bazel_module: { bp2build_available: false },
@@ -939,8 +939,8 @@
     prebuilts: [],
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 				"prebuilts":     `[]`,
@@ -949,11 +949,11 @@
 }
 
 func TestApexBundleSimple_NoLoggingParentOverride(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - logging_parent - no override",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - logging_parent - no override",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -961,7 +961,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 	bazel_module: { bp2build_available: false },
@@ -973,8 +973,8 @@
 	base: ":com.android.apogee",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":       `"apex_manifest.json"`,
 				"logging_parent": `"foo.bar.baz"`,
@@ -983,11 +983,11 @@
 }
 
 func TestApexBundleSimple_LoggingParentOverride(t *testing.T) {
-	runOverrideApexTestCase(t, bp2buildTestCase{
-		description:                "override_apex - logging_parent - override",
-		moduleTypeUnderTest:        "override_apex",
-		moduleTypeUnderTestFactory: apex.OverrideApexFactory,
-		filesystem: map[string]string{
+	runOverrideApexTestCase(t, Bp2buildTestCase{
+		Description:                "override_apex - logging_parent - override",
+		ModuleTypeUnderTest:        "override_apex",
+		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
+		Filesystem: map[string]string{
 			"system/sepolicy/apex/Android.bp": `
 filegroup {
 	name: "com.android.apogee-file_contexts",
@@ -995,7 +995,7 @@
 	bazel_module: { bp2build_available: false },
 }`,
 		},
-		blueprint: `
+		Blueprint: `
 apex {
 	name: "com.android.apogee",
 	bazel_module: { bp2build_available: false },
@@ -1008,8 +1008,8 @@
 	logging_parent: "foo.bar.baz.override",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("apex", "com.google.android.apogee", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
 				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
 				"manifest":       `"apex_manifest.json"`,
 				"logging_parent": `"foo.bar.baz.override"`,
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index dfa96a2..15bccf7 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -21,28 +21,28 @@
 	"testing"
 )
 
-func runApexKeyTestCase(t *testing.T, tc bp2buildTestCase) {
+func runApexKeyTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerApexKeyModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerApexKeyModuleTypes, tc)
 }
 
 func registerApexKeyModuleTypes(ctx android.RegistrationContext) {
 }
 
 func TestApexKeySimple(t *testing.T) {
-	runApexKeyTestCase(t, bp2buildTestCase{
-		description:                "apex key - simple example",
-		moduleTypeUnderTest:        "apex_key",
-		moduleTypeUnderTestFactory: apex.ApexKeyFactory,
-		filesystem:                 map[string]string{},
-		blueprint: `
+	runApexKeyTestCase(t, Bp2buildTestCase{
+		Description:                "apex key - simple example",
+		ModuleTypeUnderTest:        "apex_key",
+		ModuleTypeUnderTestFactory: apex.ApexKeyFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: `
 apex_key {
         name: "com.android.apogee.key",
         public_key: "com.android.apogee.avbpubkey",
         private_key: "com.android.apogee.pem",
 }
 `,
-		expectedBazelTargets: []string{makeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", attrNameToString{
+		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
 			"private_key": `"com.android.apogee.pem"`,
 			"public_key":  `"com.android.apogee.avbpubkey"`,
 		}),
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 415becb..8de6d18 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -320,7 +320,8 @@
 
 				// Handle modules with unconverted deps. By default, emit a warning.
 				if unconvertedDeps := aModule.GetUnconvertedBp2buildDeps(); len(unconvertedDeps) > 0 {
-					msg := fmt.Sprintf("%q depends on unconverted modules: %s", m.Name(), strings.Join(unconvertedDeps, ", "))
+					msg := fmt.Sprintf("%s %s:%s depends on unconverted modules: %s",
+						moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
 					if ctx.unconvertedDepMode == warnUnconvertedDeps {
 						metrics.moduleWithUnconvertedDepsMsgs = append(metrics.moduleWithUnconvertedDepsMsgs, msg)
 					} else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
@@ -329,7 +330,8 @@
 					}
 				}
 				if unconvertedDeps := aModule.GetMissingBp2buildDeps(); len(unconvertedDeps) > 0 {
-					msg := fmt.Sprintf("%q depends on missing modules: %s", m.Name(), strings.Join(unconvertedDeps, ", "))
+					msg := fmt.Sprintf("%s %s:%s depends on missing modules: %s",
+						moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
 					if ctx.unconvertedDepMode == warnUnconvertedDeps {
 						metrics.moduleWithMissingDepsMsgs = append(metrics.moduleWithMissingDepsMsgs, msg)
 					} else if ctx.unconvertedDepMode == errorModulesUnconvertedDeps {
@@ -371,6 +373,15 @@
 	if generateFilegroups {
 		// Add a filegroup target that exposes all sources in the subtree of this package
 		// NOTE: This also means we generate a BUILD file for every Android.bp file (as long as it has at least one module)
+		//
+		// This works because: https://bazel.build/reference/be/functions#exports_files
+		// "As a legacy behaviour, also files mentioned as input to a rule are exported with the
+		// default visibility until the flag --incompatible_no_implicit_file_export is flipped. However, this behavior
+		// should not be relied upon and actively migrated away from."
+		//
+		// 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 {
 			buildFileToTargets[dir] = append(buildFileToTargets[dir], BazelTarget{
 				name:      "bp2build_all_srcs",
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 19209f6..1ac7518 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -229,30 +229,76 @@
 }
 
 func TestGenerateBazelTargetModules(t *testing.T) {
-	testCases := []bp2buildTestCase{
+	testCases := []Bp2buildTestCase{
 		{
-			description: "string ptr props",
-			blueprint: `custom {
+			Description: "string prop empty",
+			Blueprint: `custom {
+	name: "foo",
+    string_literal_prop: "",
+    bazel_module: { bp2build_available: true },
+}`,
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "foo", AttrNameToString{
+					"string_literal_prop": `""`,
+				}),
+			},
+		},
+		{
+			Description: `string prop "PROP"`,
+			Blueprint: `custom {
+	name: "foo",
+    string_literal_prop: "PROP",
+    bazel_module: { bp2build_available: true },
+}`,
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "foo", AttrNameToString{
+					"string_literal_prop": `"PROP"`,
+				}),
+			},
+		},
+		{
+			Description: `string prop arch variant`,
+			Blueprint: `custom {
+    name: "foo",
+    arch: {
+        arm: { string_literal_prop: "ARM" },
+        arm64: { string_literal_prop: "ARM64" },
+    },
+    bazel_module: { bp2build_available: true },
+}`,
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "foo", AttrNameToString{
+					"string_literal_prop": `select({
+        "//build/bazel/platforms/arch:arm": "ARM",
+        "//build/bazel/platforms/arch:arm64": "ARM64",
+        "//conditions:default": None,
+    })`,
+				}),
+			},
+		},
+		{
+			Description: "string ptr props",
+			Blueprint: `custom {
 	name: "foo",
     string_ptr_prop: "",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "foo", AttrNameToString{
 					"string_ptr_prop": `""`,
 				}),
 			},
 		},
 		{
-			description: "string props",
-			blueprint: `custom {
+			Description: "string list props",
+			Blueprint: `custom {
   name: "foo",
     string_list_prop: ["a", "b"],
     string_ptr_prop: "a",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "foo", AttrNameToString{
 					"string_list_prop": `[
         "a",
         "b",
@@ -262,15 +308,15 @@
 			},
 		},
 		{
-			description: "control characters",
-			blueprint: `custom {
+			Description: "control characters",
+			Blueprint: `custom {
     name: "foo",
     string_list_prop: ["\t", "\n"],
     string_ptr_prop: "a\t\n\r",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "foo", AttrNameToString{
 					"string_list_prop": `[
         "\t",
         "\n",
@@ -280,8 +326,8 @@
 			},
 		},
 		{
-			description: "handles dep",
-			blueprint: `custom {
+			Description: "handles dep",
+			Blueprint: `custom {
   name: "has_dep",
   arch_paths: [":dep"],
   bazel_module: { bp2build_available: true },
@@ -292,31 +338,31 @@
   arch_paths: ["abc"],
   bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "dep", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "dep", AttrNameToString{
 					"arch_paths": `["abc"]`,
 				}),
-				makeBazelTarget("custom", "has_dep", attrNameToString{
+				makeBazelTarget("custom", "has_dep", AttrNameToString{
 					"arch_paths": `[":dep"]`,
 				}),
 			},
 		},
 		{
-			description: "non-existent dep",
-			blueprint: `custom {
+			Description: "non-existent dep",
+			Blueprint: `custom {
   name: "has_dep",
   arch_paths: [":dep"],
   bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "has_dep", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "has_dep", AttrNameToString{
 					"arch_paths": `[":dep__BP2BUILD__MISSING__DEP"]`,
 				}),
 			},
 		},
 		{
-			description: "arch-variant srcs",
-			blueprint: `custom {
+			Description: "arch-variant srcs",
+			Blueprint: `custom {
     name: "arch_paths",
     arch: {
       x86: { arch_paths: ["x86.txt"] },
@@ -344,8 +390,8 @@
     },
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "arch_paths", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "arch_paths", AttrNameToString{
 					"arch_paths": `select({
         "//build/bazel/platforms/arch:arm": [
             "arm.txt",
@@ -406,8 +452,8 @@
 			},
 		},
 		{
-			description: "arch-variant deps",
-			blueprint: `custom {
+			Description: "arch-variant deps",
+			Blueprint: `custom {
   name: "has_dep",
   arch: {
     x86: {
@@ -422,11 +468,11 @@
     arch_paths: ["abc"],
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "dep", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "dep", AttrNameToString{
 					"arch_paths": `["abc"]`,
 				}),
-				makeBazelTarget("custom", "has_dep", attrNameToString{
+				makeBazelTarget("custom", "has_dep", AttrNameToString{
 					"arch_paths": `select({
         "//build/bazel/platforms/arch:x86": [":dep"],
         "//conditions:default": [],
@@ -435,27 +481,27 @@
 			},
 		},
 		{
-			description: "embedded props",
-			blueprint: `custom {
+			Description: "embedded props",
+			Blueprint: `custom {
     name: "embedded_props",
     embedded_prop: "abc",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "embedded_props", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "embedded_props", AttrNameToString{
 					"embedded_attr": `"abc"`,
 				}),
 			},
 		},
 		{
-			description: "ptr to embedded props",
-			blueprint: `custom {
+			Description: "ptr to embedded props",
+			Blueprint: `custom {
     name: "ptr_to_embedded_props",
     other_embedded_prop: "abc",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("custom", "ptr_to_embedded_props", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("custom", "ptr_to_embedded_props", AttrNameToString{
 					"other_embedded_attr": `"abc"`,
 				}),
 			},
@@ -464,8 +510,8 @@
 
 	dir := "."
 	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
-			config := android.TestConfig(buildDir, nil, testCase.blueprint, nil)
+		t.Run(testCase.Description, func(t *testing.T) {
+			config := android.TestConfig(buildDir, nil, testCase.Blueprint, nil)
 			ctx := android.NewTestContext(config)
 
 			registerCustomModuleForBp2buildConversion(ctx)
@@ -483,10 +529,10 @@
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 
-			if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
-				t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.expectedBazelTargets, actualCount, bazelTargets)
+			if actualCount, expectedCount := len(bazelTargets), len(testCase.ExpectedBazelTargets); actualCount != expectedCount {
+				t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.ExpectedBazelTargets, actualCount, bazelTargets)
 			} else {
-				for i, expectedBazelTarget := range testCase.expectedBazelTargets {
+				for i, expectedBazelTarget := range testCase.ExpectedBazelTargets {
 					actualBazelTarget := bazelTargets[i]
 					if actualBazelTarget.content != expectedBazelTarget {
 						t.Errorf(
@@ -502,83 +548,83 @@
 }
 
 func TestBp2buildHostAndDevice(t *testing.T) {
-	testCases := []bp2buildTestCase{
+	testCases := []Bp2buildTestCase{
 		{
-			description:                "host and device, device only",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, device only",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			ExpectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
 			},
 		},
 		{
-			description:                "host and device, both",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, both",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: true,
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{}),
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
 			},
 		},
 		{
-			description:                "host and device, host explicitly disabled",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, host explicitly disabled",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: false,
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			ExpectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
 			},
 		},
 		{
-			description:                "host and device, neither",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, neither",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: false,
 		device_supported: false,
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
 					"target_compatible_with": `["@platforms//:incompatible"]`,
 				}),
 			},
 		},
 		{
-			description:                "host and device, neither, cannot override with product_var",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, neither, cannot override with product_var",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: false,
 		device_supported: false,
 		product_variables: { unbundled_build: { enabled: true } },
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
 					"target_compatible_with": `["@platforms//:incompatible"]`,
 				}),
 			},
 		},
 		{
-			description:                "host and device, both, disabled overrided with product_var",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, both, disabled overrided with product_var",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: true,
 		device_supported: true,
@@ -586,117 +632,117 @@
 		product_variables: { unbundled_build: { enabled: true } },
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
 					"target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`,
 				}),
 			},
 		},
 		{
-			description:                "host and device, neither, cannot override with arch enabled",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, neither, cannot override with arch enabled",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: false,
 		device_supported: false,
 		arch: { x86: { enabled: true } },
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
 					"target_compatible_with": `["@platforms//:incompatible"]`,
 				}),
 			},
 		},
 		{
-			description:                "host and device, host only",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			blueprint: `custom {
+			Description:                "host and device, host only",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: true,
 		device_supported: false,
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.HostSupported),
+			ExpectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
 			},
 		},
 		{
-			description:                "host only",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostSupported,
-			blueprint: `custom {
+			Description:                "host only",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostSupported,
+			Blueprint: `custom {
 		name: "foo",
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.HostSupported),
+			ExpectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
 			},
 		},
 		{
-			description:                "device only",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryDeviceSupported,
-			blueprint: `custom {
+			Description:                "device only",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryDeviceSupported,
+			Blueprint: `custom {
 		name: "foo",
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			ExpectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
 			},
 		},
 		{
-			description:                "host and device default, default",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			blueprint: `custom {
+			Description:                "host and device default, default",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			Blueprint: `custom {
 		name: "foo",
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{}),
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
 			},
 		},
 		{
-			description:                "host and device default, device only",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			blueprint: `custom {
+			Description:                "host and device default, device only",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: false,
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.DeviceSupported),
+			ExpectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
 			},
 		},
 		{
-			description:                "host and device default, host only",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			blueprint: `custom {
+			Description:                "host and device default, host only",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			Blueprint: `custom {
 		name: "foo",
 		device_supported: false,
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", attrNameToString{}, android.HostSupported),
+			ExpectedBazelTargets: []string{
+				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
 			},
 		},
 		{
-			description:                "host and device default, neither",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			blueprint: `custom {
+			Description:                "host and device default, neither",
+			ModuleTypeUnderTest:        "custom",
+			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
+			Blueprint: `custom {
 		name: "foo",
 		host_supported: false,
 		device_supported: false,
 		bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("custom", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
 					"target_compatible_with": `["@platforms//:incompatible"]`,
 				}),
 			},
@@ -704,7 +750,7 @@
 	}
 
 	for _, tc := range testCases {
-		t.Run(tc.description, func(t *testing.T) {
+		t.Run(tc.Description, func(t *testing.T) {
 			runBp2BuildTestCaseSimple(t, tc)
 		})
 	}
@@ -880,43 +926,43 @@
 }
 
 func TestModuleTypeBp2Build(t *testing.T) {
-	testCases := []bp2buildTestCase{
+	testCases := []Bp2buildTestCase{
 		{
-			description:                "filegroup with does not specify srcs",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "filegroup with does not specify srcs",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
     name: "fg_foo",
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
 			},
 		},
 		{
-			description:                "filegroup with no srcs",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "filegroup with no srcs",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
     name: "fg_foo",
     srcs: [],
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
 			},
 		},
 		{
-			description:                "filegroup with srcs",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "filegroup with 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{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a",
         "b",
@@ -925,32 +971,32 @@
 			},
 		},
 		{
-			description:                "filegroup with excludes srcs",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "filegroup with excludes srcs",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
     name: "fg_foo",
     srcs: ["a", "b"],
     exclude_srcs: ["a"],
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `["b"]`,
 				}),
 			},
 		},
 		{
-			description:                "filegroup with glob",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			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{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "other/a.txt",
         "other/b.txt",
@@ -958,7 +1004,7 @@
     ]`,
 				}),
 			},
-			filesystem: map[string]string{
+			Filesystem: map[string]string{
 				"other/a.txt":        "",
 				"other/b.txt":        "",
 				"other/subdir/a.txt": "",
@@ -966,11 +1012,11 @@
 			},
 		},
 		{
-			description:                "filegroup with glob in subdir",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			dir:                        "other",
-			filesystem: map[string]string{
+			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"],
@@ -981,8 +1027,8 @@
 				"other/subdir/a.txt": "",
 				"other/file":         "",
 			},
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a.txt",
         "b.txt",
@@ -992,10 +1038,10 @@
 			},
 		},
 		{
-			description:                "depends_on_other_dir_module",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "depends_on_other_dir_module",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
     name: "fg_foo",
     srcs: [
         ":foo",
@@ -1003,15 +1049,15 @@
     ],
     bazel_module: { bp2build_available: true },
 }`,
-			filesystem: map[string]string{
+			Filesystem: map[string]string{
 				"other/Android.bp": `filegroup {
     name: "foo",
     srcs: ["a", "b"],
     bazel_module: { bp2build_available: true },
 }`,
 			},
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "//other:foo",
         "c",
@@ -1020,11 +1066,11 @@
 			},
 		},
 		{
-			description:                "depends_on_other_unconverted_module_error",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			unconvertedDepsMode:        errorModulesUnconvertedDeps,
-			blueprint: `filegroup {
+			Description:                "depends_on_other_unconverted_module_error",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			UnconvertedDepsMode:        errorModulesUnconvertedDeps,
+			Blueprint: `filegroup {
     name: "foobar",
     srcs: [
         ":foo",
@@ -1032,8 +1078,8 @@
     ],
     bazel_module: { bp2build_available: true },
 }`,
-			expectedErr: fmt.Errorf(`"foobar" depends on unconverted modules: foo`),
-			filesystem: map[string]string{
+			ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on unconverted modules: foo`),
+			Filesystem: map[string]string{
 				"other/Android.bp": `filegroup {
     name: "foo",
     srcs: ["a", "b"],
@@ -1043,8 +1089,8 @@
 	}
 
 	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase)
+		t.Run(testCase.Description, func(t *testing.T) {
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase)
 		})
 	}
 }
@@ -1244,27 +1290,27 @@
 }
 
 func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
-	testCases := []bp2buildTestCase{
+	testCases := []Bp2buildTestCase{
 		{
-			description:                "filegroup bazel_module.label",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "filegroup bazel_module.label",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
     name: "fg_foo",
     bazel_module: { label: "//other:fg_foo" },
 }`,
-			expectedBazelTargets: []string{
+			ExpectedBazelTargets: []string{
 				`// BUILD file`,
 			},
-			filesystem: map[string]string{
+			Filesystem: map[string]string{
 				"other/BUILD.bazel": `// BUILD file`,
 			},
 		},
 		{
-			description:                "multiple bazel_module.label same BUILD",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "multiple bazel_module.label same BUILD",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
         name: "fg_foo",
         bazel_module: { label: "//other:fg_foo" },
     }
@@ -1273,20 +1319,20 @@
         name: "foo",
         bazel_module: { label: "//other:foo" },
     }`,
-			expectedBazelTargets: []string{
+			ExpectedBazelTargets: []string{
 				`// BUILD file`,
 			},
-			filesystem: map[string]string{
+			Filesystem: map[string]string{
 				"other/BUILD.bazel": `// BUILD file`,
 			},
 		},
 		{
-			description:                "filegroup bazel_module.label and bp2build in subdir",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			dir:                        "other",
-			blueprint:                  ``,
-			filesystem: map[string]string{
+			Description:                "filegroup bazel_module.label and bp2build in subdir",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Dir:                        "other",
+			Blueprint:                  ``,
+			Filesystem: map[string]string{
 				"other/Android.bp": `filegroup {
         name: "fg_foo",
         bazel_module: {
@@ -1301,20 +1347,20 @@
       }`,
 				"other/BUILD.bazel": `// definition for fg_bar`,
 			},
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
 				`// definition for fg_bar`,
 			},
 		},
 		{
-			description:                "filegroup bazel_module.label and filegroup bp2build",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
+			Description:                "filegroup bazel_module.label and filegroup bp2build",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
 
-			filesystem: map[string]string{
+			Filesystem: map[string]string{
 				"other/BUILD.bazel": `// BUILD file`,
 			},
-			blueprint: `filegroup {
+			Blueprint: `filegroup {
         name: "fg_foo",
         bazel_module: {
           label: "//other:fg_foo",
@@ -1327,8 +1373,8 @@
           bp2build_available: true,
         },
     }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_bar", map[string]string{}),
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_bar", map[string]string{}),
 				`// BUILD file`,
 			},
 		},
@@ -1336,20 +1382,20 @@
 
 	dir := "."
 	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
+		t.Run(testCase.Description, func(t *testing.T) {
 			fs := make(map[string][]byte)
 			toParse := []string{
 				"Android.bp",
 			}
-			for f, content := range testCase.filesystem {
+			for f, content := range testCase.Filesystem {
 				if strings.HasSuffix(f, "Android.bp") {
 					toParse = append(toParse, f)
 				}
 				fs[f] = []byte(content)
 			}
-			config := android.TestConfig(buildDir, nil, testCase.blueprint, fs)
+			config := android.TestConfig(buildDir, nil, testCase.Blueprint, fs)
 			ctx := android.NewTestContext(config)
-			ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+			ctx.RegisterModuleType(testCase.ModuleTypeUnderTest, testCase.ModuleTypeUnderTestFactory)
 			ctx.RegisterForBazelConversion()
 
 			_, errs := ctx.ParseFileList(dir, toParse)
@@ -1362,15 +1408,15 @@
 			}
 
 			checkDir := dir
-			if testCase.dir != "" {
-				checkDir = testCase.dir
+			if testCase.Dir != "" {
+				checkDir = testCase.Dir
 			}
 			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
 			android.FailIfErrored(t, err)
 			bazelTargets.sort()
 			actualCount := len(bazelTargets)
-			expectedCount := len(testCase.expectedBazelTargets)
+			expectedCount := len(testCase.ExpectedBazelTargets)
 			if actualCount != expectedCount {
 				t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets)
 			}
@@ -1379,7 +1425,7 @@
 			}
 			for i, target := range bazelTargets {
 				actualContent := target.content
-				expectedContent := testCase.expectedBazelTargets[i]
+				expectedContent := testCase.ExpectedBazelTargets[i]
 				if expectedContent != actualContent {
 					t.Errorf(
 						"Expected generated Bazel target to be '%s', got '%s'",
@@ -1393,18 +1439,18 @@
 }
 
 func TestGlobExcludeSrcs(t *testing.T) {
-	testCases := []bp2buildTestCase{
+	testCases := []Bp2buildTestCase{
 		{
-			description:                "filegroup top level exclude_srcs",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: `filegroup {
+			Description:                "filegroup top level exclude_srcs",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: `filegroup {
     name: "fg_foo",
     srcs: ["**/*.txt"],
     exclude_srcs: ["c.txt"],
     bazel_module: { bp2build_available: true },
 }`,
-			filesystem: map[string]string{
+			Filesystem: map[string]string{
 				"a.txt":          "",
 				"b.txt":          "",
 				"c.txt":          "",
@@ -1412,8 +1458,8 @@
 				"dir/e.txt":      "",
 				"dir/f.txt":      "",
 			},
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a.txt",
         "b.txt",
@@ -1424,12 +1470,12 @@
 			},
 		},
 		{
-			description:                "filegroup in subdir exclude_srcs",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint:                  "",
-			dir:                        "dir",
-			filesystem: map[string]string{
+			Description:                "filegroup in subdir exclude_srcs",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint:                  "",
+			Dir:                        "dir",
+			Filesystem: map[string]string{
 				"dir/Android.bp": `filegroup {
     name: "fg_foo",
     srcs: ["**/*.txt"],
@@ -1443,8 +1489,8 @@
 				"dir/subdir/e.txt":      "",
 				"dir/subdir/f.txt":      "",
 			},
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"srcs": `[
         "a.txt",
         "//dir/subdir:e.txt",
@@ -1456,35 +1502,35 @@
 	}
 
 	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
+		t.Run(testCase.Description, func(t *testing.T) {
 			runBp2BuildTestCaseSimple(t, testCase)
 		})
 	}
 }
 
 func TestCommonBp2BuildModuleAttrs(t *testing.T) {
-	testCases := []bp2buildTestCase{
+	testCases := []Bp2buildTestCase{
 		{
-			description:                "Required into data test",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+			Description:                "Required into data test",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
 filegroup {
     name: "fg_foo",
     required: ["reqd"],
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"data": `[":reqd"]`,
 				}),
 			},
 		},
 		{
-			description:                "Required via arch into data test",
-			moduleTypeUnderTest:        "python_library",
-			moduleTypeUnderTestFactory: python.PythonLibraryFactory,
-			blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
+			Description:                "Required via arch into data test",
+			ModuleTypeUnderTest:        "python_library",
+			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
+			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
 				simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
 python_library {
     name: "fg_foo",
@@ -1498,7 +1544,7 @@
     },
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
+			ExpectedBazelTargets: []string{
 				makeBazelTarget("py_library", "fg_foo", map[string]string{
 					"data": `select({
         "//build/bazel/platforms/arch:arm": [":reqdarm"],
@@ -1511,21 +1557,21 @@
 			},
 		},
 		{
-			description:                "Required appended to data test",
-			moduleTypeUnderTest:        "python_library",
-			moduleTypeUnderTestFactory: python.PythonLibraryFactory,
-			filesystem: map[string]string{
+			Description:                "Required appended to data test",
+			ModuleTypeUnderTest:        "python_library",
+			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
+			Filesystem: map[string]string{
 				"data.bin": "",
 				"src.py":   "",
 			},
-			blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
+			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
 python_library {
     name: "fg_foo",
     data: ["data.bin"],
     required: ["reqd"],
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
+			ExpectedBazelTargets: []string{
 				makeBazelTarget("py_library", "fg_foo", map[string]string{
 					"data": `[
         "data.bin",
@@ -1537,17 +1583,17 @@
 			},
 		},
 		{
-			description:                "All props-to-attrs at once together test",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+			Description:                "All props-to-attrs at once together test",
+			ModuleTypeUnderTest:        "filegroup",
+			ModuleTypeUnderTestFactory: android.FileGroupFactory,
+			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
 filegroup {
     name: "fg_foo",
     required: ["reqd"],
     bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
 					"data": `[":reqd"]`,
 				}),
 			},
@@ -1555,7 +1601,7 @@
 	}
 
 	for _, tc := range testCases {
-		t.Run(tc.description, func(t *testing.T) {
+		t.Run(tc.Description, func(t *testing.T) {
 			runBp2BuildTestCaseSimple(t, tc)
 		})
 	}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 6cb9509..28d2c75 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -15,11 +15,12 @@
 package bp2build
 
 import (
-	"android/soong/android"
 	"io/ioutil"
 	"os"
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 func setUp() {
@@ -103,6 +104,7 @@
         "one_to_many_prop": attr.bool(),
         "other_embedded_prop": attr.string(),
         "string_list_prop": attr.string_list(),
+        "string_literal_prop": attr.string(),
         "string_prop": attr.string(),
         "string_ptr_prop": attr.string(),
     },
@@ -132,6 +134,7 @@
         "one_to_many_prop": attr.bool(),
         "other_embedded_prop": attr.string(),
         "string_list_prop": attr.string_list(),
+        "string_literal_prop": attr.string(),
         "string_prop": attr.string(),
         "string_ptr_prop": attr.string(),
     },
@@ -161,6 +164,7 @@
         "one_to_many_prop": attr.bool(),
         "other_embedded_prop": attr.string(),
         "string_list_prop": attr.string_list(),
+        "string_literal_prop": attr.string(),
         "string_prop": attr.string(),
         "string_ptr_prop": attr.string(),
         # test_prop start
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 4794269..9e449eb 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -31,7 +31,7 @@
 type testBazelTarget struct {
 	typ   string
 	name  string
-	attrs attrNameToString
+	attrs AttrNameToString
 }
 
 func generateBazelTargetsForTest(targets []testBazelTarget, hod android.HostOrDeviceSupported) []string {
@@ -73,12 +73,12 @@
 	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
 	t.Run(description, func(t *testing.T) {
 		t.Helper()
-		runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{
-			expectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.DeviceSupported),
-			moduleTypeUnderTest:        moduleTypeUnderTest,
-			moduleTypeUnderTestFactory: cc.BinaryFactory,
-			description:                description,
-			blueprint:                  binaryReplacer.Replace(testCase.blueprint),
+		RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
+			ExpectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.DeviceSupported),
+			ModuleTypeUnderTest:        moduleTypeUnderTest,
+			ModuleTypeUnderTestFactory: cc.BinaryFactory,
+			Description:                description,
+			Blueprint:                  binaryReplacer.Replace(testCase.blueprint),
 		})
 	})
 }
@@ -88,12 +88,12 @@
 	moduleTypeUnderTest := "cc_binary_host"
 	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
 	t.Run(description, func(t *testing.T) {
-		runBp2BuildTestCase(t, registerCcBinaryModuleTypes, bp2buildTestCase{
-			expectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.HostSupported),
-			moduleTypeUnderTest:        moduleTypeUnderTest,
-			moduleTypeUnderTestFactory: cc.BinaryHostFactory,
-			description:                description,
-			blueprint:                  hostBinaryReplacer.Replace(testCase.blueprint),
+		RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
+			ExpectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.HostSupported),
+			ModuleTypeUnderTest:        moduleTypeUnderTest,
+			ModuleTypeUnderTestFactory: cc.BinaryHostFactory,
+			Description:                description,
+			Blueprint:                  hostBinaryReplacer.Replace(testCase.blueprint),
 		})
 	})
 }
@@ -126,7 +126,7 @@
 }
 `,
 		targets: []testBazelTarget{
-			{"cc_binary", "foo", attrNameToString{
+			{"cc_binary", "foo", AttrNameToString{
 				"absolute_includes": `["absolute_dir"]`,
 				"asflags":           `["-Dasflag"]`,
 				"conlyflags":        `["-Dconlyflag"]`,
@@ -166,7 +166,7 @@
 }
 `,
 		targets: []testBazelTarget{
-			{"cc_binary", "foo", attrNameToString{
+			{"cc_binary", "foo", AttrNameToString{
 				"features": `["-static_flag"]`,
 				"linkopts": `["-shared"]`,
 			},
@@ -186,7 +186,7 @@
 }
 `,
 		targets: []testBazelTarget{
-			{"cc_binary", "foo", attrNameToString{
+			{"cc_binary", "foo", AttrNameToString{
 				"linkshared": `False`,
 			},
 			},
@@ -205,7 +205,7 @@
 }
 `,
 		targets: []testBazelTarget{
-			{"cc_binary", "foo", attrNameToString{
+			{"cc_binary", "foo", AttrNameToString{
 				"additional_linker_inputs": `["vs"]`,
 				"linkopts":                 `["-Wl,--version-script,$(location vs)"]`,
 			},
@@ -230,7 +230,7 @@
 }
 ` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
 		targets: []testBazelTarget{
-			{"cc_binary", "foo", attrNameToString{
+			{"cc_binary", "foo", AttrNameToString{
 				"srcs": `[
         "cpponly.cpp",
         ":fg_foo_cpp_srcs",
@@ -285,7 +285,7 @@
 			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
 			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
 		targets: []testBazelTarget{
-			{"cc_binary", "foo", attrNameToString{
+			{"cc_binary", "foo", AttrNameToString{
 				"deps": `[
         ":implementation_static_dep",
         ":static_dep",
@@ -314,21 +314,21 @@
 	baseTestCases := []struct {
 		description   string
 		soongProperty string
-		bazelAttr     attrNameToString
+		bazelAttr     AttrNameToString
 	}{
 		{
 			description:   "nocrt: true",
 			soongProperty: `nocrt: true,`,
-			bazelAttr:     attrNameToString{"link_crt": `False`},
+			bazelAttr:     AttrNameToString{"link_crt": `False`},
 		},
 		{
 			description:   "nocrt: false",
 			soongProperty: `nocrt: false,`,
-			bazelAttr:     attrNameToString{},
+			bazelAttr:     AttrNameToString{},
 		},
 		{
 			description: "nocrt: not set",
-			bazelAttr:   attrNameToString{},
+			bazelAttr:   AttrNameToString{},
 		},
 	}
 
@@ -357,21 +357,21 @@
 	baseTestCases := []struct {
 		description   string
 		soongProperty string
-		bazelAttr     attrNameToString
+		bazelAttr     AttrNameToString
 	}{
 		{
 			description:   "no_libcrt: true",
 			soongProperty: `no_libcrt: true,`,
-			bazelAttr:     attrNameToString{"use_libcrt": `False`},
+			bazelAttr:     AttrNameToString{"use_libcrt": `False`},
 		},
 		{
 			description:   "no_libcrt: false",
 			soongProperty: `no_libcrt: false,`,
-			bazelAttr:     attrNameToString{"use_libcrt": `True`},
+			bazelAttr:     AttrNameToString{"use_libcrt": `True`},
 		},
 		{
 			description: "no_libcrt: not set",
-			bazelAttr:   attrNameToString{},
+			bazelAttr:   AttrNameToString{},
 		},
 	}
 
@@ -400,35 +400,35 @@
 	baseTestCases := []struct {
 		description   string
 		soongProperty string
-		bazelAttr     attrNameToString
+		bazelAttr     AttrNameToString
 	}{
 		{
 			description:   "pack_relocation: true",
 			soongProperty: `pack_relocations: true,`,
-			bazelAttr:     attrNameToString{},
+			bazelAttr:     AttrNameToString{},
 		},
 		{
 			description:   "pack_relocations: false",
 			soongProperty: `pack_relocations: false,`,
-			bazelAttr:     attrNameToString{"features": `["disable_pack_relocations"]`},
+			bazelAttr:     AttrNameToString{"features": `["disable_pack_relocations"]`},
 		},
 		{
 			description: "pack_relocations: not set",
-			bazelAttr:   attrNameToString{},
+			bazelAttr:   AttrNameToString{},
 		},
 		{
 			description:   "pack_relocation: true",
 			soongProperty: `allow_undefined_symbols: true,`,
-			bazelAttr:     attrNameToString{"features": `["-no_undefined_symbols"]`},
+			bazelAttr:     AttrNameToString{"features": `["-no_undefined_symbols"]`},
 		},
 		{
 			description:   "allow_undefined_symbols: false",
 			soongProperty: `allow_undefined_symbols: false,`,
-			bazelAttr:     attrNameToString{},
+			bazelAttr:     AttrNameToString{},
 		},
 		{
 			description: "allow_undefined_symbols: not set",
-			bazelAttr:   attrNameToString{},
+			bazelAttr:   AttrNameToString{},
 		},
 	}
 
@@ -462,11 +462,11 @@
 	include_build_directory: false,
 }`,
 		targets: []testBazelTarget{
-			{"proto_library", "foo_proto", attrNameToString{
+			{"proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}}, {"cc_binary", "foo", attrNameToString{
+			}}, {"cc_binary", "foo", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}},
@@ -485,11 +485,11 @@
 	include_build_directory: false,
 }`,
 		targets: []testBazelTarget{
-			{"proto_library", "foo_proto", attrNameToString{
+			{"proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}}, {"cc_binary", "foo", attrNameToString{
+			}}, {"cc_binary", "foo", AttrNameToString{
 				"deps":               `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"linkshared":         `False`,
@@ -510,7 +510,7 @@
 }
 `,
 		targets: []testBazelTarget{
-			{"genlex", "foo_genlex_l", attrNameToString{
+			{"genlex", "foo_genlex_l", AttrNameToString{
 				"srcs": `[
         "foo1.l",
         "foo2.l",
@@ -520,7 +520,7 @@
         "--bar_opt",
     ]`,
 			}},
-			{"genlex", "foo_genlex_ll", attrNameToString{
+			{"genlex", "foo_genlex_ll", AttrNameToString{
 				"srcs": `[
         "bar1.ll",
         "bar2.ll",
@@ -530,7 +530,7 @@
         "--bar_opt",
     ]`,
 			}},
-			{"cc_binary", "foo", attrNameToString{
+			{"cc_binary", "foo", AttrNameToString{
 				"srcs": `[
         "bar.cc",
         ":foo_genlex_ll",
@@ -543,3 +543,70 @@
 		},
 	})
 }
+
+func TestCcBinaryRuntimeLibs(t *testing.T) {
+	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
+		description: "cc_binary with runtime libs",
+		blueprint: `
+cc_library {
+    name: "bar",
+    srcs: ["b.cc"],
+}
+
+{rule_name} {
+    name: "foo",
+    srcs: ["a.cc"],
+    runtime_libs: ["bar"],
+}
+`,
+		targets: []testBazelTarget{
+			{"cc_library_static", "bar_bp2build_cc_library_static", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["b.cc"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			},
+			},
+			{"cc_library_shared", "bar", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["b.cc"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			},
+			},
+			{"cc_binary", "foo", AttrNameToString{
+				"local_includes": `["."]`,
+				"srcs":           `["a.cc"]`,
+				"runtime_deps":   `[":bar"]`,
+			},
+			},
+		},
+	})
+}
+
+func TestCcBinaryWithInstructionSet(t *testing.T) {
+	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
+		description: "instruction set",
+		blueprint: `
+{rule_name} {
+    name: "foo",
+    arch: {
+      arm: {
+        instruction_set: "arm",
+      }
+    }
+}
+`,
+		targets: []testBazelTarget{
+			{"cc_binary", "foo", AttrNameToString{
+				"features": `select({
+        "//build/bazel/platforms/arch:arm": [
+            "arm_isa_arm",
+            "-arm_isa_thumb",
+        ],
+        "//conditions:default": [],
+    })`,
+				"local_includes": `["."]`,
+			},
+			},
+		},
+	})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 2cc2207..024d4e0 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -43,9 +43,9 @@
 	soongCcProtoPreamble = soongCcLibraryPreamble + soongCcProtoLibraries
 )
 
-func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
 }
 
 func registerCcLibraryModuleTypes(ctx android.RegistrationContext) {
@@ -57,11 +57,11 @@
 }
 
 func TestCcLibrarySimple(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library - simple example",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library - simple example",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"android.cpp": "",
 			"bionic.cpp":  "",
 			"darwin.cpp":  "",
@@ -81,7 +81,7 @@
 			"x86_64.cpp":       "",
 			"foo-dir/a.h":      "",
 		},
-		blueprint: soongCcLibraryPreamble +
+		Blueprint: soongCcLibraryPreamble +
 			simpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + `
 cc_library {
     name: "foo-lib",
@@ -120,7 +120,7 @@
     use_version_lib: true,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"copts":               `["-Wall"]`,
 			"export_includes":     `["foo-dir"]`,
 			"implementation_deps": `[":some-headers"]`,
@@ -151,18 +151,18 @@
 }
 
 func TestCcLibraryTrimmedLdAndroid(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library - trimmed example of //bionic/linker:ld-android",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library - trimmed example of //bionic/linker:ld-android",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"ld-android.cpp":           "",
 			"linked_list.h":            "",
 			"linker.h":                 "",
 			"linker_block_allocator.h": "",
 			"linker_cfi.h":             "",
 		},
-		blueprint: soongCcLibraryPreamble +
+		Blueprint: soongCcLibraryPreamble +
 			simpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + `
 cc_library {
     name: "fake-ld-android",
@@ -193,7 +193,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("fake-ld-android", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("fake-ld-android", AttrNameToString{
 			"srcs": `["ld_android.cpp"]`,
 			"copts": `[
         "-Wall",
@@ -219,12 +219,12 @@
 }
 
 func TestCcLibraryExcludeSrcs(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		dir:                        "external",
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "external",
+		Filesystem: map[string]string{
 			"external/math/cosf.c":      "",
 			"external/math/erf.c":       "",
 			"external/math/erf_data.c":  "",
@@ -257,8 +257,8 @@
 }
 `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", attrNameToString{
+		Blueprint: soongCcLibraryPreamble,
+		ExpectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", AttrNameToString{
 			"copts": `select({
         "//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
         "//conditions:default": [],
@@ -270,16 +270,16 @@
 }
 
 func TestCcLibrarySharedStaticProps(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library shared/static props",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library shared/static props",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"both.cpp":       "",
 			"sharedonly.cpp": "",
 			"staticonly.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "a",
     srcs: ["both.cpp"],
@@ -354,8 +354,8 @@
     bazel_module: { bp2build_available: false },
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
 				"copts": `[
         "bothflag",
         "staticflag",
@@ -377,7 +377,7 @@
         ":whole_and_static_lib_for_both",
         ":whole_static_lib_for_static",
     ]`}),
-			makeBazelTarget("cc_library_shared", "a", attrNameToString{
+			makeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"copts": `[
         "bothflag",
         "sharedflag",
@@ -405,16 +405,16 @@
 }
 
 func TestCcLibraryDeps(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library shared/static props",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library shared/static props",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"both.cpp":       "",
 			"sharedonly.cpp": "",
 			"staticonly.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "a",
     srcs: ["both.cpp"],
@@ -462,8 +462,8 @@
 			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") +
 			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") +
 			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
 				"copts": `[
         "bothflag",
         "staticflag",
@@ -495,7 +495,7 @@
         ":whole_static_dep_for_static",
     ]`,
 			}),
-			makeBazelTarget("cc_library_shared", "a", attrNameToString{
+			makeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"copts": `[
         "bothflag",
         "sharedflag",
@@ -532,11 +532,11 @@
 }
 
 func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		dir:                        "foo/bar",
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "foo/bar",
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": `
 cc_library {
     name: "a",
@@ -558,15 +558,15 @@
 cc_prebuilt_library_static { name: "whole_static_lib_for_both" }
 `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+		Blueprint: soongCcLibraryPreamble,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
 				"whole_archive_deps": `[
         ":whole_static_lib_for_both_alwayslink",
         ":whole_static_lib_for_static_alwayslink",
     ]`,
 			}),
-			makeBazelTarget("cc_library_shared", "a", attrNameToString{
+			makeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"whole_archive_deps": `[
         ":whole_static_lib_for_both_alwayslink",
         ":whole_static_lib_for_shared_alwayslink",
@@ -578,12 +578,12 @@
 }
 
 func TestCcLibrarySharedStaticPropsInArch(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library shared/static props in arch",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		dir:                        "foo/bar",
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library shared/static props in arch",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "foo/bar",
+		Filesystem: map[string]string{
 			"foo/bar/arm.cpp":        "",
 			"foo/bar/x86.cpp":        "",
 			"foo/bar/sharedonly.cpp": "",
@@ -652,9 +652,9 @@
 cc_library_static { name: "android_dep_for_shared" }
 `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+		Blueprint: soongCcLibraryPreamble,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
 				"copts": `[
         "bothflag",
         "staticflag",
@@ -678,7 +678,7 @@
         "//conditions:default": [],
     })`,
 			}),
-			makeBazelTarget("cc_library_shared", "a", attrNameToString{
+			makeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"copts": `[
         "bothflag",
         "sharedflag",
@@ -728,12 +728,12 @@
 }
 
 func TestCcLibrarySharedStaticPropsWithMixedSources(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library shared/static props with c/cpp/s mixed sources",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		dir:                        "foo/bar",
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library shared/static props with c/cpp/s mixed sources",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "foo/bar",
+		Filesystem: map[string]string{
 			"foo/bar/both_source.cpp":   "",
 			"foo/bar/both_source.cc":    "",
 			"foo/bar/both_source.c":     "",
@@ -805,9 +805,9 @@
 }
 `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+		Blueprint: soongCcLibraryPreamble,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
 				"local_includes": `["."]`,
 				"srcs": `[
         "both_source.cpp",
@@ -832,7 +832,7 @@
         ":static_filegroup_c_srcs",
     ]`,
 			}),
-			makeBazelTarget("cc_library_shared", "a", attrNameToString{
+			makeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"local_includes": `["."]`,
 				"srcs": `[
         "both_source.cpp",
@@ -860,12 +860,12 @@
 }
 
 func TestCcLibraryNonConfiguredVersionScript(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library non-configured version script",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		dir:                        "foo/bar",
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library non-configured version script",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "foo/bar",
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": `
 cc_library {
     name: "a",
@@ -876,8 +876,8 @@
 }
 `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+		Blueprint: soongCcLibraryPreamble,
+		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
 			"additional_linker_inputs": `["v.map"]`,
 			"linkopts":                 `["-Wl,--version-script,$(location v.map)"]`,
 			"srcs":                     `["a.cpp"]`,
@@ -887,12 +887,12 @@
 }
 
 func TestCcLibraryConfiguredVersionScript(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library configured version script",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		dir:                        "foo/bar",
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library configured version script",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "foo/bar",
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": `
 cc_library {
    name: "a",
@@ -911,8 +911,8 @@
 }
     `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+		Blueprint: soongCcLibraryPreamble,
+		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
 			"additional_linker_inputs": `select({
         "//build/bazel/platforms/arch:arm": ["arm.map"],
         "//build/bazel/platforms/arch:arm64": ["arm64.map"],
@@ -930,11 +930,11 @@
 }
 
 func TestCcLibrarySharedLibs(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library shared_libs",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library shared_libs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "mylib",
     bazel_module: { bp2build_available: false },
@@ -946,7 +946,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
 			"implementation_dynamic_deps": `[":mylib"]`,
 		}),
 	},
@@ -955,7 +955,7 @@
 
 func TestCcLibraryFeatures(t *testing.T) {
 	expected_targets := []string{}
-	expected_targets = append(expected_targets, makeCcLibraryTargets("a", attrNameToString{
+	expected_targets = append(expected_targets, makeCcLibraryTargets("a", AttrNameToString{
 		"features": `[
         "disable_pack_relocations",
         "-no_undefined_symbols",
@@ -963,7 +963,7 @@
     ]`,
 		"srcs": `["a.cpp"]`,
 	})...)
-	expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{
+	expected_targets = append(expected_targets, makeCcLibraryTargets("b", AttrNameToString{
 		"features": `["-coverage"] + select({
         "//build/bazel/platforms/arch:x86_64": [
             "disable_pack_relocations",
@@ -973,7 +973,7 @@
     })`,
 		"srcs": `["b.cpp"]`,
 	})...)
-	expected_targets = append(expected_targets, makeCcLibraryTargets("c", attrNameToString{
+	expected_targets = append(expected_targets, makeCcLibraryTargets("c", AttrNameToString{
 		"features": `select({
         "//build/bazel/platforms/os:darwin": [
             "disable_pack_relocations",
@@ -984,11 +984,11 @@
 		"srcs": `["c.cpp"]`,
 	})...)
 
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library pack_relocations test",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library pack_relocations test",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "a",
     srcs: ["a.cpp"],
@@ -1022,23 +1022,23 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: expected_targets,
+		ExpectedBazelTargets: expected_targets,
 	})
 }
 
 func TestCcLibrarySpacesInCopts(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library spaces in copts",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library spaces in copts",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "a",
     cflags: ["-include header.h",],
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
 			"copts": `[
         "-include",
         "header.h",
@@ -1049,11 +1049,11 @@
 }
 
 func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library cppflags usage",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library cppflags usage",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `cc_library {
     name: "a",
     srcs: ["a.cpp"],
     cflags: ["-Wall"],
@@ -1074,7 +1074,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
 			"copts": `["-Wall"]`,
 			"cppflags": `[
         "-fsigned-char",
@@ -1093,11 +1093,11 @@
 }
 
 func TestCcLibraryExcludeLibs(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library {
     name: "foo_static",
     srcs: ["common.c"],
@@ -1171,7 +1171,7 @@
     bazel_module: { bp2build_available: false },
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo_static", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{
 			"implementation_deps": `select({
         "//build/bazel/platforms/arch:arm": [],
         "//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
@@ -1200,14 +1200,14 @@
 }
 
 func TestCCLibraryNoCrtTrue(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library - nocrt: true emits attribute",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library - nocrt: true emits attribute",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1215,7 +1215,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"link_crt": `False`,
 			"srcs":     `["impl.cpp"]`,
 		}),
@@ -1224,14 +1224,14 @@
 }
 
 func TestCCLibraryNoCrtFalse(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library - nocrt: false - does not emit attribute",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library - nocrt: false - does not emit attribute",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1239,21 +1239,21 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs": `["impl.cpp"]`,
 		}),
 	})
 }
 
 func TestCCLibraryNoCrtArchVariant(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library - nocrt in select",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library - nocrt in select",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1268,18 +1268,18 @@
     include_build_directory: false,
 }
 `,
-		expectedErr: fmt.Errorf("module \"foo-lib\": nocrt is not supported for arch variants"),
+		ExpectedErr: fmt.Errorf("module \"foo-lib\": nocrt is not supported for arch variants"),
 	})
 }
 
 func TestCCLibraryNoLibCrtTrue(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1287,26 +1287,26 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs":       `["impl.cpp"]`,
 			"use_libcrt": `False`,
 		}),
 	})
 }
 
-func makeCcLibraryTargets(name string, attrs attrNameToString) []string {
+func makeCcLibraryTargets(name string, attrs AttrNameToString) []string {
 	STATIC_ONLY_ATTRS := map[string]bool{}
 	SHARED_ONLY_ATTRS := map[string]bool{
 		"link_crt":                 true,
 		"additional_linker_inputs": true,
 		"linkopts":                 true,
 		"strip":                    true,
-		"stubs_symbol_file":        true,
-		"stubs_versions":           true,
 		"inject_bssl_hash":         true,
+		"has_stubs":                true,
 	}
-	sharedAttrs := attrNameToString{}
-	staticAttrs := attrNameToString{}
+
+	sharedAttrs := AttrNameToString{}
+	staticAttrs := AttrNameToString{}
 	for key, val := range attrs {
 		if _, staticOnly := STATIC_ONLY_ATTRS[key]; !staticOnly {
 			sharedAttrs[key] = val
@@ -1321,14 +1321,34 @@
 	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",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1336,7 +1356,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs":       `["impl.cpp"]`,
 			"use_libcrt": `True`,
 		}),
@@ -1344,13 +1364,13 @@
 }
 
 func TestCCLibraryNoLibCrtArchVariant(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1365,7 +1385,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs": `["impl.cpp"]`,
 			"use_libcrt": `select({
         "//build/bazel/platforms/arch:arm": False,
@@ -1377,13 +1397,13 @@
 }
 
 func TestCCLibraryNoLibCrtArchAndTargetVariant(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1403,7 +1423,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs": `["impl.cpp"]`,
 			"use_libcrt": `select({
         "//build/bazel/platforms/os_arch:android_arm": False,
@@ -1420,13 +1440,13 @@
 }
 
 func TestCCLibraryNoLibCrtArchAndTargetVariantConflict(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -1447,7 +1467,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs": `["impl.cpp"]`,
 			"use_libcrt": `select({
         "//build/bazel/platforms/os_arch:android_arm": False,
@@ -1466,38 +1486,38 @@
 
 func TestCcLibraryStrip(t *testing.T) {
 	expectedTargets := []string{}
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", attrNameToString{
+	expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", AttrNameToString{
 		"strip": `{
         "all": True,
     }`,
 	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols", attrNameToString{
+	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols", AttrNameToString{
 		"strip": `{
         "keep_symbols": True,
     }`,
 	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_and_debug_frame", attrNameToString{
+	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_and_debug_frame", AttrNameToString{
 		"strip": `{
         "keep_symbols_and_debug_frame": True,
     }`,
 	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_list", attrNameToString{
+	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_list", AttrNameToString{
 		"strip": `{
         "keep_symbols_list": ["symbol"],
     }`,
 	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("none", attrNameToString{
+	expectedTargets = append(expectedTargets, makeCcLibraryTargets("none", AttrNameToString{
 		"strip": `{
         "none": True,
     }`,
 	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("nothing", attrNameToString{})...)
+	expectedTargets = append(expectedTargets, makeCcLibraryTargets("nothing", AttrNameToString{})...)
 
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library strip args",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library strip args",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "nothing",
     include_build_directory: false,
@@ -1538,16 +1558,16 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: expectedTargets,
+		ExpectedBazelTargets: expectedTargets,
 	})
 }
 
 func TestCcLibraryStripWithArch(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library strip args",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library strip args",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "multi-arch",
     target: {
@@ -1572,7 +1592,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("multi-arch", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("multi-arch", AttrNameToString{
 			"strip": `{
         "keep_symbols": select({
             "//build/bazel/platforms/arch:arm64": True,
@@ -1596,18 +1616,18 @@
 }
 
 func TestCcLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library system_shared_libs empty at root",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library system_shared_libs empty at root",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "root_empty",
     system_shared_libs: [],
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("root_empty", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("root_empty", AttrNameToString{
 			"system_dynamic_deps": `[]`,
 		}),
 	},
@@ -1615,11 +1635,11 @@
 }
 
 func TestCcLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library system_shared_libs empty for static variant",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library system_shared_libs empty for static variant",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "static_empty",
     static: {
@@ -1628,21 +1648,21 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "static_empty_bp2build_cc_library_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "static_empty_bp2build_cc_library_static", AttrNameToString{
 				"system_dynamic_deps": "[]",
 			}),
-			makeBazelTarget("cc_library_shared", "static_empty", attrNameToString{}),
+			makeBazelTarget("cc_library_shared", "static_empty", AttrNameToString{}),
 		},
 	})
 }
 
 func TestCcLibrary_SystemSharedLibsSharedEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library system_shared_libs empty for shared variant",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library system_shared_libs empty for shared variant",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "shared_empty",
     shared: {
@@ -1651,9 +1671,9 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}),
-			makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", AttrNameToString{}),
+			makeBazelTarget("cc_library_shared", "shared_empty", AttrNameToString{
 				"system_dynamic_deps": "[]",
 			}),
 		},
@@ -1661,11 +1681,11 @@
 }
 
 func TestCcLibrary_SystemSharedLibsSharedBionicEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library system_shared_libs empty for shared, bionic variant",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library system_shared_libs empty for shared, bionic variant",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "shared_empty",
     target: {
@@ -1678,9 +1698,9 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", attrNameToString{}),
-			makeBazelTarget("cc_library_shared", "shared_empty", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", AttrNameToString{}),
+			makeBazelTarget("cc_library_shared", "shared_empty", AttrNameToString{
 				"system_dynamic_deps": "[]",
 			}),
 		},
@@ -1692,11 +1712,11 @@
 	// The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
 	// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
 	// b/195791252 tracks the fix.
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library system_shared_libs empty for linux_bionic variant",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library system_shared_libs empty for linux_bionic variant",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "target_linux_bionic_empty",
     target: {
@@ -1707,7 +1727,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", AttrNameToString{
 			"system_dynamic_deps": `[]`,
 		}),
 	},
@@ -1715,11 +1735,11 @@
 }
 
 func TestCcLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library system_shared_libs empty for bionic variant",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library system_shared_libs empty for bionic variant",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "target_bionic_empty",
     target: {
@@ -1730,7 +1750,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", AttrNameToString{
 			"system_dynamic_deps": `[]`,
 		}),
 	},
@@ -1738,11 +1758,11 @@
 }
 
 func TestCcLibrary_SystemSharedLibsSharedAndRoot(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library system_shared_libs set for shared and root",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library system_shared_libs set for shared and root",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "libc",
     bazel_module: { bp2build_available: false },
@@ -1761,11 +1781,11 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"system_dynamic_deps": `[":libc"]`,
 			}),
-			makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"system_dynamic_deps": `[
         ":libc",
         ":libm",
@@ -1776,12 +1796,12 @@
 }
 
 func TestCcLibraryOsSelects(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library - selects for all os targets",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library - selects for all os targets",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "foo-lib",
     srcs: ["base.cpp"],
@@ -1811,7 +1831,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs": `["base.cpp"] + select({
         "//build/bazel/platforms/os:android": [
             "linux.cpp",
@@ -1840,12 +1860,12 @@
 }
 
 func TestLibcryptoHashInjection(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library - libcrypto hash injection",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library - libcrypto hash injection",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryPreamble + `
 cc_library {
     name: "libcrypto",
     target: {
@@ -1856,7 +1876,7 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: makeCcLibraryTargets("libcrypto", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("libcrypto", AttrNameToString{
 			"inject_bssl_hash": `select({
         "//build/bazel/platforms/os:android": True,
         "//conditions:default": None,
@@ -1940,7 +1960,7 @@
 			if tc.gnu_extensions != "" {
 				gnuExtensionsProp = fmt.Sprintf("    gnu_extensions: %s,", tc.gnu_extensions)
 			}
-			attrs := attrNameToString{}
+			attrs := AttrNameToString{}
 			if tc.bazel_cpp_std != "" {
 				attrs["cpp_std"] = fmt.Sprintf(`"%s"`, tc.bazel_cpp_std)
 			}
@@ -1948,12 +1968,12 @@
 				attrs["c_std"] = fmt.Sprintf(`"%s"`, tc.bazel_c_std)
 			}
 
-			runCcLibraryTestCase(t, bp2buildTestCase{
-				description: fmt.Sprintf(
+			runCcLibraryTestCase(t, Bp2buildTestCase{
+				Description: fmt.Sprintf(
 					"cc_library with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
-				moduleTypeUnderTest:        "cc_library",
-				moduleTypeUnderTestFactory: cc.LibraryFactory,
-				blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
+				ModuleTypeUnderTest:        "cc_library",
+				ModuleTypeUnderTestFactory: cc.LibraryFactory,
+				Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
 cc_library {
 	name: "%s_full",
 %s // cpp_std: *string
@@ -1962,15 +1982,15 @@
 	include_build_directory: false,
 }
 `, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
-				expectedBazelTargets: makeCcLibraryTargets(name_prefix+"_full", attrs),
+				ExpectedBazelTargets: makeCcLibraryTargets(name_prefix+"_full", attrs),
 			})
 
-			runCcLibraryStaticTestCase(t, bp2buildTestCase{
-				description: fmt.Sprintf(
+			runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+				Description: fmt.Sprintf(
 					"cc_library_static with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
-				moduleTypeUnderTest:        "cc_library_static",
-				moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-				blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
+				ModuleTypeUnderTest:        "cc_library_static",
+				ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+				Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
 cc_library_static {
 	name: "%s_static",
 %s // cpp_std: *string
@@ -1979,17 +1999,17 @@
 	include_build_directory: false,
 }
 `, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
-				expectedBazelTargets: []string{
+				ExpectedBazelTargets: []string{
 					makeBazelTarget("cc_library_static", name_prefix+"_static", attrs),
 				},
 			})
 
-			runCcLibrarySharedTestCase(t, bp2buildTestCase{
-				description: fmt.Sprintf(
+			runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+				Description: fmt.Sprintf(
 					"cc_library_shared with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
-				moduleTypeUnderTest:        "cc_library_shared",
-				moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
-				blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
+				ModuleTypeUnderTest:        "cc_library_shared",
+				ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+				Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
 cc_library_shared {
 	name: "%s_shared",
 %s // cpp_std: *string
@@ -1998,7 +2018,7 @@
 	include_build_directory: false,
 }
 `, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
-				expectedBazelTargets: []string{
+				ExpectedBazelTargets: []string{
 					makeBazelTarget("cc_library_shared", name_prefix+"_shared", attrs),
 				},
 			})
@@ -2007,23 +2027,23 @@
 }
 
 func TestCcLibraryProtoSimple(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.proto"],
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
 			}),
 		},
@@ -2031,25 +2051,25 @@
 }
 
 func TestCcLibraryProtoNoCanonicalPathFromRoot(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.proto"],
 	proto: { canonical_path_from_root: false},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs":                `["foo.proto"]`,
 				"strip_import_prefix": `""`,
-			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
 			}),
 		},
@@ -2057,24 +2077,24 @@
 }
 
 func TestCcLibraryProtoExplicitCanonicalPathFromRoot(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.proto"],
 	proto: { canonical_path_from_root: true},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
 			}),
 		},
@@ -2082,10 +2102,10 @@
 }
 
 func TestCcLibraryProtoFull(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.proto"],
 	proto: {
@@ -2093,15 +2113,15 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}), makeBazelTarget("cc_proto_library", "foo_cc_proto", attrNameToString{
+			}), makeBazelTarget("cc_proto_library", "foo_cc_proto", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"implementation_whole_archive_deps": `[":foo_cc_proto"]`,
 				"deps":                              `[":libprotobuf-cpp-full"]`,
-			}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"dynamic_deps": `[":libprotobuf-cpp-full"]`,
 			}),
 		},
@@ -2109,10 +2129,10 @@
 }
 
 func TestCcLibraryProtoLite(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.proto"],
 	proto: {
@@ -2120,15 +2140,15 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
 				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"dynamic_deps": `[":libprotobuf-cpp-lite"]`,
 			}),
 		},
@@ -2136,10 +2156,10 @@
 }
 
 func TestCcLibraryProtoExportHeaders(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.proto"],
 	proto: {
@@ -2147,15 +2167,15 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"deps":               `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
@@ -2164,10 +2184,10 @@
 }
 
 func TestCcLibraryProtoFilegroups(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble +
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble +
 			simpleModuleDoNotConvertBp2build("filegroup", "a_fg_proto") +
 			simpleModuleDoNotConvertBp2build("filegroup", "b_protos") +
 			simpleModuleDoNotConvertBp2build("filegroup", "c-proto-srcs") +
@@ -2207,66 +2227,66 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "a_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "a_proto", AttrNameToString{
 				"srcs": `[":a_fg_proto"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
 				"deps": `[":a_proto"]`,
-			}), makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
 				"deps":               `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":a_cc_proto_lite"]`,
 				"srcs":               `[":a_fg_proto_cpp_srcs"]`,
 				"srcs_as":            `[":a_fg_proto_as_srcs"]`,
 				"srcs_c":             `[":a_fg_proto_c_srcs"]`,
-			}), makeBazelTarget("cc_library_shared", "a", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":a_cc_proto_lite"]`,
 				"srcs":               `[":a_fg_proto_cpp_srcs"]`,
 				"srcs_as":            `[":a_fg_proto_as_srcs"]`,
 				"srcs_c":             `[":a_fg_proto_c_srcs"]`,
-			}), makeBazelTarget("proto_library", "b_proto", attrNameToString{
+			}), makeBazelTarget("proto_library", "b_proto", AttrNameToString{
 				"srcs": `[":b_protos"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "b_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "b_cc_proto_lite", AttrNameToString{
 				"deps": `[":b_proto"]`,
-			}), makeBazelTarget("cc_library_static", "b_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "b_bp2build_cc_library_static", AttrNameToString{
 				"deps":               `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":b_cc_proto_lite"]`,
 				"srcs":               `[":b_protos_cpp_srcs"]`,
 				"srcs_as":            `[":b_protos_as_srcs"]`,
 				"srcs_c":             `[":b_protos_c_srcs"]`,
-			}), makeBazelTarget("cc_library_shared", "b", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "b", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":b_cc_proto_lite"]`,
 				"srcs":               `[":b_protos_cpp_srcs"]`,
 				"srcs_as":            `[":b_protos_as_srcs"]`,
 				"srcs_c":             `[":b_protos_c_srcs"]`,
-			}), makeBazelTarget("proto_library", "c_proto", attrNameToString{
+			}), makeBazelTarget("proto_library", "c_proto", AttrNameToString{
 				"srcs": `[":c-proto-srcs"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "c_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "c_cc_proto_lite", AttrNameToString{
 				"deps": `[":c_proto"]`,
-			}), makeBazelTarget("cc_library_static", "c_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "c_bp2build_cc_library_static", AttrNameToString{
 				"deps":               `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":c_cc_proto_lite"]`,
 				"srcs":               `[":c-proto-srcs_cpp_srcs"]`,
 				"srcs_as":            `[":c-proto-srcs_as_srcs"]`,
 				"srcs_c":             `[":c-proto-srcs_c_srcs"]`,
-			}), makeBazelTarget("cc_library_shared", "c", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "c", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":c_cc_proto_lite"]`,
 				"srcs":               `[":c-proto-srcs_cpp_srcs"]`,
 				"srcs_as":            `[":c-proto-srcs_as_srcs"]`,
 				"srcs_c":             `[":c-proto-srcs_c_srcs"]`,
-			}), makeBazelTarget("proto_library", "d_proto", attrNameToString{
+			}), makeBazelTarget("proto_library", "d_proto", AttrNameToString{
 				"srcs": `[":proto-srcs-d"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "d_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "d_cc_proto_lite", AttrNameToString{
 				"deps": `[":d_proto"]`,
-			}), makeBazelTarget("cc_library_static", "d_bp2build_cc_library_static", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "d_bp2build_cc_library_static", AttrNameToString{
 				"deps":               `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":d_cc_proto_lite"]`,
 				"srcs":               `[":proto-srcs-d_cpp_srcs"]`,
 				"srcs_as":            `[":proto-srcs-d_as_srcs"]`,
 				"srcs_c":             `[":proto-srcs-d_c_srcs"]`,
-			}), makeBazelTarget("cc_library_shared", "d", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "d", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":d_cc_proto_lite"]`,
 				"srcs":               `[":proto-srcs-d_cpp_srcs"]`,
@@ -2278,10 +2298,10 @@
 }
 
 func TestCcLibraryDisabledArchAndTarget(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.cpp"],
 	host_supported: true,
@@ -2298,7 +2318,7 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
 			"srcs": `["foo.cpp"]`,
 			"target_compatible_with": `select({
         "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
@@ -2313,10 +2333,10 @@
 }
 
 func TestCcLibraryDisabledArchAndTargetWithDefault(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.cpp"],
   enabled: false,
@@ -2334,7 +2354,7 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
 			"srcs": `["foo.cpp"]`,
 			"target_compatible_with": `select({
         "//build/bazel/platforms/os_arch:darwin_arm64": [],
@@ -2346,10 +2366,10 @@
 }
 
 func TestCcLibrarySharedDisabled(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	srcs: ["foo.cpp"],
 	enabled: false,
@@ -2365,10 +2385,10 @@
   },
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+		ExpectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 			"srcs":                   `["foo.cpp"]`,
 			"target_compatible_with": `["@platforms//:incompatible"]`,
-		}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+		}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 			"srcs": `["foo.cpp"]`,
 			"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
@@ -2380,10 +2400,10 @@
 }
 
 func TestCcLibraryStaticDisabledForSomeArch(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	host_supported: true,
 	srcs: ["foo.cpp"],
@@ -2405,13 +2425,13 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{
+		ExpectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 			"srcs": `["foo.cpp"]`,
 			"target_compatible_with": `select({
         "//build/bazel/platforms/os:windows": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
-		}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+		}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 			"srcs": `["foo.cpp"]`,
 			"target_compatible_with": `select({
         "//build/bazel/platforms/os_arch:darwin_arm64": [],
@@ -2424,12 +2444,25 @@
 }
 
 func TestCcLibraryStubs(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		description:                "cc_library stubs",
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		dir:                        "foo/bar",
-		filesystem: map[string]string{
+	expectedBazelTargets := makeCcLibraryTargets("a", AttrNameToString{
+		"has_stubs": `True`,
+	})
+	expectedBazelTargets = append(expectedBazelTargets, makeCcStubSuiteTargets("a", AttrNameToString{
+		"soname":            `"a.so"`,
+		"source_library":    `":a"`,
+		"stubs_symbol_file": `"a.map.txt"`,
+		"stubs_versions": `[
+        "28",
+        "29",
+        "current",
+    ]`,
+	}))
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library stubs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Dir:                        "foo/bar",
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": `
 cc_library {
     name: "a",
@@ -2439,39 +2472,32 @@
 }
 `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: makeCcLibraryTargets("a", attrNameToString{
-			"stubs_symbol_file": `"a.map.txt"`,
-			"stubs_versions": `[
-        "28",
-        "29",
-        "current",
-    ]`,
-		}),
+		Blueprint:            soongCcLibraryPreamble,
+		ExpectedBazelTargets: expectedBazelTargets,
 	},
 	)
 }
 
 func TestCcLibraryEscapeLdflags(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		blueprint: soongCcProtoPreamble + `cc_library {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: soongCcProtoPreamble + `cc_library {
 	name: "foo",
 	ldflags: ["-Wl,--rpath,${ORIGIN}"],
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{
+		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
 			"linkopts": `["-Wl,--rpath,$${ORIGIN}"]`,
 		}),
 	})
 }
 
 func TestCcLibraryConvertLex(t *testing.T) {
-	runCcLibraryTestCase(t, bp2buildTestCase{
-		moduleTypeUnderTest:        "cc_library",
-		moduleTypeUnderTestFactory: cc.LibraryFactory,
-		filesystem: map[string]string{
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
 			"foo.c":   "",
 			"bar.cc":  "",
 			"foo1.l":  "",
@@ -2479,22 +2505,22 @@
 			"foo2.l":  "",
 			"bar2.ll": "",
 		},
-		blueprint: `cc_library {
+		Blueprint: `cc_library {
 	name: "foo_lib",
 	srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
 	lex: { flags: ["--foo_flags"] },
 	include_build_directory: false,
 	bazel_module: { bp2build_available: true },
 }`,
-		expectedBazelTargets: append([]string{
-			makeBazelTarget("genlex", "foo_lib_genlex_l", attrNameToString{
+		ExpectedBazelTargets: append([]string{
+			makeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
 				"srcs": `[
         "foo1.l",
         "foo2.l",
     ]`,
 				"lexopts": `["--foo_flags"]`,
 			}),
-			makeBazelTarget("genlex", "foo_lib_genlex_ll", attrNameToString{
+			makeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
 				"srcs": `[
         "bar1.ll",
         "bar2.ll",
@@ -2502,7 +2528,7 @@
 				"lexopts": `["--foo_flags"]`,
 			}),
 		},
-			makeCcLibraryTargets("foo_lib", attrNameToString{
+			makeCcLibraryTargets("foo_lib", AttrNameToString{
 				"srcs": `[
         "bar.cc",
         ":foo_lib_genlex_ll",
@@ -2514,3 +2540,135 @@
 			})...),
 	})
 }
+
+func TestCCLibraryRuntimeDeps(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Blueprint: `cc_library_shared {
+	name: "bar",
+}
+
+cc_library {
+  name: "foo",
+  runtime_libs: ["foo"],
+}`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "bar", AttrNameToString{
+				"local_includes": `["."]`,
+			}),
+			makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"runtime_deps":   `[":foo"]`,
+				"local_includes": `["."]`,
+			}),
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"runtime_deps":   `[":foo"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryWithInstructionSet(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `cc_library {
+    name: "foo",
+    arch: {
+      arm: {
+        instruction_set: "arm",
+      }
+    }
+}
+`,
+		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
+			"features": `select({
+        "//build/bazel/platforms/arch:arm": [
+            "arm_isa_arm",
+            "-arm_isa_thumb",
+        ],
+        "//conditions:default": [],
+    })`,
+			"local_includes": `["."]`,
+		}),
+	})
+}
+
+func TestCcLibraryWithAidlSrcs(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with aidl srcs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+filegroup {
+    name: "A_aidl",
+    srcs: ["aidl/A.aidl"],
+	path: "aidl",
+}
+cc_library {
+	name: "foo",
+	srcs: [
+		":A_aidl",
+		"B.aidl",
+	],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("aidl_library", "A_aidl", AttrNameToString{
+				"srcs":                `["aidl/A.aidl"]`,
+				"strip_import_prefix": `"aidl"`,
+			}),
+			makeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
+				"srcs": `["B.aidl"]`,
+			}),
+			makeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
+				"deps": `[
+        ":A_aidl",
+        ":foo_aidl_library",
+    ]`,
+			}),
+			makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"whole_archive_deps": `[":foo_cc_aidl_library"]`,
+				"local_includes":     `["."]`,
+			}),
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"whole_archive_deps": `[":foo_cc_aidl_library"]`,
+				"local_includes":     `["."]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryWithNonAdjacentAidlFilegroup(t *testing.T) {
+	runCcLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with non aidl filegroup",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"path/to/A/Android.bp": `
+filegroup {
+	name: "A_aidl",
+	srcs: ["aidl/A.aidl"],
+	path: "aidl",
+}`,
+		},
+		Blueprint: `
+cc_library {
+	name: "foo",
+	srcs: [
+		":A_aidl",
+	],
+}`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
+				"deps": `["//path/to/A:A_aidl"]`,
+			}),
+			makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+				"whole_archive_deps": `[":foo_cc_aidl_library"]`,
+				"local_includes":     `["."]`,
+			}),
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"whole_archive_deps": `[":foo_cc_aidl_library"]`,
+				"local_includes":     `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 641984b..5846f83 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -59,17 +59,17 @@
 	cc.RegisterCCBuildComponents(ctx)
 }
 
-func runCcLibraryHeadersTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibraryHeadersTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
 }
 
 func TestCcLibraryHeadersSimple(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers test",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem: map[string]string{
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers test",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem: map[string]string{
 			"lib-1/lib1a.h":                        "",
 			"lib-1/lib1b.h":                        "",
 			"lib-2/lib2a.h":                        "",
@@ -82,7 +82,7 @@
 			"arch_x86_exported_include_dir/b.h":    "",
 			"arch_x86_64_exported_include_dir/c.h": "",
 		},
-		blueprint: soongCcLibraryHeadersPreamble + `
+		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
     name: "foo_headers",
     export_include_dirs: ["dir-1", "dir-2"],
@@ -105,8 +105,8 @@
 
     // TODO: Also support export_header_lib_headers
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"export_includes": `[
         "dir-1",
         "dir-2",
@@ -124,12 +124,12 @@
 }
 
 func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers test with os-specific header_libs props",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers test with os-specific header_libs props",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryPreamble + `
 cc_library_headers {
     name: "android-lib",
     bazel_module: { bp2build_available: false },
@@ -182,8 +182,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":base-lib"] + select({
         "//build/bazel/platforms/os:android": [":android-lib"],
         "//build/bazel/platforms/os:darwin": [":darwin-lib"],
@@ -198,12 +198,12 @@
 }
 
 func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryPreamble + `
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryPreamble + `
 cc_library_headers {
     name: "android-lib",
     bazel_module: { bp2build_available: false },
@@ -222,8 +222,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `select({
         "//build/bazel/platforms/os:android": [":exported-lib"],
         "//conditions:default": [],
@@ -234,12 +234,12 @@
 }
 
 func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryPreamble + `cc_library_headers {
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryPreamble + `cc_library_headers {
     name: "foo_headers",
     export_system_include_dirs: [
         "shared_include_dir",
@@ -275,8 +275,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"export_system_includes": `["shared_include_dir"] + select({
         "//build/bazel/platforms/arch:arm": ["arm_include_dir"],
         "//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"],
@@ -293,11 +293,11 @@
 }
 
 func TestCcLibraryHeadersNoCrtIgnored(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers test",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem: map[string]string{
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers test",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem: map[string]string{
 			"lib-1/lib1a.h":                        "",
 			"lib-1/lib1b.h":                        "",
 			"lib-2/lib2a.h":                        "",
@@ -310,15 +310,15 @@
 			"arch_x86_exported_include_dir/b.h":    "",
 			"arch_x86_64_exported_include_dir/c.h": "",
 		},
-		blueprint: soongCcLibraryHeadersPreamble + `
+		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
     name: "lib-1",
     export_include_dirs: ["lib-1"],
     no_libcrt: true,
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "lib-1", AttrNameToString{
 				"export_includes": `["lib-1"]`,
 			}),
 		},
@@ -326,12 +326,12 @@
 }
 
 func TestCcLibraryHeadersExportedStaticLibHeadersReexported(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers exported_static_lib_headers is reexported",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryHeadersPreamble + `
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers exported_static_lib_headers is reexported",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
 		export_static_lib_headers: ["foo_export"],
@@ -339,8 +339,8 @@
     bazel_module: { bp2build_available: true },
 }
 ` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
 			}),
 		},
@@ -348,12 +348,12 @@
 }
 
 func TestCcLibraryHeadersExportedSharedLibHeadersReexported(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers exported_shared_lib_headers is reexported",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryHeadersPreamble + `
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers exported_shared_lib_headers is reexported",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
 		export_shared_lib_headers: ["foo_export"],
@@ -361,8 +361,8 @@
     bazel_module: { bp2build_available: true },
 }
 ` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
 			}),
 		},
@@ -370,12 +370,12 @@
 }
 
 func TestCcLibraryHeadersExportedHeaderLibHeadersReexported(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, bp2buildTestCase{
-		description:                "cc_library_headers exported_header_lib_headers is reexported",
-		moduleTypeUnderTest:        "cc_library_headers",
-		moduleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		filesystem:                 map[string]string{},
-		blueprint: soongCcLibraryHeadersPreamble + `
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers exported_header_lib_headers is reexported",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
 		export_header_lib_headers: ["foo_export"],
@@ -383,8 +383,29 @@
     bazel_module: { bp2build_available: true },
 }
 ` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_headers", "foo_headers", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
+				"deps": `[":foo_export"]`,
+			}),
+		},
+	})
+}
+
+func TestCcLibraryHeadersWholeStaticLibsReexported(t *testing.T) {
+	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_headers whole_static_libs is reexported",
+		ModuleTypeUnderTest:        "cc_library_headers",
+		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
+		Filesystem:                 map[string]string{},
+		Blueprint: soongCcLibraryHeadersPreamble + `
+cc_library_headers {
+		name: "foo_headers",
+		whole_static_libs: ["foo_export"],
+    bazel_module: { bp2build_available: true },
+}
+` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
 			}),
 		},
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 74729e4..7a44f69 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -35,17 +35,17 @@
 	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
 }
 
-func runCcLibrarySharedTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "cc_library_shared"
-	(&tc).moduleTypeUnderTestFactory = cc.LibrarySharedFactory
-	runBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
+	(&tc).ModuleTypeUnderTest = "cc_library_shared"
+	(&tc).ModuleTypeUnderTestFactory = cc.LibrarySharedFactory
+	RunBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
 }
 
 func TestCcLibrarySharedSimple(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared simple overall test",
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared simple overall test",
+		Filesystem: map[string]string{
 			// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
 			"include_dir_1/include_dir_1_a.h": "",
 			"include_dir_1/include_dir_1_b.h": "",
@@ -65,7 +65,7 @@
 			"implicit_include_1.h": "",
 			"implicit_include_2.h": "",
 		},
-		blueprint: soongCcLibrarySharedPreamble + `
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_headers {
     name: "header_lib_1",
     export_include_dirs: ["header_lib_1"],
@@ -141,8 +141,8 @@
 
     // TODO: Also support export_header_lib_headers
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"absolute_includes": `[
         "include_dir_1",
         "include_dir_2",
@@ -184,10 +184,10 @@
 }
 
 func TestCcLibrarySharedArchSpecificSharedLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibrarySharedPreamble + `
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_static {
     name: "static_dep",
     bazel_module: { bp2build_available: false },
@@ -201,8 +201,8 @@
     arch: { arm64: { shared_libs: ["shared_dep"], whole_static_libs: ["static_dep"] } },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"implementation_dynamic_deps": `select({
         "//build/bazel/platforms/arch:arm64": [":shared_dep"],
         "//conditions:default": [],
@@ -217,10 +217,10 @@
 }
 
 func TestCcLibrarySharedOsSpecificSharedLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared os-specific shared_libs",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibrarySharedPreamble + `
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared os-specific shared_libs",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
     name: "shared_dep",
     bazel_module: { bp2build_available: false },
@@ -230,8 +230,8 @@
     target: { android: { shared_libs: ["shared_dep"], } },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"implementation_dynamic_deps": `select({
         "//build/bazel/platforms/os:android": [":shared_dep"],
         "//conditions:default": [],
@@ -242,10 +242,10 @@
 }
 
 func TestCcLibrarySharedBaseArchOsSpecificSharedLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared base, arch, and os-specific shared_libs",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibrarySharedPreamble + `
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared base, arch, and os-specific shared_libs",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
     name: "shared_dep",
     bazel_module: { bp2build_available: false },
@@ -265,8 +265,8 @@
     arch: { arm64: { shared_libs: ["shared_dep3"] } },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"implementation_dynamic_deps": `[":shared_dep"] + select({
         "//build/bazel/platforms/arch:arm64": [":shared_dep3"],
         "//conditions:default": [],
@@ -280,22 +280,22 @@
 }
 
 func TestCcLibrarySharedSimpleExcludeSrcs(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared simple exclude_srcs",
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared simple exclude_srcs",
+		Filesystem: map[string]string{
 			"common.c":       "",
 			"foo-a.c":        "",
 			"foo-excluded.c": "",
 		},
-		blueprint: soongCcLibrarySharedPreamble + `
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
     name: "foo_shared",
     srcs: ["common.c", "foo-*.c"],
     exclude_srcs: ["foo-excluded.c"],
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"srcs_c": `[
         "common.c",
         "foo-a.c",
@@ -306,10 +306,10 @@
 }
 
 func TestCcLibrarySharedStrip(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared stripping",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibrarySharedPreamble + `
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared stripping",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
     name: "foo_shared",
     strip: {
@@ -321,8 +321,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"strip": `{
         "all": True,
         "keep_symbols": False,
@@ -339,19 +339,19 @@
 }
 
 func TestCcLibrarySharedVersionScript(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared version script",
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared version script",
+		Filesystem: map[string]string{
 			"version_script": "",
 		},
-		blueprint: soongCcLibrarySharedPreamble + `
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
     name: "foo_shared",
     version_script: "version_script",
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"additional_linker_inputs": `["version_script"]`,
 				"linkopts":                 `["-Wl,--version-script,$(location version_script)"]`,
 			}),
@@ -360,12 +360,12 @@
 }
 
 func TestCcLibrarySharedNoCrtTrue(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared - nocrt: true emits attribute",
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared - nocrt: true emits attribute",
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library_shared {
     name: "foo_shared",
     srcs: ["impl.cpp"],
@@ -373,8 +373,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"link_crt": `False`,
 				"srcs":     `["impl.cpp"]`,
 			}),
@@ -383,12 +383,12 @@
 }
 
 func TestCcLibrarySharedNoCrtFalse(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared - nocrt: false doesn't emit attribute",
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared - nocrt: false doesn't emit attribute",
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library_shared {
     name: "foo_shared",
     srcs: ["impl.cpp"],
@@ -396,8 +396,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo_shared", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"srcs": `["impl.cpp"]`,
 			}),
 		},
@@ -405,12 +405,12 @@
 }
 
 func TestCcLibrarySharedNoCrtArchVariant(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description: "cc_library_shared - nocrt in select",
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_shared - nocrt in select",
+		Filesystem: map[string]string{
 			"impl.cpp": "",
 		},
-		blueprint: soongCcLibraryPreamble + `
+		Blueprint: soongCcLibraryPreamble + `
 cc_library_shared {
     name: "foo_shared",
     srcs: ["impl.cpp"],
@@ -425,13 +425,13 @@
     include_build_directory: false,
 }
 `,
-		expectedErr: fmt.Errorf("module \"foo_shared\": nocrt is not supported for arch variants"),
+		ExpectedErr: fmt.Errorf("module \"foo_shared\": nocrt is not supported for arch variants"),
 	})
 }
 
 func TestCcLibrarySharedProto(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		blueprint: soongCcProtoPreamble + `cc_library_shared {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcProtoPreamble + `cc_library_shared {
 	name: "foo",
 	srcs: ["foo.proto"],
 	proto: {
@@ -439,12 +439,12 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
@@ -453,14 +453,14 @@
 }
 
 func TestCcLibrarySharedUseVersionLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		blueprint: soongCcProtoPreamble + `cc_library_shared {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcProtoPreamble + `cc_library_shared {
         name: "foo",
         use_version_lib: true,
         include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"use_version_lib": "True",
 			}),
 		},
@@ -468,12 +468,12 @@
 }
 
 func TestCcLibrarySharedStubs(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description:                "cc_library_shared stubs",
-		moduleTypeUnderTest:        "cc_library_shared",
-		moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		dir:                        "foo/bar",
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_shared stubs",
+		ModuleTypeUnderTest:        "cc_library_shared",
+		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+		Dir:                        "foo/bar",
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": `
 cc_library_shared {
 	name: "a",
@@ -483,14 +483,9 @@
 }
 `,
 		},
-		blueprint: soongCcLibraryPreamble,
-		expectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "a", attrNameToString{
-			"stubs_symbol_file": `"a.map.txt"`,
-			"stubs_versions": `[
-        "28",
-        "29",
-        "current",
-    ]`,
+		Blueprint: soongCcLibraryPreamble,
+		ExpectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "a", AttrNameToString{
+			"has_stubs": `True`,
 		}),
 		},
 	},
@@ -498,11 +493,11 @@
 }
 
 func TestCcLibrarySharedSystemSharedLibsSharedEmpty(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description:                "cc_library_shared system_shared_libs empty shared default",
-		moduleTypeUnderTest:        "cc_library_shared",
-		moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		blueprint: soongCcLibrarySharedPreamble + `
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_shared system_shared_libs empty shared default",
+		ModuleTypeUnderTest:        "cc_library_shared",
+		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+		Blueprint: soongCcLibrarySharedPreamble + `
 cc_defaults {
     name: "empty_defaults",
     shared: {
@@ -515,18 +510,18 @@
     defaults: ["empty_defaults"],
 }
 `,
-		expectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "empty", attrNameToString{
+		ExpectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "empty", AttrNameToString{
 			"system_dynamic_deps": "[]",
 		})},
 	})
 }
 
 func TestCcLibrarySharedConvertLex(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description:                "cc_library_shared with lex files",
-		moduleTypeUnderTest:        "cc_library_shared",
-		moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_shared with lex files",
+		ModuleTypeUnderTest:        "cc_library_shared",
+		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+		Filesystem: map[string]string{
 			"foo.c":   "",
 			"bar.cc":  "",
 			"foo1.l":  "",
@@ -534,29 +529,29 @@
 			"foo2.l":  "",
 			"bar2.ll": "",
 		},
-		blueprint: `cc_library_shared {
+		Blueprint: `cc_library_shared {
 	name: "foo_lib",
 	srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
 	lex: { flags: ["--foo_flags"] },
 	include_build_directory: false,
 	bazel_module: { bp2build_available: true },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("genlex", "foo_lib_genlex_l", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
 				"srcs": `[
         "foo1.l",
         "foo2.l",
     ]`,
 				"lexopts": `["--foo_flags"]`,
 			}),
-			makeBazelTarget("genlex", "foo_lib_genlex_ll", attrNameToString{
+			makeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
 				"srcs": `[
         "bar1.ll",
         "bar2.ll",
     ]`,
 				"lexopts": `["--foo_flags"]`,
 			}),
-			makeBazelTarget("cc_library_shared", "foo_lib", attrNameToString{
+			makeBazelTarget("cc_library_shared", "foo_lib", AttrNameToString{
 				"srcs": `[
         "bar.cc",
         ":foo_lib_genlex_ll",
@@ -571,8 +566,8 @@
 }
 
 func TestCcLibrarySharedClangUnknownFlags(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		blueprint: soongCcProtoPreamble + `cc_library_shared {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcProtoPreamble + `cc_library_shared {
 	name: "foo",
 	conlyflags: ["-a", "-finline-functions"],
 	cflags: ["-b","-finline-functions"],
@@ -580,8 +575,8 @@
 	ldflags: ["-d","-finline-functions", "-e"],
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"conlyflags": `["-a"]`,
 				"copts":      `["-b"]`,
 				"cppflags":   `["-c"]`,
@@ -595,8 +590,8 @@
 }
 
 func TestCCLibraryFlagSpaceSplitting(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		blueprint: soongCcProtoPreamble + `cc_library_shared {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcProtoPreamble + `cc_library_shared {
 	name: "foo",
 	conlyflags: [ "-include header.h"],
 	cflags: ["-include header.h"],
@@ -604,8 +599,8 @@
 	version_script: "version_script",
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_shared", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"additional_linker_inputs": `["version_script"]`,
 				"conlyflags": `[
         "-include",
@@ -624,3 +619,25 @@
 		},
 	})
 }
+
+func TestCCLibrarySharedRuntimeDeps(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Blueprint: `cc_library_shared {
+	name: "bar",
+}
+
+cc_library_shared {
+  name: "foo",
+  runtime_libs: ["foo"],
+}`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "bar", AttrNameToString{
+				"local_includes": `["."]`,
+			}),
+			makeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+				"runtime_deps":   `[":foo"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 36c46a4..1c160ec 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -15,12 +15,12 @@
 package bp2build
 
 import (
+	"fmt"
+	"testing"
+
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/genrule"
-	"fmt"
-
-	"testing"
 )
 
 const (
@@ -65,18 +65,18 @@
 	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
 }
 
-func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcLibraryStaticTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
 
-	(&tc).moduleTypeUnderTest = "cc_library_static"
-	(&tc).moduleTypeUnderTestFactory = cc.LibraryStaticFactory
-	runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
+	(&tc).ModuleTypeUnderTest = "cc_library_static"
+	(&tc).ModuleTypeUnderTestFactory = cc.LibraryStaticFactory
+	RunBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
 }
 
 func TestCcLibraryStaticSimple(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static test",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static test",
+		Filesystem: map[string]string{
 			// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
 			"include_dir_1/include_dir_1_a.h": "",
 			"include_dir_1/include_dir_1_b.h": "",
@@ -96,7 +96,7 @@
 			"implicit_include_1.h": "",
 			"implicit_include_2.h": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_headers {
     name: "header_lib_1",
     export_include_dirs: ["header_lib_1"],
@@ -172,8 +172,8 @@
 
     // TODO: Also support export_header_lib_headers
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"absolute_includes": `[
         "include_dir_1",
         "include_dir_2",
@@ -213,9 +213,9 @@
 }
 
 func TestCcLibraryStaticSubpackage(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static subpackage test",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static subpackage test",
+		Filesystem: map[string]string{
 			// subpackage with subdirectory
 			"subpackage/Android.bp":                         "",
 			"subpackage/subpackage_header.h":                "",
@@ -229,7 +229,7 @@
 			"subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h":          "",
 			"subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: [],
@@ -237,8 +237,8 @@
         "subpackage",
     ],
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"absolute_includes": `["subpackage"]`,
 				"local_includes":    `["."]`,
 			}),
@@ -247,22 +247,22 @@
 }
 
 func TestCcLibraryStaticExportIncludeDir(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static export include dir",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static export include dir",
+		Filesystem: map[string]string{
 			// subpackage with subdirectory
 			"subpackage/Android.bp":                         "",
 			"subpackage/subpackage_header.h":                "",
 			"subpackage/subdirectory/subdirectory_header.h": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     export_include_dirs: ["subpackage"],
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"export_includes": `["subpackage"]`,
 			}),
 		},
@@ -270,22 +270,22 @@
 }
 
 func TestCcLibraryStaticExportSystemIncludeDir(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static export system include dir",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static export system include dir",
+		Filesystem: map[string]string{
 			// subpackage with subdirectory
 			"subpackage/Android.bp":                         "",
 			"subpackage/subpackage_header.h":                "",
 			"subpackage/subdirectory/subdirectory_header.h": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     export_system_include_dirs: ["subpackage"],
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"export_system_includes": `["subpackage"]`,
 			}),
 		},
@@ -293,10 +293,10 @@
 }
 
 func TestCcLibraryStaticManyIncludeDirs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
-		dir:         "subpackage",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
+		Dir:         "subpackage",
+		Filesystem: map[string]string{
 			// subpackage with subdirectory
 			"subpackage/Android.bp": `
 cc_library_static {
@@ -318,9 +318,9 @@
 			"subpackage2/header.h":                       "",
 			"subpackage3/subsubpackage/header.h":         "",
 		},
-		blueprint: soongCcLibraryStaticPreamble,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		Blueprint: soongCcLibraryStaticPreamble,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"absolute_includes": `[
         "subpackage/subsubpackage",
         "subpackage2",
@@ -336,23 +336,23 @@
 }
 
 func TestCcLibraryStaticIncludeBuildDirectoryDisabled(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static include_build_directory disabled",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static include_build_directory disabled",
+		Filesystem: map[string]string{
 			// subpackage with subdirectory
 			"subpackage/Android.bp":                         "",
 			"subpackage/subpackage_header.h":                "",
 			"subpackage/subdirectory/subdirectory_header.h": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
     local_include_dirs: ["subpackage2"],
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"absolute_includes": `["subpackage"]`,
 				"local_includes":    `["subpackage2"]`,
 			}),
@@ -361,9 +361,9 @@
 }
 
 func TestCcLibraryStaticIncludeBuildDirectoryEnabled(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static include_build_directory enabled",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static include_build_directory enabled",
+		Filesystem: map[string]string{
 			// subpackage with subdirectory
 			"subpackage/Android.bp":                         "",
 			"subpackage/subpackage_header.h":                "",
@@ -371,15 +371,15 @@
 			"subpackage2/subpackage2_header.h":              "",
 			"subpackage/subdirectory/subdirectory_header.h": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
     local_include_dirs: ["subpackage2"],
     include_build_directory: true,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"absolute_includes": `["subpackage"]`,
 				"local_includes": `[
         "subpackage2",
@@ -391,10 +391,10 @@
 }
 
 func TestCcLibraryStaticArchSpecificStaticLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static arch-specific static_libs",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static arch-specific static_libs",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "static_dep",
     bazel_module: { bp2build_available: false },
@@ -408,8 +408,8 @@
     arch: { arm64: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"implementation_deps": `select({
         "//build/bazel/platforms/arch:arm64": [":static_dep"],
         "//conditions:default": [],
@@ -424,10 +424,10 @@
 }
 
 func TestCcLibraryStaticOsSpecificStaticLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static os-specific static_libs",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static os-specific static_libs",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "static_dep",
     bazel_module: { bp2build_available: false },
@@ -441,8 +441,8 @@
     target: { android: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"implementation_deps": `select({
         "//build/bazel/platforms/os:android": [":static_dep"],
         "//conditions:default": [],
@@ -457,10 +457,10 @@
 }
 
 func TestCcLibraryStaticBaseArchOsSpecificStaticLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static base, arch and os-specific static_libs",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static base, arch and os-specific static_libs",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "static_dep",
     bazel_module: { bp2build_available: false },
@@ -485,8 +485,8 @@
     arch: { arm64: { static_libs: ["static_dep4"] } },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"implementation_deps": `[":static_dep"] + select({
         "//build/bazel/platforms/arch:arm64": [":static_dep4"],
         "//conditions:default": [],
@@ -501,22 +501,22 @@
 }
 
 func TestCcLibraryStaticSimpleExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static simple exclude_srcs",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static simple exclude_srcs",
+		Filesystem: map[string]string{
 			"common.c":       "",
 			"foo-a.c":        "",
 			"foo-excluded.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c", "foo-*.c"],
     exclude_srcs: ["foo-excluded.c"],
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `[
         "common.c",
         "foo-a.c",
@@ -527,21 +527,21 @@
 }
 
 func TestCcLibraryStaticOneArchSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static one arch specific srcs",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static one arch specific srcs",
+		Filesystem: map[string]string{
 			"common.c":  "",
 			"foo-arm.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c"],
     arch: { arm: { srcs: ["foo-arm.c"] } },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
         "//build/bazel/platforms/arch:arm": ["foo-arm.c"],
         "//conditions:default": [],
@@ -552,15 +552,15 @@
 }
 
 func TestCcLibraryStaticOneArchSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static one arch specific srcs and exclude_srcs",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static one arch specific srcs and exclude_srcs",
+		Filesystem: map[string]string{
 			"common.c":           "",
 			"for-arm.c":          "",
 			"not-for-arm.c":      "",
 			"not-for-anything.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c", "not-for-*.c"],
@@ -570,8 +570,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
         "//build/bazel/platforms/arch:arm": ["for-arm.c"],
         "//conditions:default": ["not-for-arm.c"],
@@ -582,16 +582,16 @@
 }
 
 func TestCcLibraryStaticTwoArchExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static arch specific exclude_srcs for 2 architectures",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static arch specific exclude_srcs for 2 architectures",
+		Filesystem: map[string]string{
 			"common.c":      "",
 			"for-arm.c":     "",
 			"for-x86.c":     "",
 			"not-for-arm.c": "",
 			"not-for-x86.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c", "not-for-*.c"],
@@ -602,8 +602,8 @@
     },
     include_build_directory: false,
 } `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
         "//build/bazel/platforms/arch:arm": [
             "not-for-x86.c",
@@ -624,9 +624,9 @@
 }
 
 func TestCcLibraryStaticFourArchExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static arch specific exclude_srcs for 4 architectures",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static arch specific exclude_srcs for 4 architectures",
+		Filesystem: map[string]string{
 			"common.c":             "",
 			"for-arm.c":            "",
 			"for-arm64.c":          "",
@@ -638,7 +638,7 @@
 			"not-for-x86_64.c":     "",
 			"not-for-everything.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c", "not-for-*.c"],
@@ -651,8 +651,8 @@
   },
     include_build_directory: false,
 } `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
         "//build/bazel/platforms/arch:arm": [
             "not-for-arm64.c",
@@ -691,14 +691,14 @@
 }
 
 func TestCcLibraryStaticOneArchEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static one arch empty",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static one arch empty",
+		Filesystem: map[string]string{
 			"common.cc":       "",
 			"foo-no-arm.cc":   "",
 			"foo-excluded.cc": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.cc", "foo-*.cc"],
@@ -708,8 +708,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs": `["common.cc"] + select({
         "//build/bazel/platforms/arch:arm": [],
         "//conditions:default": ["foo-no-arm.cc"],
@@ -720,15 +720,15 @@
 }
 
 func TestCcLibraryStaticOneArchEmptyOtherSet(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static one arch empty other set",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static one arch empty other set",
+		Filesystem: map[string]string{
 			"common.cc":       "",
 			"foo-no-arm.cc":   "",
 			"x86-only.cc":     "",
 			"foo-excluded.cc": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.cc", "foo-*.cc"],
@@ -739,8 +739,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs": `["common.cc"] + select({
         "//build/bazel/platforms/arch:arm": [],
         "//build/bazel/platforms/arch:x86": [
@@ -755,10 +755,10 @@
 }
 
 func TestCcLibraryStaticMultipleDepSameName(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static multiple dep same name panic",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static multiple dep same name panic",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "static_dep",
     bazel_module: { bp2build_available: false },
@@ -768,8 +768,8 @@
     static_libs: ["static_dep", "static_dep"],
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"implementation_deps": `[":static_dep"]`,
 			}),
 		},
@@ -777,14 +777,14 @@
 }
 
 func TestCcLibraryStaticOneMultilibSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static 1 multilib srcs and exclude_srcs",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static 1 multilib srcs and exclude_srcs",
+		Filesystem: map[string]string{
 			"common.c":        "",
 			"for-lib32.c":     "",
 			"not-for-lib32.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c", "not-for-*.c"],
@@ -793,8 +793,8 @@
     },
     include_build_directory: false,
 } `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
         "//build/bazel/platforms/arch:arm": ["for-lib32.c"],
         "//build/bazel/platforms/arch:x86": ["for-lib32.c"],
@@ -806,16 +806,16 @@
 }
 
 func TestCcLibraryStaticTwoMultilibSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static 2 multilib srcs and exclude_srcs",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static 2 multilib srcs and exclude_srcs",
+		Filesystem: map[string]string{
 			"common.c":        "",
 			"for-lib32.c":     "",
 			"for-lib64.c":     "",
 			"not-for-lib32.c": "",
 			"not-for-lib64.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c", "not-for-*.c"],
@@ -825,8 +825,8 @@
     },
     include_build_directory: false,
 } `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
         "//build/bazel/platforms/arch:arm": [
             "not-for-lib64.c",
@@ -855,9 +855,9 @@
 }
 
 func TestCcLibrarySTaticArchMultilibSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static arch and multilib srcs and exclude_srcs",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static arch and multilib srcs and exclude_srcs",
+		Filesystem: map[string]string{
 			"common.c":             "",
 			"for-arm.c":            "",
 			"for-arm64.c":          "",
@@ -873,7 +873,7 @@
 			"not-for-lib64.c":      "",
 			"not-for-everything.c": "",
 		},
-		blueprint: soongCcLibraryStaticPreamble + `
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
    name: "foo_static",
    srcs: ["common.c", "not-for-*.c"],
@@ -890,8 +890,8 @@
    },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
         "//build/bazel/platforms/arch:arm": [
             "not-for-arm64.c",
@@ -940,8 +940,8 @@
 }
 
 func TestCcLibraryStaticGeneratedHeadersAllPartitions(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcLibraryStaticPreamble + `
 genrule {
     name: "generated_hdr",
     cmd: "nothing to see here",
@@ -961,8 +961,8 @@
     export_generated_headers: ["export_generated_hdr"],
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"export_includes": `["."]`,
 				"local_includes":  `["."]`,
 				"hdrs":            `[":export_generated_hdr"]`,
@@ -984,9 +984,9 @@
 }
 
 func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static arch srcs/exclude_srcs with generated files",
-		filesystem: map[string]string{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static arch srcs/exclude_srcs with generated files",
+		Filesystem: map[string]string{
 			"common.cpp":             "",
 			"for-x86.cpp":            "",
 			"not-for-x86.cpp":        "",
@@ -997,7 +997,7 @@
 				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") +
 				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"),
 		},
-		blueprint: soongCcLibraryStaticPreamble +
+		Blueprint: soongCcLibraryStaticPreamble +
 			simpleModuleDoNotConvertBp2build("genrule", "generated_src") +
 			simpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") +
 			simpleModuleDoNotConvertBp2build("genrule", "generated_src_android") +
@@ -1029,8 +1029,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs": `[
         "common.cpp",
         ":generated_src",
@@ -1061,10 +1061,10 @@
 }
 
 func TestCcLibraryStaticGetTargetProperties(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
 
-		description: "cc_library_static complex GetTargetProperties",
-		blueprint: soongCcLibraryStaticPreamble + `
+		Description: "cc_library_static complex GetTargetProperties",
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     target: {
@@ -1092,8 +1092,8 @@
     },
     include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `select({
         "//build/bazel/platforms/os:android": ["android_src.c"],
         "//conditions:default": [],
@@ -1112,9 +1112,9 @@
 }
 
 func TestCcLibraryStaticProductVariableSelects(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static product variable selects",
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static product variable selects",
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c"],
@@ -1131,8 +1131,8 @@
     },
     include_build_directory: false,
 } `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"copts": `select({
         "//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
         "//conditions:default": [],
@@ -1150,10 +1150,10 @@
 }
 
 func TestCcLibraryStaticProductVariableArchSpecificSelects(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static arch-specific product variable selects",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static arch-specific product variable selects",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.c"],
@@ -1191,8 +1191,8 @@
     },
     include_build_directory: false,
 } `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"copts": `select({
         "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
         "//conditions:default": [],
@@ -1216,10 +1216,10 @@
 }
 
 func TestCcLibraryStaticProductVariableStringReplacement(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static product variable string replacement",
-		filesystem:  map[string]string{},
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static product variable string replacement",
+		Filesystem:  map[string]string{},
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.S"],
@@ -1230,8 +1230,8 @@
     },
     include_build_directory: false,
 } `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo_static", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"asflags": `select({
         "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
         "//conditions:default": [],
@@ -1243,17 +1243,17 @@
 }
 
 func TestStaticLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static system_shared_lib empty root",
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static system_shared_lib empty root",
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "root_empty",
     system_shared_libs: [],
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "root_empty", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "root_empty", AttrNameToString{
 				"system_dynamic_deps": `[]`,
 			}),
 		},
@@ -1261,9 +1261,9 @@
 }
 
 func TestStaticLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static system_shared_lib empty static default",
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static system_shared_lib empty static default",
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_defaults {
     name: "static_empty_defaults",
     static: {
@@ -1276,8 +1276,8 @@
     defaults: ["static_empty_defaults"],
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "static_empty", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "static_empty", AttrNameToString{
 				"system_dynamic_deps": `[]`,
 			}),
 		},
@@ -1285,9 +1285,9 @@
 }
 
 func TestStaticLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static system_shared_lib empty for bionic variant",
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static system_shared_lib empty for bionic variant",
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "target_bionic_empty",
     target: {
@@ -1298,8 +1298,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "target_bionic_empty", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "target_bionic_empty", AttrNameToString{
 				"system_dynamic_deps": `[]`,
 			}),
 		},
@@ -1311,9 +1311,9 @@
 	// The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
 	// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
 	// b/195791252 tracks the fix.
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static system_shared_lib empty for linux_bionic variant",
-		blueprint: soongCcLibraryStaticPreamble + `
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
+		Blueprint: soongCcLibraryStaticPreamble + `
 cc_library_static {
     name: "target_linux_bionic_empty",
     target: {
@@ -1324,8 +1324,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "target_linux_bionic_empty", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "target_linux_bionic_empty", AttrNameToString{
 				"system_dynamic_deps": `[]`,
 			}),
 		},
@@ -1333,9 +1333,9 @@
 }
 
 func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static system_shared_libs set for bionic variant",
-		blueprint: soongCcLibraryStaticPreamble +
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static system_shared_libs set for bionic variant",
+		Blueprint: soongCcLibraryStaticPreamble +
 			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
 cc_library_static {
     name: "target_bionic",
@@ -1347,8 +1347,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "target_bionic", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "target_bionic", AttrNameToString{
 				"system_dynamic_deps": `select({
         "//build/bazel/platforms/os:android": [":libc"],
         "//build/bazel/platforms/os:linux_bionic": [":libc"],
@@ -1360,9 +1360,9 @@
 }
 
 func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
-		blueprint: soongCcLibraryStaticPreamble +
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
+		Blueprint: soongCcLibraryStaticPreamble +
 			simpleModuleDoNotConvertBp2build("cc_library", "libc") +
 			simpleModuleDoNotConvertBp2build("cc_library", "libm") + `
 cc_library_static {
@@ -1376,8 +1376,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "target_linux_bionic", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "target_linux_bionic", AttrNameToString{
 				"system_dynamic_deps": `[":libc"] + select({
         "//build/bazel/platforms/os:linux_bionic": [":libm"],
         "//conditions:default": [],
@@ -1388,9 +1388,9 @@
 }
 
 func TestCcLibrarystatic_SystemSharedLibUsedAsDep(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		description: "cc_library_static system_shared_lib empty for linux_bionic variant",
-		blueprint: soongCcLibraryStaticPreamble +
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
+		Blueprint: soongCcLibraryStaticPreamble +
 			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
 cc_library_static {
     name: "used_in_bionic_oses",
@@ -1418,26 +1418,26 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "all", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "all", AttrNameToString{
 				"implementation_dynamic_deps": `select({
         "//build/bazel/platforms/os:android": [],
         "//build/bazel/platforms/os:linux_bionic": [],
         "//conditions:default": [":libc"],
     })`,
 			}),
-			makeBazelTarget("cc_library_static", "keep_for_empty_system_shared_libs", attrNameToString{
+			makeBazelTarget("cc_library_static", "keep_for_empty_system_shared_libs", AttrNameToString{
 				"implementation_dynamic_deps": `[":libc"]`,
 				"system_dynamic_deps":         `[]`,
 			}),
-			makeBazelTarget("cc_library_static", "used_in_bionic_oses", attrNameToString{}),
+			makeBazelTarget("cc_library_static", "used_in_bionic_oses", AttrNameToString{}),
 		},
 	})
 }
 
 func TestCcLibraryStaticProto(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		blueprint: soongCcProtoPreamble + `cc_library_static {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcProtoPreamble + `cc_library_static {
 	name: "foo",
 	srcs: ["foo.proto"],
 	proto: {
@@ -1445,12 +1445,12 @@
 	},
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "foo_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "foo_proto", AttrNameToString{
 				"srcs": `["foo.proto"]`,
-			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", attrNameToString{
+			}), makeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
 				"deps": `[":foo_proto"]`,
-			}), makeBazelTarget("cc_library_static", "foo", attrNameToString{
+			}), makeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"deps":               `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
 			}),
@@ -1459,14 +1459,14 @@
 }
 
 func TestCcLibraryStaticUseVersionLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		blueprint: soongCcProtoPreamble + `cc_library_static {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcProtoPreamble + `cc_library_static {
 	name: "foo",
 	use_version_lib: true,
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"use_version_lib": "True",
 			}),
 		},
@@ -1474,16 +1474,16 @@
 }
 
 func TestCcLibraryStaticStdInFlags(t *testing.T) {
-	runCcLibraryStaticTestCase(t, bp2buildTestCase{
-		blueprint: soongCcProtoPreamble + `cc_library_static {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcProtoPreamble + `cc_library_static {
 	name: "foo",
 	cflags: ["-std=candcpp"],
 	conlyflags: ["-std=conly"],
 	cppflags: ["-std=cpp"],
 	include_build_directory: false,
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_library_static", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"conlyflags": `["-std=conly"]`,
 				"cppflags":   `["-std=cpp"]`,
 			}),
@@ -1495,67 +1495,89 @@
 	testCases := []struct {
 		desc string
 		prop string
-		attr attrNameToString
+		attr AttrNameToString
 	}{
 		{
 			desc: "c++_shared deduped to libc++",
 			prop: `stl: "c++_shared",`,
-			attr: attrNameToString{
+			attr: AttrNameToString{
 				"stl": `"libc++"`,
 			},
 		},
 		{
 			desc: "libc++ to libc++",
 			prop: `stl: "libc++",`,
-			attr: attrNameToString{
+			attr: AttrNameToString{
 				"stl": `"libc++"`,
 			},
 		},
 		{
 			desc: "c++_static to libc++_static",
 			prop: `stl: "c++_static",`,
-			attr: attrNameToString{
+			attr: AttrNameToString{
 				"stl": `"libc++_static"`,
 			},
 		},
 		{
 			desc: "libc++_static to libc++_static",
 			prop: `stl: "libc++_static",`,
-			attr: attrNameToString{
+			attr: AttrNameToString{
 				"stl": `"libc++_static"`,
 			},
 		},
 		{
 			desc: "system to system",
 			prop: `stl: "system",`,
-			attr: attrNameToString{
+			attr: AttrNameToString{
 				"stl": `"system"`,
 			},
 		},
 		{
 			desc: "none to none",
 			prop: `stl: "none",`,
-			attr: attrNameToString{
+			attr: AttrNameToString{
 				"stl": `"none"`,
 			},
 		},
 		{
 			desc: "empty to empty",
-			attr: attrNameToString{},
+			attr: AttrNameToString{},
 		},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.desc, func(*testing.T) {
-			runCcLibraryStaticTestCase(t, bp2buildTestCase{
-				blueprint: fmt.Sprintf(`cc_library_static {
+			runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+				Blueprint: fmt.Sprintf(`cc_library_static {
 	name: "foo",
 	include_build_directory: false,
 	%s
 }`, tc.prop),
-				expectedBazelTargets: []string{
+				ExpectedBazelTargets: []string{
 					makeBazelTarget("cc_library_static", "foo", tc.attr),
 				},
 			})
 		})
 	}
 }
+
+func TestCCLibraryStaticRuntimeDeps(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Blueprint: `cc_library_shared {
+	name: "bar",
+}
+
+cc_library_static {
+  name: "foo",
+  runtime_libs: ["foo"],
+}`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_library_shared", "bar", AttrNameToString{
+				"local_includes": `["."]`,
+			}),
+			makeBazelTarget("cc_library_static", "foo", AttrNameToString{
+				"runtime_deps":   `[":foo"]`,
+				"local_includes": `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index 52688d9..37d5580 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -26,23 +26,23 @@
 	ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
 }
 
-func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) {
+func runCcObjectTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "cc_object"
-	(&tc).moduleTypeUnderTestFactory = cc.ObjectFactory
-	runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
+	(&tc).ModuleTypeUnderTest = "cc_object"
+	(&tc).ModuleTypeUnderTestFactory = cc.ObjectFactory
+	RunBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
 }
 
 func TestCcObjectSimple(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "simple cc_object generates cc_object with include header dep",
-		filesystem: map[string]string{
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "simple cc_object generates cc_object with include header dep",
+		Filesystem: map[string]string{
 			"a/b/foo.h":     "",
 			"a/b/bar.h":     "",
 			"a/b/exclude.c": "",
 			"a/b/c.c":       "",
 		},
-		blueprint: `cc_object {
+		Blueprint: `cc_object {
     name: "foo",
     local_include_dirs: ["include"],
     system_shared_libs: [],
@@ -59,8 +59,8 @@
     min_sdk_version: "29",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `[
         "-fno-addrsig",
         "-Wno-gcc-compat",
@@ -73,16 +73,16 @@
     ]`,
 				"srcs":                `["a/b/c.c"]`,
 				"system_dynamic_deps": `[]`,
-        "sdk_version": `"current"`,
-        "min_sdk_version": `"29"`,
+				"sdk_version":         `"current"`,
+				"min_sdk_version":     `"29"`,
 			}),
 		},
 	})
 }
 
 func TestCcObjectDefaults(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		blueprint: `cc_object {
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Blueprint: `cc_object {
     name: "foo",
     system_shared_libs: [],
     srcs: [
@@ -105,8 +105,8 @@
     ],
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `[
         "-Werror",
         "-fno-addrsig",
@@ -119,13 +119,13 @@
 }
 
 func TestCcObjectCcObjetDepsInObjs(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object with cc_object deps in objs props",
-		filesystem: map[string]string{
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object with cc_object deps in objs props",
+		Filesystem: map[string]string{
 			"a/b/c.c": "",
 			"x/y/z.c": "",
 		},
-		blueprint: `cc_object {
+		Blueprint: `cc_object {
     name: "foo",
     system_shared_libs: [],
     srcs: ["a/b/c.c"],
@@ -140,12 +140,12 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "bar", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "bar", AttrNameToString{
 				"copts":               `["-fno-addrsig"]`,
 				"srcs":                `["x/y/z.c"]`,
 				"system_dynamic_deps": `[]`,
-			}), makeBazelTarget("cc_object", "foo", attrNameToString{
+			}), makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts":               `["-fno-addrsig"]`,
 				"deps":                `[":bar"]`,
 				"srcs":                `["a/b/c.c"]`,
@@ -156,21 +156,21 @@
 }
 
 func TestCcObjectIncludeBuildDirFalse(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object with include_build_dir: false",
-		filesystem: map[string]string{
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object with include_build_dir: false",
+		Filesystem: map[string]string{
 			"a/b/c.c": "",
 			"x/y/z.c": "",
 		},
-		blueprint: `cc_object {
+		Blueprint: `cc_object {
     name: "foo",
     system_shared_libs: [],
     srcs: ["a/b/c.c"],
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts":               `["-fno-addrsig"]`,
 				"srcs":                `["a/b/c.c"]`,
 				"system_dynamic_deps": `[]`,
@@ -180,9 +180,9 @@
 }
 
 func TestCcObjectProductVariable(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object with product variable",
-		blueprint: `cc_object {
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object with product variable",
+		Blueprint: `cc_object {
     name: "foo",
     system_shared_libs: [],
     include_build_directory: false,
@@ -194,8 +194,8 @@
     srcs: ["src.S"],
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"asflags": `select({
         "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
         "//conditions:default": [],
@@ -209,9 +209,9 @@
 }
 
 func TestCcObjectCflagsOneArch(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object setting cflags for one arch",
-		blueprint: `cc_object {
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object setting cflags for one arch",
+		Blueprint: `cc_object {
     name: "foo",
     system_shared_libs: [],
     srcs: ["a.cpp"],
@@ -226,8 +226,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `["-fno-addrsig"] + select({
         "//build/bazel/platforms/arch:x86": ["-fPIC"],
         "//conditions:default": [],
@@ -243,9 +243,9 @@
 }
 
 func TestCcObjectCflagsFourArch(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object setting cflags for 4 architectures",
-		blueprint: `cc_object {
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object setting cflags for 4 architectures",
+		Blueprint: `cc_object {
     name: "foo",
     system_shared_libs: [],
     srcs: ["base.cpp"],
@@ -270,8 +270,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `["-fno-addrsig"] + select({
         "//build/bazel/platforms/arch:arm": ["-Wall"],
         "//build/bazel/platforms/arch:arm64": ["-Wall"],
@@ -293,17 +293,17 @@
 }
 
 func TestCcObjectLinkerScript(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object setting linker_script",
-		blueprint: `cc_object {
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object setting linker_script",
+		Blueprint: `cc_object {
     name: "foo",
     srcs: ["base.cpp"],
     linker_script: "bunny.lds",
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts":         `["-fno-addrsig"]`,
 				"linker_script": `"bunny.lds"`,
 				"srcs":          `["base.cpp"]`,
@@ -313,9 +313,9 @@
 }
 
 func TestCcObjectDepsAndLinkerScriptSelects(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object setting deps and linker_script across archs",
-		blueprint: `cc_object {
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object setting deps and linker_script across archs",
+		Blueprint: `cc_object {
     name: "foo",
     srcs: ["base.cpp"],
     arch: {
@@ -359,8 +359,8 @@
     bazel_module: { bp2build_available: false },
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `["-fno-addrsig"]`,
 				"deps": `select({
         "//build/bazel/platforms/arch:arm": [":arm_obj"],
@@ -381,9 +381,9 @@
 }
 
 func TestCcObjectSelectOnLinuxAndBionicArchs(t *testing.T) {
-	runCcObjectTestCase(t, bp2buildTestCase{
-		description: "cc_object setting srcs based on linux and bionic archs",
-		blueprint: `cc_object {
+	runCcObjectTestCase(t, Bp2buildTestCase{
+		Description: "cc_object setting srcs based on linux and bionic archs",
+		Blueprint: `cc_object {
     name: "foo",
     srcs: ["base.cpp"],
     target: {
@@ -400,8 +400,8 @@
     include_build_directory: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("cc_object", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `["-fno-addrsig"]`,
 				"srcs": `["base.cpp"] + select({
         "//build/bazel/platforms/os_arch:android_arm64": [
diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
index 3cf8969..32c3f4d 100644
--- a/bp2build/cc_prebuilt_library_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_conversion_test.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
@@ -22,24 +22,24 @@
 
 func TestPrebuiltLibraryStaticAndSharedSimple(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library static and shared simple",
-			moduleTypeUnderTest:        "cc_prebuilt_library",
-			moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library static and shared simple",
+			ModuleTypeUnderTest:        "cc_prebuilt_library",
+			ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library {
 	name: "libtest",
 	srcs: ["libf.so"],
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library": `"libf.so"`,
 				}),
-				makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+				makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libf.so"`,
 				}),
 			},
@@ -48,15 +48,15 @@
 
 func TestPrebuiltLibraryWithArchVariance(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library with arch variance",
-			moduleTypeUnderTest:        "cc_prebuilt_library",
-			moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library with arch variance",
+			ModuleTypeUnderTest:        "cc_prebuilt_library",
+			ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library {
 	name: "libtest",
 	arch: {
@@ -65,15 +65,15 @@
 	},
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
         "//conditions:default": None,
     })`,
 				}),
-				makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+				makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
@@ -86,16 +86,16 @@
 
 func TestPrebuiltLibraryAdditionalAttrs(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library additional attributes",
-			moduleTypeUnderTest:        "cc_prebuilt_library",
-			moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library additional attributes",
+			ModuleTypeUnderTest:        "cc_prebuilt_library",
+			ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so":    "",
 				"testdir/1/": "",
 				"testdir/2/": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library {
 	name: "libtest",
 	srcs: ["libf.so"],
@@ -103,14 +103,14 @@
 	export_system_include_dirs: ["testdir/2/"],
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library":         `"libf.so"`,
 					"export_includes":        `["testdir/1/"]`,
 					"export_system_includes": `["testdir/2/"]`,
 				}),
 				// TODO(b/229374533): When fixed, update this test
-				makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+				makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libf.so"`,
 				}),
 			},
@@ -119,15 +119,15 @@
 
 func TestPrebuiltLibrarySharedStanzaFails(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library with shared stanza fails because multiple sources",
-			moduleTypeUnderTest:        "cc_prebuilt_library",
-			moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library with shared stanza fails because multiple sources",
+			ModuleTypeUnderTest:        "cc_prebuilt_library",
+			ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library {
 	name: "libtest",
 	srcs: ["libf.so"],
@@ -136,21 +136,21 @@
 	},
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedErr: fmt.Errorf("Expected at most one source file"),
+			ExpectedErr: fmt.Errorf("Expected at most one source file"),
 		})
 }
 
 func TestPrebuiltLibraryStaticStanzaFails(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library with static stanza fails because multiple sources",
-			moduleTypeUnderTest:        "cc_prebuilt_library",
-			moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library with static stanza fails because multiple sources",
+			ModuleTypeUnderTest:        "cc_prebuilt_library",
+			ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library {
 	name: "libtest",
 	srcs: ["libf.so"],
@@ -159,21 +159,21 @@
 	},
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedErr: fmt.Errorf("Expected at most one source file"),
+			ExpectedErr: fmt.Errorf("Expected at most one source file"),
 		})
 }
 
 func TestPrebuiltLibrarySharedAndStaticStanzas(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library with both shared and static stanzas",
-			moduleTypeUnderTest:        "cc_prebuilt_library",
-			moduleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library with both shared and static stanzas",
+			ModuleTypeUnderTest:        "cc_prebuilt_library",
+			ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library {
 	name: "libtest",
 	static: {
@@ -184,11 +184,11 @@
 	},
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
 					"static_library": `"libf.so"`,
 				}),
-				makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+				makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libg.so"`,
 				}),
 			},
diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go
index 57905e5..bcf0ce2 100644
--- a/bp2build/cc_prebuilt_library_shared_test.go
+++ b/bp2build/cc_prebuilt_library_shared_test.go
@@ -9,21 +9,21 @@
 
 func TestSharedPrebuiltLibrary(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library shared simple",
-			moduleTypeUnderTest:        "cc_prebuilt_library_shared",
-			moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library shared simple",
+			ModuleTypeUnderTest:        "cc_prebuilt_library_shared",
+			ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library_shared {
 	name: "libtest",
 	srcs: ["libf.so"],
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `"libf.so"`,
 				}),
 			},
@@ -32,15 +32,15 @@
 
 func TestSharedPrebuiltLibraryWithArchVariance(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library shared with arch variance",
-			moduleTypeUnderTest:        "cc_prebuilt_library_shared",
-			moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library shared with arch variance",
+			ModuleTypeUnderTest:        "cc_prebuilt_library_shared",
+			ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library_shared {
 	name: "libtest",
 	arch: {
@@ -49,8 +49,8 @@
 	},
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_shared", "libtest", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_shared", "libtest", AttrNameToString{
 					"shared_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
@@ -63,15 +63,15 @@
 
 func TestSharedPrebuiltLibrarySharedStanzaFails(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library shared with shared stanza fails because multiple sources",
-			moduleTypeUnderTest:        "cc_prebuilt_library_shared",
-			moduleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library shared with shared stanza fails because multiple sources",
+			ModuleTypeUnderTest:        "cc_prebuilt_library_shared",
+			ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library_shared {
 	name: "libtest",
 	srcs: ["libf.so"],
@@ -80,6 +80,6 @@
 	},
 	bazel_module: { bp2build_available: true},
 }`,
-			expectedErr: fmt.Errorf("Expected at most one source file"),
+			ExpectedErr: fmt.Errorf("Expected at most one source file"),
 		})
 }
diff --git a/bp2build/cc_prebuilt_library_static_test.go b/bp2build/cc_prebuilt_library_static_test.go
index 59839c8..489a53d 100644
--- a/bp2build/cc_prebuilt_library_static_test.go
+++ b/bp2build/cc_prebuilt_library_static_test.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
@@ -22,21 +22,21 @@
 
 func TestStaticPrebuiltLibrary(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library static simple",
-			moduleTypeUnderTest:        "cc_prebuilt_library_static",
-			moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library static simple",
+			ModuleTypeUnderTest:        "cc_prebuilt_library_static",
+			ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library_static {
 	name: "libtest",
 	srcs: ["libf.so"],
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_static", "libtest", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_static", "libtest", AttrNameToString{
 					"static_library": `"libf.so"`,
 				}),
 			},
@@ -45,15 +45,15 @@
 
 func TestStaticPrebuiltLibraryWithArchVariance(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library static with arch variance",
-			moduleTypeUnderTest:        "cc_prebuilt_library_static",
-			moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library static with arch variance",
+			ModuleTypeUnderTest:        "cc_prebuilt_library_static",
+			ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library_static {
 	name: "libtest",
 	arch: {
@@ -62,8 +62,8 @@
 	},
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTargets: []string{
-				makeBazelTarget("prebuilt_library_static", "libtest", attrNameToString{
+			ExpectedBazelTargets: []string{
+				makeBazelTarget("prebuilt_library_static", "libtest", AttrNameToString{
 					"static_library": `select({
         "//build/bazel/platforms/arch:arm": "libg.so",
         "//build/bazel/platforms/arch:arm64": "libf.so",
@@ -76,15 +76,15 @@
 
 func TestStaticPrebuiltLibraryStaticStanzaFails(t *testing.T) {
 	runBp2BuildTestCaseSimple(t,
-		bp2buildTestCase{
-			description:                "prebuilt library with static stanza fails because multiple sources",
-			moduleTypeUnderTest:        "cc_prebuilt_library_static",
-			moduleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
-			filesystem: map[string]string{
+		Bp2buildTestCase{
+			Description:                "prebuilt library with static stanza fails because multiple sources",
+			ModuleTypeUnderTest:        "cc_prebuilt_library_static",
+			ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
+			Filesystem: map[string]string{
 				"libf.so": "",
 				"libg.so": "",
 			},
-			blueprint: `
+			Blueprint: `
 cc_prebuilt_library_static {
 	name: "libtest",
 	srcs: ["libf.so"],
@@ -93,16 +93,16 @@
 	},
 	bazel_module: { bp2build_available: true },
 }`,
-			expectedErr: fmt.Errorf("Expected at most one source file"),
+			ExpectedErr: fmt.Errorf("Expected at most one source file"),
 		})
 }
 
 func TestCcLibraryStaticConvertLex(t *testing.T) {
-	runCcLibrarySharedTestCase(t, bp2buildTestCase{
-		description:                "cc_library_static with lex files",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		filesystem: map[string]string{
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library_static with lex files",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Filesystem: map[string]string{
 			"foo.c":   "",
 			"bar.cc":  "",
 			"foo1.l":  "",
@@ -110,29 +110,29 @@
 			"foo2.l":  "",
 			"bar2.ll": "",
 		},
-		blueprint: `cc_library_static {
+		Blueprint: `cc_library_static {
 	name: "foo_lib",
 	srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
 	lex: { flags: ["--foo_flags"] },
 	include_build_directory: false,
 	bazel_module: { bp2build_available: true },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("genlex", "foo_lib_genlex_l", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
 				"srcs": `[
         "foo1.l",
         "foo2.l",
     ]`,
 				"lexopts": `["--foo_flags"]`,
 			}),
-			makeBazelTarget("genlex", "foo_lib_genlex_ll", attrNameToString{
+			makeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
 				"srcs": `[
         "bar1.ll",
         "bar2.ll",
     ]`,
 				"lexopts": `["--foo_flags"]`,
 			}),
-			makeBazelTarget("cc_library_static", "foo_lib", attrNameToString{
+			makeBazelTarget("cc_library_static", "foo_lib", AttrNameToString{
 				"srcs": `[
         "bar.cc",
         ":foo_lib_genlex_ll",
diff --git a/bp2build/cc_yasm_conversion_test.go b/bp2build/cc_yasm_conversion_test.go
new file mode 100644
index 0000000..2a71834
--- /dev/null
+++ b/bp2build/cc_yasm_conversion_test.go
@@ -0,0 +1,179 @@
+// 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 runYasmTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	RunBp2BuildTestCase(t, registerYasmModuleTypes, tc)
+}
+
+func registerYasmModuleTypes(ctx android.RegistrationContext) {
+	cc.RegisterCCBuildComponents(ctx)
+	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
+	ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
+	ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+}
+
+func TestYasmSimple(t *testing.T) {
+	runYasmTestCase(t, Bp2buildTestCase{
+		Description:                "Simple yasm test",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"main.cpp":   "",
+			"myfile.asm": "",
+		},
+		Blueprint: `
+cc_library {
+  name: "foo",
+  srcs: ["main.cpp", "myfile.asm"],
+}`,
+		ExpectedBazelTargets: append([]string{
+			makeBazelTarget("yasm", "foo_yasm", map[string]string{
+				"include_dirs": `["."]`,
+				"srcs":         `["myfile.asm"]`,
+			}),
+		}, makeCcLibraryTargets("foo", map[string]string{
+			"local_includes": `["."]`,
+			"srcs": `[
+        "main.cpp",
+        ":foo_yasm",
+    ]`,
+		})...),
+	})
+}
+
+func TestYasmWithIncludeDirs(t *testing.T) {
+	runYasmTestCase(t, Bp2buildTestCase{
+		Description:                "Simple yasm test",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"main.cpp":                    "",
+			"myfile.asm":                  "",
+			"include1/foo/myinclude.inc":  "",
+			"include2/foo/myinclude2.inc": "",
+		},
+		Blueprint: `
+cc_library {
+  name: "foo",
+  local_include_dirs: ["include1/foo"],
+  export_include_dirs: ["include2/foo"],
+  srcs: ["main.cpp", "myfile.asm"],
+}`,
+		ExpectedBazelTargets: append([]string{
+			makeBazelTarget("yasm", "foo_yasm", map[string]string{
+				"include_dirs": `[
+        "include1/foo",
+        ".",
+        "include2/foo",
+    ]`,
+				"srcs": `["myfile.asm"]`,
+			}),
+		}, makeCcLibraryTargets("foo", map[string]string{
+			"local_includes": `[
+        "include1/foo",
+        ".",
+    ]`,
+			"export_includes": `["include2/foo"]`,
+			"srcs": `[
+        "main.cpp",
+        ":foo_yasm",
+    ]`,
+		})...),
+	})
+}
+
+func TestYasmConditionalBasedOnArch(t *testing.T) {
+	runYasmTestCase(t, Bp2buildTestCase{
+		Description:                "Simple yasm test",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"main.cpp":   "",
+			"myfile.asm": "",
+		},
+		Blueprint: `
+cc_library {
+  name: "foo",
+  srcs: ["main.cpp"],
+  arch: {
+    x86: {
+      srcs: ["myfile.asm"],
+    },
+  },
+}`,
+		ExpectedBazelTargets: append([]string{
+			makeBazelTarget("yasm", "foo_yasm", map[string]string{
+				"include_dirs": `["."]`,
+				"srcs": `select({
+        "//build/bazel/platforms/arch:x86": ["myfile.asm"],
+        "//conditions:default": [],
+    })`,
+			}),
+		}, makeCcLibraryTargets("foo", map[string]string{
+			"local_includes": `["."]`,
+			"srcs": `["main.cpp"] + select({
+        "//build/bazel/platforms/arch:x86": [":foo_yasm"],
+        "//conditions:default": [],
+    })`,
+		})...),
+	})
+}
+
+func TestYasmPartiallyConditional(t *testing.T) {
+	runYasmTestCase(t, Bp2buildTestCase{
+		Description:                "Simple yasm test",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Filesystem: map[string]string{
+			"main.cpp":         "",
+			"myfile.asm":       "",
+			"mysecondfile.asm": "",
+		},
+		Blueprint: `
+cc_library {
+  name: "foo",
+  srcs: ["main.cpp", "myfile.asm"],
+  arch: {
+    x86: {
+      srcs: ["mysecondfile.asm"],
+    },
+  },
+}`,
+		ExpectedBazelTargets: append([]string{
+			makeBazelTarget("yasm", "foo_yasm", map[string]string{
+				"include_dirs": `["."]`,
+				"srcs": `["myfile.asm"] + select({
+        "//build/bazel/platforms/arch:x86": ["mysecondfile.asm"],
+        "//conditions:default": [],
+    })`,
+			}),
+		}, makeCcLibraryTargets("foo", map[string]string{
+			"local_includes": `["."]`,
+			"srcs": `[
+        "main.cpp",
+        ":foo_yasm",
+    ]`,
+		})...),
+	})
+}
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index d37a523..9398d12 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -13,6 +13,30 @@
 
 type selects map[string]reflect.Value
 
+func getStringValue(str bazel.StringAttribute) (reflect.Value, []selects) {
+	value := reflect.ValueOf(str.Value)
+
+	if !str.HasConfigurableValues() {
+		return value, []selects{}
+	}
+
+	ret := selects{}
+	for _, axis := range str.SortedConfigurationAxes() {
+		configToStrs := str.ConfigurableValues[axis]
+		for config, strs := range configToStrs {
+			selectKey := axis.SelectKey(config)
+			ret[selectKey] = reflect.ValueOf(strs)
+		}
+	}
+	// if there is a select, use the base value as the conditions default value
+	if len(ret) > 0 {
+		ret[bazel.ConditionsDefaultSelectKey] = value
+		value = reflect.Zero(value.Type())
+	}
+
+	return value, []selects{ret}
+}
+
 func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
 	value := reflect.ValueOf(list.Value)
 	if !list.HasConfigurableValues() {
@@ -137,6 +161,12 @@
 	// If true, print the default attribute value, even if the attribute is zero.
 	shouldPrintDefault := false
 	switch list := v.(type) {
+	case bazel.StringAttribute:
+		if err := list.Collapse(); err != nil {
+			return "", err
+		}
+		value, configurableAttrs = getStringValue(list)
+		defaultSelectValue = &bazelNone
 	case bazel.StringListAttribute:
 		value, configurableAttrs = getStringListValues(list)
 		defaultSelectValue = &emptyBazelList
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 8cf9bea..d98b6a3 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -2,7 +2,6 @@
 
 import (
 	"encoding/json"
-	"fmt"
 	"reflect"
 	"strings"
 
@@ -80,21 +79,14 @@
 		files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
 	}
 
-	files = append(files, createBuildFiles(cfg, buildToTargets, mode)...)
+	files = append(files, createBuildFiles(buildToTargets, mode)...)
 
 	return files
 }
 
-func createBuildFiles(cfg android.Config, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
+func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
 	files := make([]BazelFile, 0, len(buildToTargets))
-	warnNotWriting := cfg.IsEnvTrue("BP2BUILD_VERBOSE")
 	for _, dir := range android.SortedStringKeys(buildToTargets) {
-		if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) {
-			if warnNotWriting {
-				fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
-			}
-			continue
-		}
 		targets := buildToTargets[dir]
 		targets.sort()
 
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index b43cf53..de09a17 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -21,38 +21,103 @@
 	"testing"
 )
 
-func runFilegroupTestCase(t *testing.T, tc bp2buildTestCase) {
+func runFilegroupTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "filegroup"
-	(&tc).moduleTypeUnderTestFactory = android.FileGroupFactory
-	runBp2BuildTestCase(t, registerFilegroupModuleTypes, tc)
+	(&tc).ModuleTypeUnderTest = "filegroup"
+	(&tc).ModuleTypeUnderTestFactory = android.FileGroupFactory
+	RunBp2BuildTestCase(t, registerFilegroupModuleTypes, tc)
 }
 
 func registerFilegroupModuleTypes(ctx android.RegistrationContext) {}
 
 func TestFilegroupSameNameAsFile_OneFile(t *testing.T) {
-	runFilegroupTestCase(t, bp2buildTestCase{
-		description: "filegroup - same name as file, with one file",
-		filesystem:  map[string]string{},
-		blueprint: `
+	runFilegroupTestCase(t, Bp2buildTestCase{
+		Description: "filegroup - same name as file, with one file",
+		Filesystem:  map[string]string{},
+		Blueprint: `
 filegroup {
     name: "foo",
     srcs: ["foo"],
 }
 `,
-		expectedBazelTargets: []string{}})
+		ExpectedBazelTargets: []string{}})
 }
 
 func TestFilegroupSameNameAsFile_MultipleFiles(t *testing.T) {
-	runFilegroupTestCase(t, bp2buildTestCase{
-		description: "filegroup - same name as file, with multiple files",
-		filesystem:  map[string]string{},
-		blueprint: `
+	runFilegroupTestCase(t, Bp2buildTestCase{
+		Description: "filegroup - same name as file, with multiple files",
+		Filesystem:  map[string]string{},
+		Blueprint: `
 filegroup {
 	name: "foo",
 	srcs: ["foo", "bar"],
 }
 `,
-		expectedErr: fmt.Errorf("filegroup 'foo' cannot contain a file with the same name"),
+		ExpectedErr: fmt.Errorf("filegroup 'foo' cannot contain a file with the same name"),
 	})
 }
+
+func TestFilegroupWithAidlSrcs(t *testing.T) {
+	testcases := []struct {
+		name               string
+		bp                 string
+		expectedBazelAttrs AttrNameToString
+	}{
+		{
+			name: "filegroup with only aidl srcs",
+			bp: `
+	filegroup {
+		name: "foo",
+		srcs: ["aidl/foo.aidl"],
+		path: "aidl",
+	}`,
+			expectedBazelAttrs: AttrNameToString{
+				"srcs":                `["aidl/foo.aidl"]`,
+				"strip_import_prefix": `"aidl"`,
+			},
+		},
+		{
+			name: "filegroup without path",
+			bp: `
+	filegroup {
+		name: "foo",
+		srcs: ["aidl/foo.aidl"],
+	}`,
+			expectedBazelAttrs: AttrNameToString{
+				"srcs": `["aidl/foo.aidl"]`,
+			},
+		},
+	}
+
+	for _, test := range testcases {
+		expectedBazelTargets := []string{
+			MakeBazelTargetNoRestrictions("aidl_library", "foo", test.expectedBazelAttrs),
+		}
+		runFilegroupTestCase(t, Bp2buildTestCase{
+			Description:          test.name,
+			Blueprint:            test.bp,
+			ExpectedBazelTargets: expectedBazelTargets,
+		})
+	}
+}
+
+func TestFilegroupWithAidlAndNonAidlSrcs(t *testing.T) {
+	runFilegroupTestCase(t, Bp2buildTestCase{
+		Description: "filegroup with aidl and non-aidl srcs",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+filegroup {
+    name: "foo",
+    srcs: [
+		"aidl/foo.aidl",
+		"buf.proto",
+	],
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
+				"srcs": `[
+        "aidl/foo.aidl",
+        "buf.proto",
+    ]`}),
+		}})
+}
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 4504892..a8bfecd 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -27,11 +27,11 @@
 	ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() })
 }
 
-func runGenruleTestCase(t *testing.T, tc bp2buildTestCase) {
+func runGenruleTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "genrule"
-	(&tc).moduleTypeUnderTestFactory = genrule.GenRuleFactory
-	runBp2BuildTestCase(t, registerGenruleModuleTypes, tc)
+	(&tc).ModuleTypeUnderTest = "genrule"
+	(&tc).ModuleTypeUnderTestFactory = genrule.GenRuleFactory
+	RunBp2BuildTestCase(t, registerGenruleModuleTypes, tc)
 }
 
 func otherGenruleBp(genruleTarget string) map[string]string {
@@ -101,7 +101,7 @@
 }`
 
 	for _, tc := range testCases {
-		moduleAttrs := attrNameToString{
+		moduleAttrs := AttrNameToString{
 			"cmd":   fmt.Sprintf(`"$(location :foo.tool) --genDir=%s arg $(SRCS) $(OUTS)"`, tc.genDir),
 			"outs":  `["foo.out"]`,
 			"srcs":  `["foo.in"]`,
@@ -113,12 +113,12 @@
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        tc.moduleType,
-					moduleTypeUnderTestFactory: tc.factory,
-					blueprint:                  fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
-					expectedBazelTargets:       expectedBazelTargets,
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
+					ExpectedBazelTargets:       expectedBazelTargets,
 				})
 		})
 	}
@@ -169,13 +169,13 @@
 }`
 
 	for _, tc := range testCases {
-		fooAttrs := attrNameToString{
+		fooAttrs := AttrNameToString{
 			"cmd":   `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`,
 			"outs":  `["foo.out"]`,
 			"srcs":  `["foo.in"]`,
 			"tools": `[":foo.tools"]`,
 		}
-		fooToolsAttrs := attrNameToString{
+		fooToolsAttrs := AttrNameToString{
 			"cmd": `"cp $(SRCS) $(OUTS)"`,
 			"outs": `[
         "foo_tool.out",
@@ -190,12 +190,12 @@
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        tc.moduleType,
-					moduleTypeUnderTestFactory: tc.factory,
-					blueprint:                  fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
-					expectedBazelTargets:       expectedBazelTargets,
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
+					ExpectedBazelTargets:       expectedBazelTargets,
 				})
 		})
 	}
@@ -238,7 +238,7 @@
 }`
 
 	for _, tc := range testCases {
-		moduleAttrs := attrNameToString{
+		moduleAttrs := AttrNameToString{
 			"cmd":   `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
 			"outs":  `["foo.out"]`,
 			"srcs":  `["foo.in"]`,
@@ -250,13 +250,13 @@
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        tc.moduleType,
-					moduleTypeUnderTestFactory: tc.factory,
-					blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					expectedBazelTargets:       expectedBazelTargets,
-					filesystem:                 otherGenruleBp(tc.moduleType),
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
+					ExpectedBazelTargets:       expectedBazelTargets,
+					Filesystem:                 otherGenruleBp(tc.moduleType),
 				})
 		})
 	}
@@ -299,7 +299,7 @@
 }`
 
 	for _, tc := range testCases {
-		moduleAttrs := attrNameToString{
+		moduleAttrs := AttrNameToString{
 			"cmd":   `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`,
 			"outs":  `["foo.out"]`,
 			"srcs":  `["//other:other.tool"]`,
@@ -311,13 +311,13 @@
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        tc.moduleType,
-					moduleTypeUnderTestFactory: tc.factory,
-					blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					expectedBazelTargets:       expectedBazelTargets,
-					filesystem:                 otherGenruleBp(tc.moduleType),
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
+					ExpectedBazelTargets:       expectedBazelTargets,
+					Filesystem:                 otherGenruleBp(tc.moduleType),
 				})
 		})
 	}
@@ -360,7 +360,7 @@
 }`
 
 	for _, tc := range testCases {
-		moduleAttrs := attrNameToString{
+		moduleAttrs := AttrNameToString{
 			"cmd":  `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`,
 			"outs": `["foo.out"]`,
 			"srcs": `["foo.in"]`,
@@ -375,13 +375,13 @@
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        tc.moduleType,
-					moduleTypeUnderTestFactory: tc.factory,
-					blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					expectedBazelTargets:       expectedBazelTargets,
-					filesystem:                 otherGenruleBp(tc.moduleType),
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
+					ExpectedBazelTargets:       expectedBazelTargets,
+					Filesystem:                 otherGenruleBp(tc.moduleType),
 				})
 		})
 	}
@@ -424,7 +424,7 @@
 }`
 
 	for _, tc := range testCases {
-		moduleAttrs := attrNameToString{
+		moduleAttrs := AttrNameToString{
 			"cmd":  `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
 			"outs": `["foo.out"]`,
 			"srcs": `["foo.in"]`,
@@ -439,13 +439,13 @@
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        tc.moduleType,
-					moduleTypeUnderTestFactory: tc.factory,
-					blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					expectedBazelTargets:       expectedBazelTargets,
-					filesystem:                 otherGenruleBp(tc.moduleType),
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
+					ExpectedBazelTargets:       expectedBazelTargets,
+					Filesystem:                 otherGenruleBp(tc.moduleType),
 				})
 		})
 	}
@@ -487,7 +487,7 @@
 }`
 
 	for _, tc := range testCases {
-		moduleAttrs := attrNameToString{
+		moduleAttrs := AttrNameToString{
 			"cmd":  `"cp $(SRCS) $(OUTS)"`,
 			"outs": `["foo.out"]`,
 			"srcs": `["foo.in"]`,
@@ -498,22 +498,22 @@
 		}
 
 		t.Run(tc.moduleType, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        tc.moduleType,
-					moduleTypeUnderTestFactory: tc.factory,
-					blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					expectedBazelTargets:       expectedBazelTargets,
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
+					ExpectedBazelTargets:       expectedBazelTargets,
 				})
 		})
 	}
 }
 
 func TestGenruleBp2BuildInlinesDefaults(t *testing.T) {
-	testCases := []bp2buildTestCase{
+	testCases := []Bp2buildTestCase{
 		{
-			description: "genrule applies properties from a genrule_defaults dependency if not specified",
-			blueprint: `genrule_defaults {
+			Description: "genrule applies properties from a genrule_defaults dependency if not specified",
+			Blueprint: `genrule_defaults {
     name: "gen_defaults",
     cmd: "do-something $(in) $(out)",
 }
@@ -525,8 +525,8 @@
     bazel_module: { bp2build_available: true },
 }
 `,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
 					"cmd":  `"do-something $(SRCS) $(OUTS)"`,
 					"outs": `["out"]`,
 					"srcs": `["in1"]`,
@@ -534,8 +534,8 @@
 			},
 		},
 		{
-			description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
-			blueprint: `genrule_defaults {
+			Description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
+			Blueprint: `genrule_defaults {
     name: "gen_defaults",
     out: ["out-from-defaults"],
     srcs: ["in-from-defaults"],
@@ -550,8 +550,8 @@
     bazel_module: { bp2build_available: true },
 }
 `,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
 					"cmd": `"do-something $(SRCS) $(OUTS)"`,
 					"outs": `[
         "out-from-defaults",
@@ -565,8 +565,8 @@
 			},
 		},
 		{
-			description: "genrule applies properties from list of genrule_defaults",
-			blueprint: `genrule_defaults {
+			Description: "genrule applies properties from list of genrule_defaults",
+			Blueprint: `genrule_defaults {
     name: "gen_defaults1",
     cmd: "cp $(in) $(out)",
 }
@@ -583,8 +583,8 @@
     bazel_module: { bp2build_available: true },
 }
 `,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
 					"cmd":  `"cp $(SRCS) $(OUTS)"`,
 					"outs": `["out"]`,
 					"srcs": `["in1"]`,
@@ -592,8 +592,8 @@
 			},
 		},
 		{
-			description: "genrule applies properties from genrule_defaults transitively",
-			blueprint: `genrule_defaults {
+			Description: "genrule applies properties from genrule_defaults transitively",
+			Blueprint: `genrule_defaults {
     name: "gen_defaults1",
     defaults: ["gen_defaults2"],
     cmd: "cmd1 $(in) $(out)", // overrides gen_defaults2's cmd property value.
@@ -620,8 +620,8 @@
     bazel_module: { bp2build_available: true },
 }
 `,
-			expectedBazelTargets: []string{
-				makeBazelTargetNoRestrictions("genrule", "gen", attrNameToString{
+			ExpectedBazelTargets: []string{
+				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
 					"cmd": `"cmd1 $(SRCS) $(OUTS)"`,
 					"outs": `[
         "out-from-3",
@@ -638,7 +638,7 @@
 	}
 
 	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
+		t.Run(testCase.Description, func(t *testing.T) {
 			runGenruleTestCase(t, testCase)
 		})
 	}
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
index 7682663..4845973 100644
--- a/bp2build/gensrcs_conversion_test.go
+++ b/bp2build/gensrcs_conversion_test.go
@@ -24,7 +24,7 @@
 	testcases := []struct {
 		name               string
 		bp                 string
-		expectedBazelAttrs attrNameToString
+		expectedBazelAttrs AttrNameToString
 	}{
 		{
 			name: "gensrcs with common usage of properties",
@@ -37,7 +37,7 @@
                 output_extension: "out",
                 bazel_module: { bp2build_available: true },
 			}`,
-			expectedBazelAttrs: attrNameToString{
+			expectedBazelAttrs: AttrNameToString{
 				"srcs": `[
         "test/input.txt",
         ":external_files__BP2BUILD__MISSING__DEP",
@@ -56,7 +56,7 @@
                 cmd: "cat $(in) > $(out)",
                 bazel_module: { bp2build_available: true },
 			}`,
-			expectedBazelAttrs: attrNameToString{
+			expectedBazelAttrs: AttrNameToString{
 				"srcs": `["input.txt"]`,
 				"cmd":  `"cat $(SRC) > $(OUT)"`,
 			},
@@ -65,15 +65,15 @@
 
 	for _, test := range testcases {
 		expectedBazelTargets := []string{
-			makeBazelTargetNoRestrictions("gensrcs", "foo", test.expectedBazelAttrs),
+			MakeBazelTargetNoRestrictions("gensrcs", "foo", test.expectedBazelAttrs),
 		}
 		t.Run(test.name, func(t *testing.T) {
-			runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				bp2buildTestCase{
-					moduleTypeUnderTest:        "gensrcs",
-					moduleTypeUnderTestFactory: genrule.GenSrcsFactory,
-					blueprint:                  test.bp,
-					expectedBazelTargets:       expectedBazelTargets,
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        "gensrcs",
+					ModuleTypeUnderTestFactory: genrule.GenSrcsFactory,
+					Blueprint:                  test.bp,
+					ExpectedBazelTargets:       expectedBazelTargets,
 				})
 		})
 	}
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index d7a76a8..50ea542 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -22,11 +22,11 @@
 	"android/soong/java"
 )
 
-func runJavaBinaryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaBinaryHostTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "java_binary_host"
-	(&tc).moduleTypeUnderTestFactory = java.BinaryHostFactory
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+	(&tc).ModuleTypeUnderTest = "java_binary_host"
+	(&tc).ModuleTypeUnderTestFactory = java.BinaryHostFactory
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory)
 		ctx.RegisterModuleType("java_library", java.LibraryFactory)
 	}, tc)
@@ -41,10 +41,10 @@
 }
 
 func TestJavaBinaryHost(t *testing.T) {
-	runJavaBinaryHostTestCase(t, bp2buildTestCase{
-		description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
-		filesystem:  fs,
-		blueprint: `java_binary_host {
+	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
+		Filesystem:  fs,
+		Blueprint: `java_binary_host {
     name: "java-binary-host-1",
     srcs: ["a.java", "b.java"],
     exclude_srcs: ["b.java"],
@@ -54,8 +54,8 @@
     bazel_module: { bp2build_available: true },
     java_version: "8",
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_binary", "java-binary-host-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
 				"srcs":       `["a.java"]`,
 				"main_class": `"com.android.test.MainClass"`,
 				"deps":       `["//other:jni-lib-1"]`,
@@ -74,10 +74,10 @@
 }
 
 func TestJavaBinaryHostRuntimeDeps(t *testing.T) {
-	runJavaBinaryHostTestCase(t, bp2buildTestCase{
-		description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
-		filesystem:  fs,
-		blueprint: `java_binary_host {
+	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
+		Filesystem:  fs,
+		Blueprint: `java_binary_host {
     name: "java-binary-host-1",
     static_libs: ["java-dep-1"],
     manifest: "test.mf",
@@ -90,8 +90,8 @@
     bazel_module: { bp2build_available: false },
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_binary", "java-binary-host-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
 				"main_class":   `"com.android.test.MainClass"`,
 				"runtime_deps": `[":java-dep-1"]`,
 				"target_compatible_with": `select({
diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go
index 0b3191c..707ecce 100644
--- a/bp2build/java_import_conversion_test.go
+++ b/bp2build/java_import_conversion_test.go
@@ -21,45 +21,45 @@
 	"testing"
 )
 
-func runJavaImportTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaImportTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerJavaImportModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerJavaImportModuleTypes, tc)
 }
 
 func registerJavaImportModuleTypes(ctx android.RegistrationContext) {
 }
 
 func TestJavaImportMinimal(t *testing.T) {
-	runJavaImportTestCase(t, bp2buildTestCase{
-		description:                "Java import - simple example",
-		moduleTypeUnderTest:        "java_import",
-		moduleTypeUnderTestFactory: java.ImportFactory,
-		filesystem: map[string]string{
+	runJavaImportTestCase(t, Bp2buildTestCase{
+		Description:                "Java import - simple example",
+		ModuleTypeUnderTest:        "java_import",
+		ModuleTypeUnderTestFactory: java.ImportFactory,
+		Filesystem: map[string]string{
 			"import.jar": "",
 		},
-		blueprint: `
+		Blueprint: `
 java_import {
         name: "example_import",
         jars: ["import.jar"],
         bazel_module: { bp2build_available: true },
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_import", "example_import", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_import", "example_import", AttrNameToString{
 				"jars": `["import.jar"]`,
 			}),
 		}})
 }
 
 func TestJavaImportArchVariant(t *testing.T) {
-	runJavaImportTestCase(t, bp2buildTestCase{
-		description:                "Java import - simple example",
-		moduleTypeUnderTest:        "java_import",
-		moduleTypeUnderTestFactory: java.ImportFactory,
-		filesystem: map[string]string{
+	runJavaImportTestCase(t, Bp2buildTestCase{
+		Description:                "Java import - simple example",
+		ModuleTypeUnderTest:        "java_import",
+		ModuleTypeUnderTestFactory: java.ImportFactory,
+		Filesystem: map[string]string{
 			"import.jar": "",
 		},
-		blueprint: `
+		Blueprint: `
 java_import {
         name: "example_import",
 		target: {
@@ -73,8 +73,8 @@
         bazel_module: { bp2build_available: true },
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_import", "example_import", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_import", "example_import", AttrNameToString{
 				"jars": `select({
         "//build/bazel/platforms/os:android": ["android.jar"],
         "//build/bazel/platforms/os:linux": ["linux.jar"],
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index e4d9cbc..b57cf35 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -22,22 +22,22 @@
 	"android/soong/java"
 )
 
-func runJavaLibraryTestCaseWithRegistrationCtxFunc(t *testing.T, tc bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
+func runJavaLibraryTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "java_library"
-	(&tc).moduleTypeUnderTestFactory = java.LibraryFactory
-	runBp2BuildTestCase(t, registrationCtxFunc, tc)
+	(&tc).ModuleTypeUnderTest = "java_library"
+	(&tc).ModuleTypeUnderTestFactory = java.LibraryFactory
+	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
 }
 
-func runJavaLibraryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
 	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {})
 }
 
 func TestJavaLibrary(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		description: "java_library with srcs, exclude_srcs and libs",
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Description: "java_library with srcs, exclude_srcs and libs",
+		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java", "b.java"],
     exclude_srcs: ["b.java"],
@@ -50,12 +50,12 @@
     srcs: ["b.java"],
     bazel_module: { bp2build_available: true },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"srcs": `["a.java"]`,
 				"deps": `[":java-lib-2"]`,
 			}),
-			makeBazelTarget("java_library", "java-lib-2", attrNameToString{
+			makeBazelTarget("java_library", "java-lib-2", AttrNameToString{
 				"srcs": `["b.java"]`,
 			}),
 		},
@@ -63,8 +63,8 @@
 }
 
 func TestJavaLibraryConvertsStaticLibsToDepsAndExports(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
     libs: ["java-lib-2"],
@@ -83,8 +83,8 @@
     srcs: ["c.java"],
     bazel_module: { bp2build_available: false },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"srcs": `["a.java"]`,
 				"deps": `[
         ":java-lib-2",
@@ -97,8 +97,8 @@
 }
 
 func TestJavaLibraryConvertsStaticLibsToExportsIfNoSrcs(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
     name: "java-lib-1",
     static_libs: ["java-lib-2"],
     bazel_module: { bp2build_available: true },
@@ -109,8 +109,8 @@
     srcs: ["a.java"],
     bazel_module: { bp2build_available: false },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"exports": `[":java-lib-2"]`,
 			}),
 		},
@@ -118,9 +118,9 @@
 }
 
 func TestJavaLibraryFailsToConvertLibsWithNoSrcs(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		expectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		ExpectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
+		Blueprint: `java_library {
     name: "java-lib-1",
     libs: ["java-lib-2"],
     bazel_module: { bp2build_available: true },
@@ -131,13 +131,13 @@
     srcs: ["a.java"],
     bazel_module: { bp2build_available: false },
 }`,
-		expectedBazelTargets: []string{},
+		ExpectedBazelTargets: []string{},
 	})
 }
 
 func TestJavaLibraryPlugins(t *testing.T) {
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, bp2buildTestCase{
-		blueprint: `java_library {
+	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+		Blueprint: `java_library {
     name: "java-lib-1",
     plugins: ["java-plugin-1"],
     bazel_module: { bp2build_available: true },
@@ -148,8 +148,8 @@
     srcs: ["a.java"],
     bazel_module: { bp2build_available: false },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"plugins": `[":java-plugin-1"]`,
 			}),
 		},
@@ -159,14 +159,14 @@
 }
 
 func TestJavaLibraryJavaVersion(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
     java_version: "11",
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"srcs":      `["a.java"]`,
 				"javacopts": `["-source 11 -target 11"]`,
 			}),
@@ -175,8 +175,8 @@
 }
 
 func TestJavaLibraryErrorproneJavacflagsEnabledManually(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
     javacflags: ["-Xsuper-fast"],
@@ -185,8 +185,8 @@
         javacflags: ["-Xep:SpeedLimit:OFF"],
     },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"javacopts": `[
         "-Xsuper-fast",
         "-Xep:SpeedLimit:OFF",
@@ -198,8 +198,8 @@
 }
 
 func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledByDefault(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
     javacflags: ["-Xsuper-fast"],
@@ -207,8 +207,8 @@
         javacflags: ["-Xep:SpeedLimit:OFF"],
     },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"javacopts": `["-Xsuper-fast"]`,
 				"srcs":      `["a.java"]`,
 			}),
@@ -217,8 +217,8 @@
 }
 
 func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledManually(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
     javacflags: ["-Xsuper-fast"],
@@ -227,8 +227,8 @@
         javacflags: ["-Xep:SpeedLimit:OFF"],
     },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"javacopts": `["-Xsuper-fast"]`,
 				"srcs":      `["a.java"]`,
 			}),
@@ -237,11 +237,11 @@
 }
 
 func TestJavaLibraryLogTags(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		description:                "Java library - logtags creates separate dependency",
-		moduleTypeUnderTest:        "java_library",
-		moduleTypeUnderTestFactory: java.LibraryFactory,
-		blueprint: `java_library {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "Java library - logtags creates separate dependency",
+		ModuleTypeUnderTest:        "java_library",
+		ModuleTypeUnderTestFactory: java.LibraryFactory,
+		Blueprint: `java_library {
         name: "example_lib",
         srcs: [
 			"a.java",
@@ -251,14 +251,14 @@
 		],
         bazel_module: { bp2build_available: true },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("event_log_tags", "example_lib_logtags", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("event_log_tags", "example_lib_logtags", AttrNameToString{
 				"srcs": `[
         "a.logtag",
         "b.logtag",
     ]`,
 			}),
-			makeBazelTarget("java_library", "example_lib", attrNameToString{
+			makeBazelTarget("java_library", "example_lib", AttrNameToString{
 				"srcs": `[
         "a.java",
         "b.java",
@@ -269,18 +269,18 @@
 }
 
 func TestJavaLibraryResources(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		filesystem: map[string]string{
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
 			"res/a.res":      "",
 			"res/b.res":      "",
 			"res/dir1/b.res": "",
 		},
-		blueprint: `java_library {
+		Blueprint: `java_library {
     name: "java-lib-1",
 	java_resources: ["res/a.res", "res/b.res"],
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"resources": `[
         "res/a.res",
         "res/b.res",
@@ -291,18 +291,18 @@
 }
 
 func TestJavaLibraryResourceDirs(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		filesystem: map[string]string{
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
 			"res/a.res":      "",
 			"res/b.res":      "",
 			"res/dir1/b.res": "",
 		},
-		blueprint: `java_library {
+		Blueprint: `java_library {
     name: "java-lib-1",
 	java_resource_dirs: ["res"],
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"resource_strip_prefix": `"res"`,
 				"resources": `[
         "res/a.res",
@@ -315,18 +315,18 @@
 }
 
 func TestJavaLibraryResourcesExcludeDir(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		filesystem: map[string]string{
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
 			"res/a.res":         "",
 			"res/exclude/b.res": "",
 		},
-		blueprint: `java_library {
+		Blueprint: `java_library {
     name: "java-lib-1",
 	java_resource_dirs: ["res"],
 	exclude_java_resource_dirs: ["res/exclude"],
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"resource_strip_prefix": `"res"`,
 				"resources":             `["res/a.res"]`,
 			}),
@@ -335,19 +335,19 @@
 }
 
 func TestJavaLibraryResourcesExcludeFile(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		filesystem: map[string]string{
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
 			"res/a.res":            "",
 			"res/dir1/b.res":       "",
 			"res/dir1/exclude.res": "",
 		},
-		blueprint: `java_library {
+		Blueprint: `java_library {
     name: "java-lib-1",
 	java_resource_dirs: ["res"],
 	exclude_java_resources: ["res/dir1/exclude.res"],
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"resource_strip_prefix": `"res"`,
 				"resources": `[
         "res/a.res",
@@ -359,16 +359,178 @@
 }
 
 func TestJavaLibraryResourcesFailsWithMultipleDirs(t *testing.T) {
-	runJavaLibraryTestCase(t, bp2buildTestCase{
-		filesystem: map[string]string{
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
 			"res/a.res":  "",
 			"res1/a.res": "",
 		},
-		blueprint: `java_library {
+		Blueprint: `java_library {
     name: "java-lib-1",
 	java_resource_dirs: ["res", "res1"],
 }`,
-		expectedErr:          fmt.Errorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)"),
-		expectedBazelTargets: []string{},
+		ExpectedErr:          fmt.Errorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)"),
+		ExpectedBazelTargets: []string{},
+	})
+}
+
+func TestJavaLibraryAidl(t *testing.T) {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Description:                "Java library - aidl creates separate dependency",
+		ModuleTypeUnderTest:        "java_library",
+		ModuleTypeUnderTestFactory: java.LibraryFactory,
+		Blueprint: `java_library {
+        name: "example_lib",
+        srcs: [
+			"a.java",
+			"b.java",
+			"a.aidl",
+			"b.aidl",
+		],
+        bazel_module: { bp2build_available: true },
+}`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{
+				"srcs": `[
+        "a.aidl",
+        "b.aidl",
+    ]`,
+			}),
+			makeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
+				"deps": `[":example_lib_aidl_library"]`,
+			}),
+			makeBazelTarget("java_library", "example_lib", AttrNameToString{
+				"deps":    `[":example_lib_java_aidl_library"]`,
+				"exports": `[":example_lib_java_aidl_library"]`,
+				"srcs": `[
+        "a.java",
+        "b.java",
+    ]`,
+			}),
+		}})
+}
+
+func TestJavaLibraryAidlSrcsNoFileGroup(t *testing.T) {
+	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+		Description:                "Java library - aidl filegroup is parsed",
+		ModuleTypeUnderTest:        "java_library",
+		ModuleTypeUnderTestFactory: java.LibraryFactory,
+		Blueprint: `
+java_library {
+        name: "example_lib",
+        srcs: [
+			"a.java",
+			"b.aidl",
+		],
+        bazel_module: { bp2build_available: true },
+}`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{
+				"srcs": `["b.aidl"]`,
+			}),
+			makeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
+				"deps": `[":example_lib_aidl_library"]`,
+			}),
+			makeBazelTarget("java_library", "example_lib", AttrNameToString{
+				"deps":    `[":example_lib_java_aidl_library"]`,
+				"exports": `[":example_lib_java_aidl_library"]`,
+				"srcs":    `["a.java"]`,
+			}),
+		},
+	}, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	})
+}
+
+func TestJavaLibraryAidlFilegroup(t *testing.T) {
+	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+		Description:                "Java library - aidl filegroup is parsed",
+		ModuleTypeUnderTest:        "java_library",
+		ModuleTypeUnderTestFactory: java.LibraryFactory,
+		Blueprint: `
+filegroup {
+	name: "random_other_files",
+	srcs: [
+		"a.java",
+		"b.java",
+	],
+}
+filegroup {
+	name: "aidl_files",
+	srcs: [
+		"a.aidl",
+		"b.aidl",
+	],
+}
+java_library {
+        name: "example_lib",
+        srcs: [
+			"a.java",
+			"b.java",
+			":aidl_files",
+			":random_other_files",
+		],
+        bazel_module: { bp2build_available: true },
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("aidl_library", "aidl_files", AttrNameToString{
+				"srcs": `[
+        "a.aidl",
+        "b.aidl",
+    ]`,
+			}),
+			makeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
+				"deps": `[":aidl_files"]`,
+			}),
+			makeBazelTarget("java_library", "example_lib", AttrNameToString{
+				"deps":    `[":example_lib_java_aidl_library"]`,
+				"exports": `[":example_lib_java_aidl_library"]`,
+				"srcs": `[
+        "a.java",
+        "b.java",
+        ":random_other_files",
+    ]`,
+			}),
+			MakeBazelTargetNoRestrictions("filegroup", "random_other_files", AttrNameToString{
+				"srcs": `[
+        "a.java",
+        "b.java",
+    ]`,
+			}),
+		},
+	}, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	})
+}
+
+func TestJavaLibraryAidlNonAdjacentAidlFilegroup(t *testing.T) {
+	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+		Description:                "java_library with non adjacent aidl filegroup",
+		ModuleTypeUnderTest:        "java_library",
+		ModuleTypeUnderTestFactory: java.LibraryFactory,
+		Filesystem: map[string]string{
+			"path/to/A/Android.bp": `
+filegroup {
+	name: "A_aidl",
+	srcs: ["aidl/A.aidl"],
+	path: "aidl",
+}`,
+		},
+		Blueprint: `
+java_library {
+	name: "foo",
+	srcs: [
+		":A_aidl",
+	],
+}`,
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_aidl_library", "foo_java_aidl_library", AttrNameToString{
+				"deps": `["//path/to/A:A_aidl"]`,
+			}),
+			makeBazelTarget("java_library", "foo", AttrNameToString{
+				"exports": `[":foo_java_aidl_library"]`,
+			}),
+		},
+	}, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	})
 }
diff --git a/bp2build/java_library_host_conversion_test.go b/bp2build/java_library_host_conversion_test.go
index 83cc551..1dcf163 100644
--- a/bp2build/java_library_host_conversion_test.go
+++ b/bp2build/java_library_host_conversion_test.go
@@ -21,17 +21,17 @@
 	"android/soong/java"
 )
 
-func runJavaLibraryHostTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaLibraryHostTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "java_library_host"
-	(&tc).moduleTypeUnderTestFactory = java.LibraryHostFactory
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+	(&tc).ModuleTypeUnderTest = "java_library_host"
+	(&tc).ModuleTypeUnderTestFactory = java.LibraryHostFactory
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
 }
 
 func TestJavaLibraryHost(t *testing.T) {
-	runJavaLibraryHostTestCase(t, bp2buildTestCase{
-		description: "java_library_host with srcs, exclude_srcs and libs",
-		blueprint: `java_library_host {
+	runJavaLibraryHostTestCase(t, Bp2buildTestCase{
+		Description: "java_library_host with srcs, exclude_srcs and libs",
+		Blueprint: `java_library_host {
     name: "java-lib-host-1",
     srcs: ["a.java", "b.java"],
     exclude_srcs: ["b.java"],
@@ -45,8 +45,8 @@
     bazel_module: { bp2build_available: true },
     java_version: "9",
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_library", "java-lib-host-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_library", "java-lib-host-1", AttrNameToString{
 				"srcs": `["a.java"]`,
 				"deps": `[":java-lib-host-2"]`,
 				"target_compatible_with": `select({
@@ -54,7 +54,7 @@
         "//conditions:default": [],
     })`,
 			}),
-			makeBazelTarget("java_library", "java-lib-host-2", attrNameToString{
+			makeBazelTarget("java_library", "java-lib-host-2", AttrNameToString{
 				"javacopts": `["-source 1.9 -target 1.9"]`,
 				"srcs":      `["c.java"]`,
 				"target_compatible_with": `select({
diff --git a/bp2build/java_plugin_conversion_test.go b/bp2build/java_plugin_conversion_test.go
index dc763e7..2d2e5ff 100644
--- a/bp2build/java_plugin_conversion_test.go
+++ b/bp2build/java_plugin_conversion_test.go
@@ -21,19 +21,19 @@
 	"android/soong/java"
 )
 
-func runJavaPluginTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaPluginTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "java_plugin"
-	(&tc).moduleTypeUnderTestFactory = java.PluginFactory
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+	(&tc).ModuleTypeUnderTest = "java_plugin"
+	(&tc).ModuleTypeUnderTestFactory = java.PluginFactory
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("java_library", java.LibraryFactory)
 	}, tc)
 }
 
 func TestJavaPlugin(t *testing.T) {
-	runJavaPluginTestCase(t, bp2buildTestCase{
-		description: "java_plugin with srcs, libs, static_libs",
-		blueprint: `java_plugin {
+	runJavaPluginTestCase(t, Bp2buildTestCase{
+		Description: "java_plugin with srcs, libs, static_libs",
+		Blueprint: `java_plugin {
     name: "java-plug-1",
     srcs: ["a.java", "b.java"],
     libs: ["java-lib-1"],
@@ -53,8 +53,8 @@
     srcs: ["c.java"],
     bazel_module: { bp2build_available: false },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_plugin", "java-plug-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
@@ -74,9 +74,9 @@
 }
 
 func TestJavaPluginNoSrcs(t *testing.T) {
-	runJavaPluginTestCase(t, bp2buildTestCase{
-		description: "java_plugin without srcs converts (static) libs to deps",
-		blueprint: `java_plugin {
+	runJavaPluginTestCase(t, Bp2buildTestCase{
+		Description: "java_plugin without srcs converts (static) libs to deps",
+		Blueprint: `java_plugin {
     name: "java-plug-1",
     libs: ["java-lib-1"],
     static_libs: ["java-lib-2"],
@@ -94,8 +94,8 @@
     srcs: ["c.java"],
     bazel_module: { bp2build_available: false },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("java_plugin", "java-plug-1", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
 				"target_compatible_with": `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index c6feeb8..6465641 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -22,11 +22,11 @@
 	"android/soong/java"
 )
 
-func runJavaProtoTestCase(t *testing.T, tc bp2buildTestCase) {
+func runJavaProtoTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "java_library_static"
-	(&tc).moduleTypeUnderTestFactory = java.LibraryFactory
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+	(&tc).ModuleTypeUnderTest = "java_library_static"
+	(&tc).ModuleTypeUnderTestFactory = java.LibraryFactory
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
 }
 
 func TestJavaProto(t *testing.T) {
@@ -70,25 +70,25 @@
     srcs: ["a.proto"],
 }`
 
-	protoLibrary := makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
+	protoLibrary := makeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
 		"srcs": `["a.proto"]`,
 	})
 
 	for _, tc := range testCases {
 		javaLibraryName := fmt.Sprintf("java-protos_%s", tc.javaLibraryNameExtension)
 
-		runJavaProtoTestCase(t, bp2buildTestCase{
-			description: fmt.Sprintf("java_proto %s", tc.protoType),
-			blueprint:   fmt.Sprintf(bp, tc.protoType),
-			expectedBazelTargets: []string{
+		runJavaProtoTestCase(t, Bp2buildTestCase{
+			Description: fmt.Sprintf("java_proto %s", tc.protoType),
+			Blueprint:   fmt.Sprintf(bp, tc.protoType),
+			ExpectedBazelTargets: []string{
 				protoLibrary,
 				makeBazelTarget(
 					tc.javaLibraryType,
 					javaLibraryName,
-					attrNameToString{
+					AttrNameToString{
 						"deps": `[":java-protos_proto"]`,
 					}),
-				makeBazelTarget("java_library", "java-protos", attrNameToString{
+				makeBazelTarget("java_library", "java-protos", AttrNameToString{
 					"exports": fmt.Sprintf(`[":%s"]`, javaLibraryName),
 				}),
 			},
@@ -97,25 +97,25 @@
 }
 
 func TestJavaProtoDefault(t *testing.T) {
-	runJavaProtoTestCase(t, bp2buildTestCase{
-		description: "java_library proto default",
-		blueprint: `java_library_static {
+	runJavaProtoTestCase(t, Bp2buildTestCase{
+		Description: "java_library proto default",
+		Blueprint: `java_library_static {
     name: "java-protos",
     srcs: ["a.proto"],
     java_version: "7",
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
 				"srcs": `["a.proto"]`,
 			}),
 			makeBazelTarget(
 				"java_lite_proto_library",
 				"java-protos_java_proto_lite",
-				attrNameToString{
+				AttrNameToString{
 					"deps": `[":java-protos_proto"]`,
 				}),
-			makeBazelTarget("java_library", "java-protos", attrNameToString{
+			makeBazelTarget("java_library", "java-protos", AttrNameToString{
 				"exports":   `[":java-protos_java_proto_lite"]`,
 				"javacopts": `["-source 1.7 -target 1.7"]`,
 			}),
diff --git a/bp2build/linker_config_conversion_test.go b/bp2build/linker_config_conversion_test.go
index 4662af4..3b8a363 100644
--- a/bp2build/linker_config_conversion_test.go
+++ b/bp2build/linker_config_conversion_test.go
@@ -21,23 +21,23 @@
 	"android/soong/linkerconfig"
 )
 
-func runLinkerConfigTestCase(t *testing.T, tc bp2buildTestCase) {
+func runLinkerConfigTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "linker_config"
-	(&tc).moduleTypeUnderTestFactory = linkerconfig.LinkerConfigFactory
+	(&tc).ModuleTypeUnderTest = "linker_config"
+	(&tc).ModuleTypeUnderTestFactory = linkerconfig.LinkerConfigFactory
 	runBp2BuildTestCaseSimple(t, tc)
 }
 
 func TestLinkerConfigConvertsSrc(t *testing.T) {
 	runLinkerConfigTestCase(t,
-		bp2buildTestCase{
-			blueprint: `
+		Bp2buildTestCase{
+			Blueprint: `
 linker_config {
 	name: "foo",
 	src: "a.json",
 }
 `,
-			expectedBazelTargets: []string{makeBazelTarget("linker_config", "foo", attrNameToString{
+			ExpectedBazelTargets: []string{makeBazelTarget("linker_config", "foo", AttrNameToString{
 				"src": `"a.json"`,
 			})},
 		})
@@ -46,14 +46,14 @@
 
 func TestLinkerConfigNoSrc(t *testing.T) {
 	runLinkerConfigTestCase(t,
-		bp2buildTestCase{
-			blueprint: `
+		Bp2buildTestCase{
+			Blueprint: `
 linker_config {
 	name: "foo",
 }
 `,
-			expectedBazelTargets: []string{},
-			expectedErr:          fmt.Errorf("Android.bp:2:1: module \"foo\": src: empty src is not supported"),
+			ExpectedBazelTargets: []string{},
+			ExpectedErr:          fmt.Errorf("Android.bp:2:1: module \"foo\": src: empty src is not supported"),
 		})
 
 }
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index 2e4b221..fce4c74 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -21,21 +21,21 @@
 	"testing"
 )
 
-func runPrebuiltEtcTestCase(t *testing.T, tc bp2buildTestCase) {
+func runPrebuiltEtcTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "prebuilt_etc"
-	(&tc).moduleTypeUnderTestFactory = etc.PrebuiltEtcFactory
-	runBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
+	(&tc).ModuleTypeUnderTest = "prebuilt_etc"
+	(&tc).ModuleTypeUnderTestFactory = etc.PrebuiltEtcFactory
+	RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
 }
 
 func registerPrebuiltEtcModuleTypes(ctx android.RegistrationContext) {
 }
 
 func TestPrebuiltEtcSimple(t *testing.T) {
-	runPrebuiltEtcTestCase(t, bp2buildTestCase{
-		description: "prebuilt_etc - simple example",
-		filesystem:  map[string]string{},
-		blueprint: `
+	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+		Description: "prebuilt_etc - simple example",
+		Filesystem:  map[string]string{},
+		Blueprint: `
 prebuilt_etc {
     name: "apex_tz_version",
     src: "version/tz_version",
@@ -44,8 +44,8 @@
     installable: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
 				"filename":    `"tz_version"`,
 				"installable": `False`,
 				"src":         `"version/tz_version"`,
@@ -54,10 +54,10 @@
 }
 
 func TestPrebuiltEtcArchVariant(t *testing.T) {
-	runPrebuiltEtcTestCase(t, bp2buildTestCase{
-		description: "prebuilt_etc - arch variant",
-		filesystem:  map[string]string{},
-		blueprint: `
+	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+		Description: "prebuilt_etc - arch variant",
+		Filesystem:  map[string]string{},
+		Blueprint: `
 prebuilt_etc {
     name: "apex_tz_version",
     src: "version/tz_version",
@@ -74,8 +74,8 @@
     }
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
 				"filename":    `"tz_version"`,
 				"installable": `False`,
 				"src": `select({
@@ -88,10 +88,10 @@
 }
 
 func TestPrebuiltEtcArchAndTargetVariant(t *testing.T) {
-	runPrebuiltEtcTestCase(t, bp2buildTestCase{
-		description: "prebuilt_etc - arch variant",
-		filesystem:  map[string]string{},
-		blueprint: `
+	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+		Description: "prebuilt_etc - arch variant",
+		Filesystem:  map[string]string{},
+		Blueprint: `
 prebuilt_etc {
     name: "apex_tz_version",
     src: "version/tz_version",
@@ -113,8 +113,8 @@
     },
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
 				"filename":    `"tz_version"`,
 				"installable": `False`,
 				"src": `select({
@@ -129,21 +129,21 @@
 			})}})
 }
 
-func runPrebuiltUsrShareTestCase(t *testing.T, tc bp2buildTestCase) {
+func runPrebuiltUsrShareTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	(&tc).moduleTypeUnderTest = "prebuilt_usr_share"
-	(&tc).moduleTypeUnderTestFactory = etc.PrebuiltUserShareFactory
-	runBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
+	(&tc).ModuleTypeUnderTest = "prebuilt_usr_share"
+	(&tc).ModuleTypeUnderTestFactory = etc.PrebuiltUserShareFactory
+	RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
 }
 
 func registerPrebuiltUsrShareModuleTypes(ctx android.RegistrationContext) {
 }
 
 func TestPrebuiltUsrShareSimple(t *testing.T) {
-	runPrebuiltUsrShareTestCase(t, bp2buildTestCase{
-		description: "prebuilt_usr_share - simple example",
-		filesystem:  map[string]string{},
-		blueprint: `
+	runPrebuiltUsrShareTestCase(t, Bp2buildTestCase{
+		Description: "prebuilt_usr_share - simple example",
+		Filesystem:  map[string]string{},
+		Blueprint: `
 prebuilt_usr_share {
     name: "apex_tz_version",
     src: "version/tz_version",
@@ -152,8 +152,8 @@
     installable: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
 				"filename":    `"tz_version"`,
 				"installable": `False`,
 				"src":         `"version/tz_version"`,
@@ -162,10 +162,10 @@
 }
 
 func TestPrebuiltEtcNoSubdir(t *testing.T) {
-	runPrebuiltEtcTestCase(t, bp2buildTestCase{
-		description: "prebuilt_etc - no subdir",
-		filesystem:  map[string]string{},
-		blueprint: `
+	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+		Description: "prebuilt_etc - no subdir",
+		Filesystem:  map[string]string{},
+		Blueprint: `
 prebuilt_etc {
     name: "apex_tz_version",
     src: "version/tz_version",
@@ -173,8 +173,8 @@
     installable: false,
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("prebuilt_file", "apex_tz_version", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
 				"filename":    `"tz_version"`,
 				"installable": `False`,
 				"src":         `"version/tz_version"`,
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 22bd028..79da5d5 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -7,27 +7,27 @@
 	"android/soong/python"
 )
 
-func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc bp2buildTestCase) {
+func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
 		ctx.RegisterModuleType("python_library_host", python.PythonLibraryHostFactory)
 	}, tc)
 }
 
 func TestPythonBinaryHostSimple(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, bp2buildTestCase{
-		description:                "simple python_binary_host converts to a native py_binary",
-		moduleTypeUnderTest:        "python_binary_host",
-		moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		filesystem: map[string]string{
+	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+		Description:                "simple python_binary_host converts to a native py_binary",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Filesystem: map[string]string{
 			"a.py":           "",
 			"b/c.py":         "",
 			"b/d.py":         "",
 			"b/e.py":         "",
 			"files/data.txt": "",
 		},
-		blueprint: `python_binary_host {
+		Blueprint: `python_binary_host {
     name: "foo",
     main: "a.py",
     srcs: ["**/*.py"],
@@ -41,8 +41,8 @@
       srcs: ["b/e.py"],
       bazel_module: { bp2build_available: false },
     }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("py_binary", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("py_binary", "foo", AttrNameToString{
 				"data":    `["files/data.txt"]`,
 				"deps":    `[":bar"]`,
 				"main":    `"a.py"`,
@@ -62,11 +62,11 @@
 }
 
 func TestPythonBinaryHostPy2(t *testing.T) {
-	runBp2BuildTestCaseSimple(t, bp2buildTestCase{
-		description:                "py2 python_binary_host",
-		moduleTypeUnderTest:        "python_binary_host",
-		moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		blueprint: `python_binary_host {
+	runBp2BuildTestCaseSimple(t, Bp2buildTestCase{
+		Description:                "py2 python_binary_host",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Blueprint: `python_binary_host {
     name: "foo",
     srcs: ["a.py"],
     version: {
@@ -81,8 +81,8 @@
     bazel_module: { bp2build_available: true },
 }
 `,
-		expectedBazelTargets: []string{
-			makeBazelTarget("py_binary", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("py_binary", "foo", AttrNameToString{
 				"python_version": `"PY2"`,
 				"imports":        `["."]`,
 				"srcs":           `["a.py"]`,
@@ -96,11 +96,11 @@
 }
 
 func TestPythonBinaryHostPy3(t *testing.T) {
-	runBp2BuildTestCaseSimple(t, bp2buildTestCase{
-		description:                "py3 python_binary_host",
-		moduleTypeUnderTest:        "python_binary_host",
-		moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		blueprint: `python_binary_host {
+	runBp2BuildTestCaseSimple(t, Bp2buildTestCase{
+		Description:                "py3 python_binary_host",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Blueprint: `python_binary_host {
     name: "foo",
     srcs: ["a.py"],
     version: {
@@ -115,9 +115,9 @@
     bazel_module: { bp2build_available: true },
 }
 `,
-		expectedBazelTargets: []string{
+		ExpectedBazelTargets: []string{
 			// python_version is PY3 by default.
-			makeBazelTarget("py_binary", "foo", attrNameToString{
+			makeBazelTarget("py_binary", "foo", AttrNameToString{
 				"imports": `["."]`,
 				"srcs":    `["a.py"]`,
 				"target_compatible_with": `select({
@@ -130,15 +130,15 @@
 }
 
 func TestPythonBinaryHostArchVariance(t *testing.T) {
-	runBp2BuildTestCaseSimple(t, bp2buildTestCase{
-		description:                "test arch variants",
-		moduleTypeUnderTest:        "python_binary_host",
-		moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		filesystem: map[string]string{
+	runBp2BuildTestCaseSimple(t, Bp2buildTestCase{
+		Description:                "test arch variants",
+		ModuleTypeUnderTest:        "python_binary_host",
+		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
+		Filesystem: map[string]string{
 			"dir/arm.py": "",
 			"dir/x86.py": "",
 		},
-		blueprint: `python_binary_host {
+		Blueprint: `python_binary_host {
 					 name: "foo-arm",
 					 arch: {
 						 arm: {
@@ -149,8 +149,8 @@
 						 },
 					},
 				 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("py_binary", "foo-arm", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("py_binary", "foo-arm", AttrNameToString{
 				"imports": `["."]`,
 				"srcs": `select({
         "//build/bazel/platforms/arch:arm": ["arm.py"],
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index f51f106..1d6061b 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -21,7 +21,7 @@
 	expectedError        error
 }
 
-func convertPythonLibTestCaseToBp2build_Host(tc pythonLibBp2BuildTestCase) bp2buildTestCase {
+func convertPythonLibTestCaseToBp2build_Host(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
 	for i := range tc.expectedBazelTargets {
 		tc.expectedBazelTargets[i].attrs["target_compatible_with"] = `select({
         "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
@@ -32,7 +32,7 @@
 	return convertPythonLibTestCaseToBp2build(tc)
 }
 
-func convertPythonLibTestCaseToBp2build(tc pythonLibBp2BuildTestCase) bp2buildTestCase {
+func convertPythonLibTestCaseToBp2build(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
 	var bp2BuildTargets []string
 	for _, t := range tc.expectedBazelTargets {
 		bp2BuildTargets = append(bp2BuildTargets, makeBazelTarget(t.typ, t.name, t.attrs))
@@ -43,28 +43,28 @@
 	for k, v := range tc.filesystem {
 		filesystemCopy[k] = v
 	}
-	return bp2buildTestCase{
-		description:          tc.description,
-		filesystem:           filesystemCopy,
-		blueprint:            tc.blueprint,
-		expectedBazelTargets: bp2BuildTargets,
-		dir:                  tc.dir,
-		expectedErr:          tc.expectedError,
+	return Bp2buildTestCase{
+		Description:          tc.description,
+		Filesystem:           filesystemCopy,
+		Blueprint:            tc.blueprint,
+		ExpectedBazelTargets: bp2BuildTargets,
+		Dir:                  tc.dir,
+		ExpectedErr:          tc.expectedError,
 	}
 }
 
 func runPythonLibraryTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
 	t.Helper()
 	testCase := convertPythonLibTestCaseToBp2build(tc)
-	testCase.description = fmt.Sprintf(testCase.description, "python_library")
-	testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library")
-	for name, contents := range testCase.filesystem {
+	testCase.Description = fmt.Sprintf(testCase.Description, "python_library")
+	testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library")
+	for name, contents := range testCase.Filesystem {
 		if strings.HasSuffix(name, "Android.bp") {
-			testCase.filesystem[name] = fmt.Sprintf(contents, "python_library")
+			testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library")
 		}
 	}
-	testCase.moduleTypeUnderTest = "python_library"
-	testCase.moduleTypeUnderTestFactory = python.PythonLibraryFactory
+	testCase.ModuleTypeUnderTest = "python_library"
+	testCase.ModuleTypeUnderTestFactory = python.PythonLibraryFactory
 
 	runBp2BuildTestCaseSimple(t, testCase)
 }
@@ -72,16 +72,16 @@
 func runPythonLibraryHostTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
 	t.Helper()
 	testCase := convertPythonLibTestCaseToBp2build_Host(tc)
-	testCase.description = fmt.Sprintf(testCase.description, "python_library_host")
-	testCase.blueprint = fmt.Sprintf(testCase.blueprint, "python_library_host")
-	for name, contents := range testCase.filesystem {
+	testCase.Description = fmt.Sprintf(testCase.Description, "python_library_host")
+	testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library_host")
+	for name, contents := range testCase.Filesystem {
 		if strings.HasSuffix(name, "Android.bp") {
-			testCase.filesystem[name] = fmt.Sprintf(contents, "python_library_host")
+			testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library_host")
 		}
 	}
-	testCase.moduleTypeUnderTest = "python_library_host"
-	testCase.moduleTypeUnderTestFactory = python.PythonLibraryHostFactory
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+	testCase.ModuleTypeUnderTest = "python_library_host"
+	testCase.ModuleTypeUnderTestFactory = python.PythonLibraryHostFactory
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
 	},
 		testCase)
@@ -121,7 +121,7 @@
 				{
 					typ:  "py_library",
 					name: "foo",
-					attrs: attrNameToString{
+					attrs: AttrNameToString{
 						"data": `["files/data.txt"]`,
 						"deps": `[":bar"]`,
 						"srcs": `[
@@ -155,7 +155,7 @@
 				{
 					typ:  "py_library",
 					name: "foo",
-					attrs: attrNameToString{
+					attrs: AttrNameToString{
 						"srcs":         `["a.py"]`,
 						"srcs_version": `"PY2"`,
 						"imports":      `["."]`,
@@ -183,7 +183,7 @@
 				{
 					typ:  "py_library",
 					name: "foo",
-					attrs: attrNameToString{
+					attrs: AttrNameToString{
 						"srcs":         `["a.py"]`,
 						"srcs_version": `"PY3"`,
 						"imports":      `["."]`,
@@ -212,7 +212,7 @@
 					// srcs_version is PY2ANDPY3 by default.
 					typ:  "py_library",
 					name: "foo",
-					attrs: attrNameToString{
+					attrs: AttrNameToString{
 						"srcs":    `["a.py"]`,
 						"imports": `["."]`,
 					},
@@ -238,7 +238,7 @@
 					// srcs_version is PY2ANDPY3 by default.
 					typ:  "py_library",
 					name: "foo",
-					attrs: attrNameToString{
+					attrs: AttrNameToString{
 						"srcs":         `["a.py"]`,
 						"imports":      `["../.."]`,
 						"srcs_version": `"PY3"`,
@@ -292,7 +292,7 @@
 			{
 				typ:  "py_library",
 				name: "foo",
-				attrs: attrNameToString{
+				attrs: AttrNameToString{
 					"srcs": `select({
         "//build/bazel/platforms/arch:arm": ["arm.py"],
         "//build/bazel/platforms/arch:x86": ["x86.py"],
@@ -324,21 +324,21 @@
 			{
 				typ:  "proto_library",
 				name: "foo_proto",
-				attrs: attrNameToString{
+				attrs: AttrNameToString{
 					"srcs": `["dir/myproto.proto"]`,
 				},
 			},
 			{
 				typ:  "py_proto_library",
 				name: "foo_py_proto",
-				attrs: attrNameToString{
+				attrs: AttrNameToString{
 					"deps": `[":foo_proto"]`,
 				},
 			},
 			{
 				typ:  "py_library",
 				name: "foo",
-				attrs: attrNameToString{
+				attrs: AttrNameToString{
 					"srcs":         `["dir/mylib.py"]`,
 					"srcs_version": `"PY3"`,
 					"imports":      `["."]`,
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
index ac89087..d8f701d 100644
--- a/bp2build/sh_conversion_test.go
+++ b/bp2build/sh_conversion_test.go
@@ -48,25 +48,25 @@
 	}
 }
 
-func runShBinaryTestCase(t *testing.T, tc bp2buildTestCase) {
+func runShBinaryTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
 }
 
 func TestShBinarySimple(t *testing.T) {
-	runShBinaryTestCase(t, bp2buildTestCase{
-		description:                "sh_binary test",
-		moduleTypeUnderTest:        "sh_binary",
-		moduleTypeUnderTestFactory: sh.ShBinaryFactory,
-		blueprint: `sh_binary {
+	runShBinaryTestCase(t, Bp2buildTestCase{
+		Description:                "sh_binary test",
+		ModuleTypeUnderTest:        "sh_binary",
+		ModuleTypeUnderTestFactory: sh.ShBinaryFactory,
+		Blueprint: `sh_binary {
     name: "foo",
     src: "foo.sh",
     filename: "foo.exe",
     sub_dir: "sub",
     bazel_module: { bp2build_available: true },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("sh_binary", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("sh_binary", "foo", AttrNameToString{
 				"srcs":     `["foo.sh"]`,
 				"filename": `"foo.exe"`,
 				"sub_dir":  `"sub"`,
@@ -75,17 +75,17 @@
 }
 
 func TestShBinaryDefaults(t *testing.T) {
-	runShBinaryTestCase(t, bp2buildTestCase{
-		description:                "sh_binary test",
-		moduleTypeUnderTest:        "sh_binary",
-		moduleTypeUnderTestFactory: sh.ShBinaryFactory,
-		blueprint: `sh_binary {
+	runShBinaryTestCase(t, Bp2buildTestCase{
+		Description:                "sh_binary test",
+		ModuleTypeUnderTest:        "sh_binary",
+		ModuleTypeUnderTestFactory: sh.ShBinaryFactory,
+		Blueprint: `sh_binary {
     name: "foo",
     src: "foo.sh",
     bazel_module: { bp2build_available: true },
 }`,
-		expectedBazelTargets: []string{
-			makeBazelTarget("sh_binary", "foo", attrNameToString{
+		ExpectedBazelTargets: []string{
+			makeBazelTarget("sh_binary", "foo", AttrNameToString{
 				"srcs": `["foo.sh"]`,
 			})},
 	})
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index 8460cae..a94b2b9 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -20,9 +20,9 @@
 	"testing"
 )
 
-func runSoongConfigModuleTypeTest(t *testing.T, tc bp2buildTestCase) {
+func runSoongConfigModuleTypeTest(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
 }
 
 func registerSoongConfigModuleTypes(ctx android.RegistrationContext) {
@@ -61,12 +61,12 @@
 }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - soong_config_module_type is supported in bp2build",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		blueprint:                  bp,
-		expectedBazelTargets: []string{`cc_library_static(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - soong_config_module_type is supported in bp2build",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint:                  bp,
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
         "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
@@ -107,15 +107,15 @@
 }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - soong_config_module_type_import is supported in bp2build",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		filesystem: map[string]string{
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - soong_config_module_type_import is supported in bp2build",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Filesystem: map[string]string{
 			"foo/bar/SoongConfig.bp": configBp,
 		},
-		blueprint: bp,
-		expectedBazelTargets: []string{`cc_library_static(
+		Blueprint: bp,
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
         "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
@@ -161,12 +161,12 @@
 }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for string vars",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		blueprint:                  bp,
-		expectedBazelTargets: []string{`cc_library_static(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for string vars",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint:                  bp,
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
         "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
@@ -232,12 +232,12 @@
 	},
 }`
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for multiple variable types",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		blueprint:                  bp,
-		expectedBazelTargets: []string{`cc_library_static(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for multiple variable types",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint:                  bp,
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
         "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
@@ -298,15 +298,15 @@
 cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_available: false } }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for label list attributes",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		blueprint:                  bp,
-		filesystem: map[string]string{
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for label list attributes",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint:                  bp,
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": otherDeps,
 		},
-		expectedBazelTargets: []string{`cc_library_static(
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
         "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
@@ -365,12 +365,12 @@
 }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - defaults with a single namespace",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		blueprint:                  bp,
-		expectedBazelTargets: []string{`cc_library_static(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - defaults with a single namespace",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint:                  bp,
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "lib",
     copts = select({
         "//build/bazel/product_variables:vendor_foo__feature": [
@@ -446,12 +446,12 @@
 }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - multiple defaults with a single namespace",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		blueprint:                  bp,
-		expectedBazelTargets: []string{`cc_library_static(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - multiple defaults with a single namespace",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint:                  bp,
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "lib",
     asflags = select({
         "//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
@@ -562,12 +562,12 @@
 }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - defaults with multiple namespaces",
-		moduleTypeUnderTest:        "cc_library_static",
-		moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		blueprint:                  bp,
-		expectedBazelTargets: []string{`cc_library_static(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - defaults with multiple namespaces",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint:                  bp,
+		ExpectedBazelTargets: []string{`cc_library_static(
     name = "lib",
     copts = select({
         "//build/bazel/product_variables:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
@@ -653,15 +653,15 @@
 cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for library_linking_strategy",
-		moduleTypeUnderTest:        "cc_binary",
-		moduleTypeUnderTestFactory: cc.BinaryFactory,
-		blueprint:                  bp,
-		filesystem: map[string]string{
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for library_linking_strategy",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": otherDeps,
 		},
-		expectedBazelTargets: []string{`cc_binary(
+		ExpectedBazelTargets: []string{`cc_binary(
     name = "library_linking_strategy_sample_binary",
     deps = select({
         "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
@@ -734,15 +734,15 @@
 cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for library_linking_strategy",
-		moduleTypeUnderTest:        "cc_binary",
-		moduleTypeUnderTestFactory: cc.BinaryFactory,
-		blueprint:                  bp,
-		filesystem: map[string]string{
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for library_linking_strategy",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": otherDeps,
 		},
-		expectedBazelTargets: []string{`cc_binary(
+		ExpectedBazelTargets: []string{`cc_binary(
     name = "library_linking_strategy_sample_binary",
     deps = select({
         "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
@@ -822,15 +822,15 @@
 cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
 `
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for library_linking_strategy",
-		moduleTypeUnderTest:        "cc_binary",
-		moduleTypeUnderTestFactory: cc.BinaryFactory,
-		blueprint:                  bp,
-		filesystem: map[string]string{
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for library_linking_strategy",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		Filesystem: map[string]string{
 			"foo/bar/Android.bp": otherDeps,
 		},
-		expectedBazelTargets: []string{`cc_binary(
+		ExpectedBazelTargets: []string{`cc_binary(
     name = "alphabet_binary",
     deps = select({
         "//build/bazel/product_variables:android__alphabet__a": [],
@@ -888,13 +888,13 @@
     },
 }`
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for library_linking_strategy",
-		moduleTypeUnderTest:        "cc_binary",
-		moduleTypeUnderTestFactory: cc.BinaryFactory,
-		blueprint:                  bp,
-		filesystem:                 map[string]string{},
-		expectedBazelTargets: []string{`cc_binary(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for library_linking_strategy",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		Filesystem:                 map[string]string{},
+		ExpectedBazelTargets: []string{`cc_binary(
     name = "alphabet_binary",
     local_includes = ["."],
     srcs = ["main.cc"],
@@ -941,13 +941,13 @@
     enabled: false,
 }`
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for library_linking_strategy",
-		moduleTypeUnderTest:        "cc_binary",
-		moduleTypeUnderTestFactory: cc.BinaryFactory,
-		blueprint:                  bp,
-		filesystem:                 map[string]string{},
-		expectedBazelTargets: []string{`cc_binary(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for library_linking_strategy",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		Filesystem:                 map[string]string{},
+		ExpectedBazelTargets: []string{`cc_binary(
     name = "alphabet_binary",
     local_includes = ["."],
     srcs = ["main.cc"],
@@ -985,13 +985,13 @@
     defaults: ["alphabet_sample_cc_defaults"],
 }`
 
-	runSoongConfigModuleTypeTest(t, bp2buildTestCase{
-		description:                "soong config variables - generates selects for library_linking_strategy",
-		moduleTypeUnderTest:        "cc_binary",
-		moduleTypeUnderTestFactory: cc.BinaryFactory,
-		blueprint:                  bp,
-		filesystem:                 map[string]string{},
-		expectedBazelTargets: []string{`cc_binary(
+	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+		Description:                "soong config variables - generates selects for library_linking_strategy",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		Filesystem:                 map[string]string{},
+		ExpectedBazelTargets: []string{`cc_binary(
     name = "alphabet_binary",
     local_includes = ["."],
     srcs = ["main.cc"],
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index 78e7b0e..023ec96 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -1,12 +1,27 @@
+// 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"
 	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"regexp"
 
+	"android/soong/android"
 	"android/soong/shared"
 )
 
@@ -58,6 +73,57 @@
 	return result
 }
 
+func mergeBuildFiles(output string, srcBuildFile string, generatedBuildFile string, verbose bool) error {
+
+	srcBuildFileContent, err := os.ReadFile(srcBuildFile)
+	if err != nil {
+		return err
+	}
+
+	generatedBuildFileContent, err := os.ReadFile(generatedBuildFile)
+	if err != nil {
+		return err
+	}
+
+	// There can't be a package() call in both the source and generated BUILD files.
+	// bp2build will generate a package() call for licensing information, but if
+	// there's no licensing information, it will still generate a package() call
+	// that just sets default_visibility=public. If the handcrafted build file
+	// also has a package() call, we'll allow it to override the bp2build
+	// generated one if it doesn't have any licensing information. If the bp2build
+	// one has licensing information and the handcrafted one exists, we'll leave
+	// them both in for bazel to throw an error.
+	packageRegex := regexp.MustCompile(`(?m)^package\s*\(`)
+	packageDefaultVisibilityRegex := regexp.MustCompile(`(?m)^package\s*\(\s*default_visibility\s*=\s*\[\s*"//visibility:public",?\s*]\s*\)`)
+	if packageRegex.Find(srcBuildFileContent) != nil {
+		if verbose && packageDefaultVisibilityRegex.Find(generatedBuildFileContent) != nil {
+			fmt.Fprintf(os.Stderr, "Both '%s' and '%s' have a package() target, removing the first one\n",
+				generatedBuildFile, srcBuildFile)
+		}
+		generatedBuildFileContent = packageDefaultVisibilityRegex.ReplaceAll(generatedBuildFileContent, []byte{})
+	}
+
+	outFile, err := os.Create(output)
+	if err != nil {
+		return err
+	}
+
+	_, err = outFile.Write(generatedBuildFileContent)
+	if err != nil {
+		return err
+	}
+
+	if generatedBuildFileContent[len(generatedBuildFileContent)-1] != '\n' {
+		_, err = outFile.WriteString("\n")
+		if err != nil {
+			return err
+		}
+	}
+
+	_, err = outFile.Write(srcBuildFileContent)
+	return err
+}
+
 // Calls readdir() and returns it as a map from the basename of the files in dir
 // to os.FileInfo.
 func readdirToMap(dir string) map[string]os.FileInfo {
@@ -125,6 +191,17 @@
 	srcDirMap := readdirToMap(shared.JoinPath(topdir, srcDir))
 	buildFilesMap := readdirToMap(shared.JoinPath(topdir, buildFilesDir))
 
+	renamingBuildFile := false
+	if _, ok := srcDirMap["BUILD"]; ok {
+		if _, ok := srcDirMap["BUILD.bazel"]; !ok {
+			if _, ok := buildFilesMap["BUILD.bazel"]; ok {
+				renamingBuildFile = true
+				srcDirMap["BUILD.bazel"] = srcDirMap["BUILD"]
+				delete(srcDirMap, "BUILD")
+			}
+		}
+	}
+
 	allEntries := make(map[string]bool)
 	for n := range srcDirMap {
 		allEntries[n] = true
@@ -148,21 +225,28 @@
 		// The full paths of children in the input trees and in the output tree
 		forestChild := shared.JoinPath(forestDir, f)
 		srcChild := shared.JoinPath(srcDir, f)
+		if f == "BUILD.bazel" && renamingBuildFile {
+			srcChild = shared.JoinPath(srcDir, "BUILD")
+		}
 		buildFilesChild := shared.JoinPath(buildFilesDir, f)
 
 		// Descend in the exclusion tree, if there are any excludes left
-		var excludeChild *node
-		if exclude == nil {
-			excludeChild = nil
-		} else {
-			excludeChild = exclude.children[f]
+		var excludeChild *node = nil
+		if exclude != nil {
+			if f == "BUILD.bazel" && renamingBuildFile {
+				excludeChild = exclude.children["BUILD"]
+			} else {
+				excludeChild = exclude.children[f]
+			}
 		}
 
 		srcChildEntry, sExists := srcDirMap[f]
 		buildFilesChildEntry, bExists := buildFilesMap[f]
-		excluded := excludeChild != nil && excludeChild.excluded
 
-		if excluded {
+		if excludeChild != nil && excludeChild.excluded {
+			if bExists {
+				symlinkIntoForest(topdir, forestChild, buildFilesChild)
+			}
 			continue
 		}
 
@@ -198,13 +282,15 @@
 			// Both are directories. Descend.
 			plantSymlinkForestRecursive(cfg, topdir, forestChild, buildFilesChild, srcChild, excludeChild, acc, okay)
 		} else if !sDir && !bDir {
-			// Neither is a directory. Prioritize BUILD files generated by bp2build
-			// over any BUILD file imported into external/.
-			if cfg.IsEnvTrue("BP2BUILD_VERBOSE") {
-				fmt.Fprintf(os.Stderr, "Both '%s' and '%s' exist, symlinking the former to '%s'\n",
-					buildFilesChild, srcChild, forestChild)
+			// Neither is a directory. Merge them.
+			srcBuildFile := shared.JoinPath(topdir, srcChild)
+			generatedBuildFile := shared.JoinPath(topdir, buildFilesChild)
+			err = mergeBuildFiles(shared.JoinPath(topdir, forestChild), srcBuildFile, generatedBuildFile, cfg.IsEnvTrue("BP2BUILD_VERBOSE"))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "Error merging %s and %s: %s",
+					srcBuildFile, generatedBuildFile, err)
+				*okay = false
 			}
-			symlinkIntoForest(topdir, forestChild, buildFilesChild)
 		} else {
 			// Both exist and one is a file. This is an error.
 			fmt.Fprintf(os.Stderr,
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 580bac4..0f321de 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -53,16 +53,16 @@
 	return false
 }
 
-func errored(t *testing.T, tc bp2buildTestCase, errs []error) bool {
+func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
 	t.Helper()
-	if tc.expectedErr != nil {
+	if tc.ExpectedErr != nil {
 		// Rely on checkErrors, as this test case is expected to have an error.
 		return false
 	}
 
 	if len(errs) > 0 {
 		for _, err := range errs {
-			t.Errorf("%s: %s", tc.description, err)
+			t.Errorf("%s: %s", tc.Description, err)
 		}
 		return true
 	}
@@ -71,42 +71,42 @@
 	return false
 }
 
-func runBp2BuildTestCaseSimple(t *testing.T, tc bp2buildTestCase) {
+func runBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
-	runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
 }
 
-type bp2buildTestCase struct {
-	description                string
-	moduleTypeUnderTest        string
-	moduleTypeUnderTestFactory android.ModuleFactory
-	blueprint                  string
-	expectedBazelTargets       []string
-	filesystem                 map[string]string
-	dir                        string
+type Bp2buildTestCase struct {
+	Description                string
+	ModuleTypeUnderTest        string
+	ModuleTypeUnderTestFactory android.ModuleFactory
+	Blueprint                  string
+	ExpectedBazelTargets       []string
+	Filesystem                 map[string]string
+	Dir                        string
 	// An error with a string contained within the string of the expected error
-	expectedErr         error
-	unconvertedDepsMode unconvertedDepsMode
+	ExpectedErr         error
+	UnconvertedDepsMode unconvertedDepsMode
 }
 
-func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
+func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
 	t.Helper()
 	dir := "."
 	filesystem := make(map[string][]byte)
 	toParse := []string{
 		"Android.bp",
 	}
-	for f, content := range tc.filesystem {
+	for f, content := range tc.Filesystem {
 		if strings.HasSuffix(f, "Android.bp") {
 			toParse = append(toParse, f)
 		}
 		filesystem[f] = []byte(content)
 	}
-	config := android.TestConfig(buildDir, nil, tc.blueprint, filesystem)
+	config := android.TestConfig(buildDir, nil, tc.Blueprint, filesystem)
 	ctx := android.NewTestContext(config)
 
 	registerModuleTypes(ctx)
-	ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory)
+	ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
 	ctx.RegisterBp2BuildConfig(bp2buildConfig)
 	ctx.RegisterForBazelConversion()
 
@@ -120,35 +120,35 @@
 	}
 
 	parseAndResolveErrs := append(parseErrs, resolveDepsErrs...)
-	if tc.expectedErr != nil && checkError(t, parseAndResolveErrs, tc.expectedErr) {
+	if tc.ExpectedErr != nil && checkError(t, parseAndResolveErrs, tc.ExpectedErr) {
 		return
 	}
 
 	checkDir := dir
-	if tc.dir != "" {
-		checkDir = tc.dir
+	if tc.Dir != "" {
+		checkDir = tc.Dir
 	}
 	codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
-	codegenCtx.unconvertedDepMode = tc.unconvertedDepsMode
+	codegenCtx.unconvertedDepMode = tc.UnconvertedDepsMode
 	bazelTargets, errs := generateBazelTargetsForDir(codegenCtx, checkDir)
-	if tc.expectedErr != nil {
-		if checkError(t, errs, tc.expectedErr) {
+	if tc.ExpectedErr != nil {
+		if checkError(t, errs, tc.ExpectedErr) {
 			return
 		} else {
-			t.Errorf("Expected error: %q, got: %q and %q", tc.expectedErr, errs, parseAndResolveErrs)
+			t.Errorf("Expected error: %q, got: %q and %q", tc.ExpectedErr, errs, parseAndResolveErrs)
 		}
 	} else {
 		android.FailIfErrored(t, errs)
 	}
-	if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
+	if actualCount, expectedCount := len(bazelTargets), len(tc.ExpectedBazelTargets); actualCount != expectedCount {
 		t.Errorf("%s: Expected %d bazel target (%s), got `%d`` (%s)",
-			tc.description, expectedCount, tc.expectedBazelTargets, actualCount, bazelTargets)
+			tc.Description, expectedCount, tc.ExpectedBazelTargets, actualCount, bazelTargets)
 	} else {
 		for i, target := range bazelTargets {
-			if w, g := tc.expectedBazelTargets[i], target.content; w != g {
+			if w, g := tc.ExpectedBazelTargets[i], target.content; w != g {
 				t.Errorf(
 					"%s: Expected generated Bazel target to be `%s`, got `%s`",
-					tc.description, w, g)
+					tc.Description, w, g)
 			}
 		}
 	}
@@ -173,11 +173,12 @@
 	Bool_prop     bool
 	Bool_ptr_prop *bool
 	// Ensure that properties tagged `blueprint:mutated` are omitted
-	Int_prop         int `blueprint:"mutated"`
-	Int64_ptr_prop   *int64
-	String_prop      string
-	String_ptr_prop  *string
-	String_list_prop []string
+	Int_prop            int `blueprint:"mutated"`
+	Int64_ptr_prop      *int64
+	String_prop         string
+	String_literal_prop *string `android:"arch_variant"`
+	String_ptr_prop     *string
+	String_list_prop    []string
 
 	Nested_props     nestedProps
 	Nested_props_ptr *nestedProps
@@ -305,23 +306,29 @@
 type customBazelModuleAttributes struct {
 	EmbeddedAttr
 	*OtherEmbeddedAttr
-	String_ptr_prop  *string
-	String_list_prop []string
-	Arch_paths       bazel.LabelListAttribute
+	String_literal_prop bazel.StringAttribute
+	String_ptr_prop     *string
+	String_list_prop    []string
+	Arch_paths          bazel.LabelListAttribute
 }
 
 func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	paths := bazel.LabelListAttribute{}
-
 	if p := m.props.One_to_many_prop; p != nil && *p {
 		customBp2buildOneToMany(ctx, m)
 		return
 	}
 
+	paths := bazel.LabelListAttribute{}
+	strAttr := bazel.StringAttribute{}
 	for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
 		for config, props := range configToProps {
-			if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
-				paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude))
+			if custProps, ok := props.(*customProps); ok {
+				if custProps.Arch_paths != nil {
+					paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
+				}
+				if custProps.String_literal_prop != nil {
+					strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
+				}
 			}
 		}
 	}
@@ -329,10 +336,12 @@
 	paths.ResolveExcludes()
 
 	attrs := &customBazelModuleAttributes{
-		String_ptr_prop:  m.props.String_ptr_prop,
-		String_list_prop: m.props.String_list_prop,
-		Arch_paths:       paths,
+		String_literal_prop: strAttr,
+		String_ptr_prop:     m.props.String_ptr_prop,
+		String_list_prop:    m.props.String_list_prop,
+		Arch_paths:          paths,
 	}
+
 	attrs.Embedded_attr = m.props.Embedded_prop
 	if m.props.OtherEmbeddedProps != nil {
 		attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
@@ -391,10 +400,10 @@
 }`, typ, name)
 }
 
-type attrNameToString map[string]string
+type AttrNameToString map[string]string
 
-func (a attrNameToString) clone() attrNameToString {
-	newAttrs := make(attrNameToString, len(a))
+func (a AttrNameToString) clone() AttrNameToString {
+	newAttrs := make(AttrNameToString, len(a))
 	for k, v := range a {
 		newAttrs[k] = v
 	}
@@ -403,7 +412,7 @@
 
 // makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
 // device specific, or independent of host/device.
-func makeBazelTargetHostOrDevice(typ, name string, attrs attrNameToString, hod android.HostOrDeviceSupported) string {
+func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
 	if _, ok := attrs["target_compatible_with"]; !ok {
 		switch hod {
 		case android.HostSupported:
@@ -426,15 +435,15 @@
 )`, typ, strings.Join(attrStrings, "\n"))
 }
 
-// makeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
+// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
 // target_compatible_with.  This is useful for module types like filegroup and genrule that arch not
 // arch variant
-func makeBazelTargetNoRestrictions(typ, name string, attrs attrNameToString) string {
+func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
 	return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
 }
 
 // makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
 // as this is the most common default in Soong.
-func makeBazelTarget(typ, name string, attrs attrNameToString) string {
+func makeBazelTarget(typ, name string, attrs AttrNameToString) string {
 	return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
 }
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 5d2533f..e89cc4e 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -69,12 +69,23 @@
 }
 
 type BpfProperties struct {
-	Srcs         []string `android:"path"`
-	Cflags       []string
+	// source paths to the files.
+	Srcs []string `android:"path"`
+
+	// additional cflags that should be used to build the bpf variant of
+	// the C/C++ module.
+	Cflags []string
+
+	// directories (relative to the root of the source tree) that will
+	// be added to the include paths using -I.
 	Include_dirs []string
-	Sub_dir      string
-	// If set to true, generate BTF debug info for maps & programs
-	Btf    *bool
+
+	// optional subdirectory under which this module is installed into.
+	Sub_dir string
+
+	// if set to true, generate BTF debug info for maps & programs.
+	Btf *bool
+
 	Vendor *bool
 
 	VendorInternal bool `blueprint:"mutated"`
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index 94b28dc..ddaa98a 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -553,7 +553,9 @@
 
 // If a variable is LOCAL_MODULE, get its value from the 'name' attribute.
 // This handles the statement
-//    LOCAL_SRC_FILES := $(LOCAL_MODULE)
+//
+//	LOCAL_SRC_FILES := $(LOCAL_MODULE)
+//
 // which occurs often.
 func resolveLocalModule(mod *parser.Module, val parser.Expression) parser.Expression {
 	if varLocalName, ok := val.(*parser.Variable); ok {
@@ -567,9 +569,9 @@
 }
 
 // etcPrebuiltModuleUpdate contains information on updating certain parts of a defined module such as:
-//    * changing the module type from prebuilt_etc to a different one
-//    * stripping the prefix of the install path based on the module type
-//    * appending additional boolean properties to the prebuilt module
+//   - changing the module type from prebuilt_etc to a different one
+//   - stripping the prefix of the install path based on the module type
+//   - appending additional boolean properties to the prebuilt module
 type etcPrebuiltModuleUpdate struct {
 	// The prefix of the install path defined in local_module_path. The prefix is removed from local_module_path
 	// before setting the 'filename' attribute.
diff --git a/build_kzip.bash b/build_kzip.bash
index 6219021..eeef7d4 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -44,16 +44,23 @@
 declare -r go_root=$(realpath prebuilts/go/linux-x86)
 declare -r source_root=$PWD
 
-# TODO(asmundak): Until b/182183061 is fixed, default corpus has to be specified
-# in the rules file. Generate this file on the fly with corpus value set from the
-# environment variable.
-for dir in blueprint soong; do
-  (cd "build/$dir";
+# For the Go code, we invoke the extractor directly. The two caveats are that
+# the extractor's rewrite rules are generated on the fly as they depend on the
+# value of XREF_CORPUS, and that the name of the kzip file is derived from the
+# directory name by replacing '/' with '_'.
+# Go extractor should succeed.
+declare -ar go_modules=(build/blueprint build/soong
+  build/make/tools/canoninja build/make/tools/compliance build/make/tools/rbcrun)
+set -e
+for dir in "${go_modules[@]}"; do
+  (cd "$dir";
+   outfile=$(echo "$dir" | sed -r 's|/|_|g;s|(.*)|\1.go.kzip|');
    KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" \
    --rules=<(printf '[{"pattern": "(.*)","vname": {"path": "@1@", "corpus":"%s"}}]' "${XREF_CORPUS}") \
-   --canonicalize_package_corpus --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
+   --canonicalize_package_corpus --output "${abspath_out}/soong/$outfile" ./...
   )
 done
+set +e
 
 declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l)
 (($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
diff --git a/cc/afdo.go b/cc/afdo.go
index 66e9732..fb66bbe 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -66,8 +66,9 @@
 }
 
 // Get list of profile file names, ordered by level of specialisation. For example:
-//   1. libfoo_arm64.afdo
-//   2. libfoo.afdo
+//  1. libfoo_arm64.afdo
+//  2. libfoo.afdo
+//
 // Add more specialisation as needed.
 func getProfileFiles(ctx android.BaseModuleContext, moduleName string) []string {
 	var files []string
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ff5ba45..a957246 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -23,6 +23,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/multitree"
 )
 
 var (
@@ -226,17 +227,27 @@
 	}
 }
 
-func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
-	if library.sAbiDiff.Valid() && !library.static() {
-		entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff.String())
+func (library *libraryDecorator) getAbiDiffsForAndroidMkDeps() []string {
+	if library.static() {
+		return nil
 	}
+	var abiDiffs []string
+	if library.sAbiDiff.Valid() {
+		abiDiffs = append(abiDiffs, library.sAbiDiff.String())
+	}
+	if library.prevSAbiDiff.Valid() {
+		abiDiffs = append(abiDiffs, library.prevSAbiDiff.String())
+	}
+	return abiDiffs
+}
+
+func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
+	entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", library.getAbiDiffsForAndroidMkDeps()...)
 }
 
 // TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries
 func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
-	if library.sAbiDiff.Valid() && !library.static() {
-		fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
-	}
+	fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", strings.Join(library.getAbiDiffsForAndroidMkDeps(), " "))
 }
 
 func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
@@ -401,14 +412,13 @@
 			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
 		}
 		entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
-		if Bool(test.Properties.Test_options.Unit_test) {
-			entries.SetBool("LOCAL_IS_UNIT_TEST", true)
-		}
 
 		entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory))
 		if len(test.Properties.Data_bins) > 0 {
 			entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
 		}
+
+		test.Properties.Test_options.CommonTestOptions.SetAndroidMkEntries(entries)
 	})
 
 	AndroidMkWriteTestData(test.data, entries)
@@ -616,6 +626,24 @@
 	androidMkWriteAllowUndefinedSymbols(p.baseLinker, entries)
 }
 
+func (a *apiLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "SHARED_LIBRARIES"
+	entries.SubName += multitree.GetApiImportSuffix()
+
+	entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		a.libraryDecorator.androidMkWriteExportedFlags(entries)
+		src := *a.properties.Src
+		path, file := filepath.Split(src)
+		stem, suffix, ext := android.SplitFileExt(file)
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+		entries.SetString("LOCAL_MODULE_PATH", path)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+		entries.SetString("LOCAL_SOONG_TOC", a.toc().String())
+	})
+}
+
 func androidMkWriteAllowUndefinedSymbols(linker *baseLinker, entries *android.AndroidMkEntries) {
 	allow := linker.Properties.Allow_undefined_symbols
 	if allow != nil {
diff --git a/cc/binary.go b/cc/binary.go
index b2f2482..849aafa 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -617,6 +617,7 @@
 		Dynamic_deps:       baseAttrs.implementationDynamicDeps,
 		Whole_archive_deps: baseAttrs.wholeArchiveDeps,
 		System_deps:        baseAttrs.systemDynamicDeps,
+		Runtime_deps:       baseAttrs.runtimeDeps,
 
 		Local_includes:    baseAttrs.localIncludes,
 		Absolute_includes: baseAttrs.absoluteIncludes,
@@ -667,6 +668,7 @@
 	Dynamic_deps       bazel.LabelListAttribute
 	Whole_archive_deps bazel.LabelListAttribute
 	System_deps        bazel.LabelListAttribute
+	Runtime_deps       bazel.LabelListAttribute
 
 	Local_includes    bazel.StringListAttribute
 	Absolute_includes bazel.StringListAttribute
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 6cd6733..625e7ce 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
@@ -30,20 +30,23 @@
 const (
 	cSrcPartition     = "c"
 	asSrcPartition    = "as"
+	asmSrcPartition   = "asm"
 	lSrcPartition     = "l"
 	llSrcPartition    = "ll"
 	cppSrcPartition   = "cpp"
 	protoSrcPartition = "proto"
+	aidlSrcPartition  = "aidl"
 )
 
 // staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
 // properties which apply to either the shared or static version of a cc_library module.
 type staticOrSharedAttributes struct {
-	Srcs    bazel.LabelListAttribute
-	Srcs_c  bazel.LabelListAttribute
-	Srcs_as bazel.LabelListAttribute
-	Hdrs    bazel.LabelListAttribute
-	Copts   bazel.StringListAttribute
+	Srcs      bazel.LabelListAttribute
+	Srcs_c    bazel.LabelListAttribute
+	Srcs_as   bazel.LabelListAttribute
+	Srcs_aidl bazel.LabelListAttribute
+	Hdrs      bazel.LabelListAttribute
+	Copts     bazel.StringListAttribute
 
 	Deps                              bazel.LabelListAttribute
 	Implementation_deps               bazel.LabelListAttribute
@@ -51,6 +54,7 @@
 	Implementation_dynamic_deps       bazel.LabelListAttribute
 	Whole_archive_deps                bazel.LabelListAttribute
 	Implementation_whole_archive_deps bazel.LabelListAttribute
+	Runtime_deps                      bazel.LabelListAttribute
 
 	System_dynamic_deps bazel.LabelListAttribute
 
@@ -66,10 +70,17 @@
 	// Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl
 	// macro.
 	addSuffixForFilegroup := func(suffix string) bazel.LabelMapper {
-		return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
-			m, exists := ctx.ModuleFromName(label.OriginalModuleName)
+		return func(otherModuleCtx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+
+			m, exists := otherModuleCtx.ModuleFromName(label.OriginalModuleName)
 			labelStr := label.Label
-			if !exists || !android.IsFilegroup(ctx, m) {
+			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) {
 				return labelStr, false
 			}
 			return labelStr + suffix, true
@@ -81,6 +92,8 @@
 		protoSrcPartition: android.ProtoSrcLabelPartition,
 		cSrcPartition:     bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")},
 		asSrcPartition:    bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")},
+		asmSrcPartition:   bazel.LabelPartition{Extensions: []string{".asm"}},
+		aidlSrcPartition:  android.AidlSrcLabelPartition,
 		// TODO(http://b/231968910): If there is ever a filegroup target that
 		// 		contains .l or .ll files we will need to find a way to add a
 		// 		LabelMapper for these that identifies these filegroups and
@@ -279,7 +292,10 @@
 	compilerAttributes
 	linkerAttributes
 
+	// A combination of compilerAttributes.features and linkerAttributes.features
+	features        bazel.StringListAttribute
 	protoDependency *bazel.LabelAttribute
+	aidlDependency  *bazel.LabelAttribute
 }
 
 // Convenience struct to hold all attributes parsed from compiler properties.
@@ -289,6 +305,7 @@
 	// Assembly options and sources
 	asFlags bazel.StringListAttribute
 	asSrcs  bazel.LabelListAttribute
+	asmSrcs bazel.LabelListAttribute
 	// C options and sources
 	conlyFlags bazel.StringListAttribute
 	cSrcs      bazel.LabelListAttribute
@@ -316,9 +333,12 @@
 	includes BazelIncludes
 
 	protoSrcs bazel.LabelListAttribute
+	aidlSrcs  bazel.LabelListAttribute
 
 	stubsSymbolFile *string
 	stubsVersions   bazel.StringListAttribute
+
+	features bazel.StringListAttribute
 }
 
 type filterOutFn func(string) bool
@@ -382,6 +402,13 @@
 	ca.absoluteIncludes.SetSelectValue(axis, config, props.Include_dirs)
 	ca.localIncludes.SetSelectValue(axis, config, localIncludeDirs)
 
+	instructionSet := proptools.StringDefault(props.Instruction_set, "")
+	if instructionSet == "arm" {
+		ca.features.SetSelectValue(axis, config, []string{"arm_isa_arm", "-arm_isa_thumb"})
+	} else if instructionSet != "" && instructionSet != "thumb" {
+		ctx.ModuleErrorf("Unknown value for instruction_set: %s", instructionSet)
+	}
+
 	// In Soong, cflags occur on the command line before -std=<val> flag, resulting in the value being
 	// overridden. In Bazel we always allow overriding, via flags; however, this can cause
 	// incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
@@ -434,6 +461,7 @@
 	partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs)
 
 	ca.protoSrcs = partitionedSrcs[protoSrcPartition]
+	ca.aidlSrcs = partitionedSrcs[aidlSrcPartition]
 
 	for p, lla := range partitionedSrcs {
 		// if there are no sources, there is no need for headers
@@ -447,6 +475,7 @@
 	ca.srcs = partitionedSrcs[cppSrcPartition]
 	ca.cSrcs = partitionedSrcs[cSrcPartition]
 	ca.asSrcs = partitionedSrcs[asSrcPartition]
+	ca.asmSrcs = partitionedSrcs[asmSrcPartition]
 	ca.lSrcs = partitionedSrcs[lSrcPartition]
 	ca.llSrcs = partitionedSrcs[llSrcPartition]
 
@@ -465,12 +494,27 @@
 	}
 
 	allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, props.Srcs, props.Exclude_srcs)
+
 	if len(props.Srcs) > 0 || len(props.Exclude_srcs) > 0 {
 		anySrcs = true
 	}
+
 	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.
@@ -527,6 +571,61 @@
 	return relative, absolute
 }
 
+type YasmAttributes struct {
+	Srcs         bazel.LabelListAttribute
+	Flags        bazel.StringListAttribute
+	Include_dirs bazel.StringListAttribute
+}
+
+func bp2BuildYasm(ctx android.Bp2buildMutatorContext, m *Module, ca compilerAttributes) *bazel.LabelAttribute {
+	if ca.asmSrcs.IsEmpty() {
+		return nil
+	}
+
+	// Yasm needs the include directories from both local_includes and
+	// export_include_dirs. We don't care about actually exporting them from the
+	// yasm rule though, because they will also be present on the cc_ rule that
+	// wraps this yasm rule.
+	includes := ca.localIncludes.Clone()
+	bp2BuildPropParseHelper(ctx, m, &FlagExporterProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
+		if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
+			if len(flagExporterProperties.Export_include_dirs) > 0 {
+				x := bazel.StringListAttribute{}
+				x.SetSelectValue(axis, config, flagExporterProperties.Export_include_dirs)
+				includes.Append(x)
+			}
+		}
+	})
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "yasm",
+			Bzl_load_location: "//build/bazel/rules/cc:yasm.bzl",
+		},
+		android.CommonAttributes{Name: m.Name() + "_yasm"},
+		&YasmAttributes{
+			Srcs:         ca.asmSrcs,
+			Flags:        ca.asFlags,
+			Include_dirs: *includes,
+		})
+
+	// We only want to add a dependency on the _yasm target if there are asm
+	// sources in the current configuration. If there are unconfigured asm
+	// sources, always add the dependency. Otherwise, add the dependency only
+	// on the configuration axes and values that had asm sources.
+	if len(ca.asmSrcs.Value.Includes) > 0 {
+		return bazel.MakeLabelAttribute(":" + m.Name() + "_yasm")
+	}
+
+	ret := &bazel.LabelAttribute{}
+	for _, axis := range ca.asmSrcs.SortedConfigurationAxes() {
+		for config := range ca.asmSrcs.ConfigurableValues[axis] {
+			ret.SetSelectValue(axis, config, bazel.Label{Label: ":" + m.Name() + "_yasm"})
+		}
+	}
+	return ret
+}
+
 // bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module..
 func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
 	archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
@@ -582,9 +681,12 @@
 			includes, absoluteIncludes := includesFromLabelList(headers.implementation)
 			currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, config)
 			currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...))
+
 			compilerAttrs.absoluteIncludes.SetSelectValue(axis, config, currAbsoluteIncludes)
+
 			currIncludes := compilerAttrs.localIncludes.SelectValue(axis, config)
 			currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...))
+
 			compilerAttrs.localIncludes.SetSelectValue(axis, config, currIncludes)
 
 			if libraryProps, ok := archVariantLibraryProperties[axis][config].(*LibraryProperties); ok {
@@ -595,6 +697,7 @@
 			}
 		}
 	}
+
 	compilerAttrs.convertStlProps(ctx, module)
 	(&linkerAttrs).convertStripProps(ctx, module)
 
@@ -612,25 +715,109 @@
 	(&compilerAttrs).finalize(ctx, implementationHdrs)
 	(&linkerAttrs).finalize(ctx)
 
+	(&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs))
+
 	protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
+	aidlDep := bp2buildCcAidlLibrary(ctx, module, compilerAttrs.aidlSrcs)
 
 	// bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know
 	// which. This will add the newly generated proto library to the appropriate attribute and nothing
 	// to the other
 	(&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib)
 	(&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib)
+	// TODO(b/243023967) Add aidlDep to implementationWholeArchiveDeps if aidl.export_aidl_headers is true
+	(&linkerAttrs).wholeArchiveDeps.Add(aidlDep)
 
 	convertedLSrcs := bp2BuildLex(ctx, module.Name(), compilerAttrs)
 	(&compilerAttrs).srcs.Add(&convertedLSrcs.srcName)
 	(&compilerAttrs).cSrcs.Add(&convertedLSrcs.cSrcName)
 
+	features := compilerAttrs.features.Clone().Append(linkerAttrs.features)
+	features.DeduplicateAxesFromBase()
+
 	return baseAttributes{
 		compilerAttrs,
 		linkerAttrs,
+		*features,
 		protoDep.protoDep,
+		aidlDep,
 	}
 }
 
+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,
+) *bazel.LabelAttribute {
+	suffix := "_cc_aidl_library"
+	ccAidlLibrarylabel := m.Name() + suffix
+
+	aidlLibraries := bp2buildAidlLibraries(ctx, m, aidlSrcs)
+
+	if aidlLibraries.IsEmpty() {
+		return nil
+	}
+
+	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
+}
+
 func bp2BuildParseSdkAttributes(module *Module) sdkAttributes {
 	return sdkAttributes{
 		Sdk_version:     module.Properties.Sdk_version,
@@ -649,6 +836,7 @@
 	implementationDeps               bazel.LabelListAttribute
 	dynamicDeps                      bazel.LabelListAttribute
 	implementationDynamicDeps        bazel.LabelListAttribute
+	runtimeDeps                      bazel.LabelListAttribute
 	wholeArchiveDeps                 bazel.LabelListAttribute
 	implementationWholeArchiveDeps   bazel.LabelListAttribute
 	systemDynamicDeps                bazel.LabelListAttribute
@@ -716,6 +904,45 @@
 	sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes(ctx, !isBinary, sharedLibs, props.Exclude_shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDepsExcludes)
 	la.dynamicDeps.SetSelectValue(axis, config, sharedDeps.export)
 	la.implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation)
+	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
+		// OsConfigurationAxis/OsAndroid are grouped by having stubs or not, so Bazel select()
+		// statement can be used to choose source/stub variants of them.
+		depsWithStubs := []bazel.Label{}
+		for _, l := range sharedDeps.implementation.Includes {
+			dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
+			if m, ok := dep.(*Module); ok && m.HasStubsVariants() {
+				depsWithStubs = append(depsWithStubs, l)
+			}
+		}
+		if len(depsWithStubs) > 0 {
+			implDynamicDeps := bazel.SubtractBazelLabelList(sharedDeps.implementation, bazel.MakeLabelList(depsWithStubs))
+			la.implementationDynamicDeps.SetSelectValue(axis, config, implDynamicDeps)
+
+			stubLibLabels := []bazel.Label{}
+			for _, l := range depsWithStubs {
+				l.Label = l.Label + "_stub_libs_current"
+				stubLibLabels = append(stubLibLabels, l)
+			}
+			inApexSelectValue := la.implementationDynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
+			nonApexSelectValue := la.implementationDynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
+			defaultSelectValue := la.implementationDynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
+			if axis == bazel.NoConfigAxis {
+				(&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)
+			} 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)
+			}
+		}
+	}
 
 	if !BoolDefault(props.Pack_relocations, packRelocationsDefault) {
 		axisFeatures = append(axisFeatures, "disable_pack_relocations")
@@ -764,6 +991,11 @@
 	if axisFeatures != nil {
 		la.features.SetSelectValue(axis, config, axisFeatures)
 	}
+
+	runtimeDeps := android.BazelLabelForModuleDepsExcludes(ctx, props.Runtime_libs, props.Exclude_runtime_libs)
+	if !runtimeDeps.IsEmpty() {
+		la.runtimeDeps.SetSelectValue(axis, config, runtimeDeps)
+	}
 }
 
 func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
@@ -915,7 +1147,7 @@
 
 func bazelLabelForStaticModule(ctx android.BazelConversionPathContext, m blueprint.Module) string {
 	label := android.BazelModuleLabel(ctx, m)
-	if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary && !android.GenerateCcLibraryStaticOnly(m.Name()) {
+	if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary && !android.GetBp2BuildAllowList().GenerateCcLibraryStaticOnly(m.Name()) {
 		label += "_bp2build_cc_library_static"
 	}
 	return label
diff --git a/cc/builder.go b/cc/builder.go
index ab2b80a..35ae69b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -282,7 +282,7 @@
 	sAbiDiff = pctx.RuleFunc("sAbiDiff",
 		func(ctx android.PackageRuleContext) blueprint.RuleParams {
 			commandStr := "($sAbiDiffer ${extraFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})"
-			commandStr += "|| (echo 'error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py ${createReferenceDumpFlags} -l ${libName}'"
+			commandStr += "|| (echo '${errorMessage}'"
 			commandStr += " && (mkdir -p $$DIST_DIR/abidiffs && cp ${out} $$DIST_DIR/abidiffs/)"
 			commandStr += " && exit 1)"
 			return blueprint.RuleParams{
@@ -290,7 +290,7 @@
 				CommandDeps: []string{"$sAbiDiffer"},
 			}
 		},
-		"extraFlags", "referenceDump", "libName", "arch", "createReferenceDumpFlags")
+		"extraFlags", "referenceDump", "libName", "arch", "errorMessage")
 
 	// Rule to unzip a reference abi dump.
 	unzipRefSAbiDump = pctx.AndroidStaticRule("unzipRefSAbiDump",
@@ -920,10 +920,15 @@
 
 // sourceAbiDiff registers a build statement to compare linked sAbi dump files (.lsdump).
 func sourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
-	baseName, exportedHeaderFlags string, diffFlags []string,
-	checkAllApis, isLlndk, isNdk, isVndkExt bool) android.OptionalPath {
+	baseName, prevVersion, exportedHeaderFlags string, diffFlags []string,
+	checkAllApis, isLlndk, isNdk, isVndkExt, previousVersionDiff bool) android.OptionalPath {
 
-	outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
+	var outputFile android.ModuleOutPath
+	if prevVersion == "" {
+		outputFile = android.PathForModuleOut(ctx, baseName+".abidiff")
+	} else {
+		outputFile = android.PathForModuleOut(ctx, baseName+"."+prevVersion+".abidiff")
+	}
 	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
 
 	var extraFlags []string
@@ -935,10 +940,27 @@
 			"-allow-unreferenced-elf-symbol-changes")
 	}
 
+	var errorMessage string
+	// When error occurs in previous version ABI diff, Developers can't just update ABI
+	// reference but need to follow instructions to ensure ABI backward compatibility.
+	if previousVersionDiff {
+		// TODO(b/241496591): Remove -advice-only after b/239792343 and b/239790286 are reolved.
+		extraFlags = append(extraFlags, "-advice-only")
+		errorMessage = "error: Please follow development/vndk/tools/header-checker/README.md to ensure the ABI compatibility between your source code and version " + prevVersion + "."
+		// The prevVersion is expected as a string of int, skip it if not.
+		if prevVersionInt, err := strconv.Atoi(prevVersion); err == nil {
+			sourceVersion := strconv.Itoa(prevVersionInt + 1)
+			extraFlags = append(extraFlags, "-target-version", sourceVersion)
+		}
+	} else {
+		errorMessage = "error: Please update ABI references with: $ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName
+		extraFlags = append(extraFlags, "-target-version", "current")
+	}
+
 	if isLlndk || isNdk {
 		extraFlags = append(extraFlags, "-consider-opaque-types-different")
 	}
-	if isVndkExt {
+	if isVndkExt || previousVersionDiff {
 		extraFlags = append(extraFlags, "-allow-extensions")
 	}
 	// TODO(b/232891473): Simplify the above logic with diffFlags.
@@ -951,11 +973,11 @@
 		Input:       inputDump,
 		Implicit:    referenceDump,
 		Args: map[string]string{
-			"referenceDump":            referenceDump.String(),
-			"libName":                  libName,
-			"arch":                     ctx.Arch().ArchType.Name,
-			"extraFlags":               strings.Join(extraFlags, " "),
-			"createReferenceDumpFlags": "",
+			"referenceDump": referenceDump.String(),
+			"libName":       libName,
+			"arch":          ctx.Arch().ArchType.Name,
+			"extraFlags":    strings.Join(extraFlags, " "),
+			"errorMessage":  errorMessage,
 		},
 	})
 	return android.OptionalPathForPath(outputFile)
diff --git a/cc/cc.go b/cc/cc.go
index bc95813..f1e9bf6 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -31,6 +31,7 @@
 	"android/soong/cc/config"
 	"android/soong/fuzz"
 	"android/soong/genrule"
+	"android/soong/multitree"
 	"android/soong/snapshot"
 )
 
@@ -62,7 +63,6 @@
 		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
 
 		ctx.TopDown("fuzz_deps", fuzzMutatorDeps)
-		ctx.BottomUp("fuzz", fuzzMutator)
 
 		ctx.BottomUp("coverage", coverageMutator).Parallel()
 
@@ -514,6 +514,7 @@
 	getVndkExtendsModuleName() string
 	isAfdoCompile() bool
 	isPgoCompile() bool
+	isCfi() bool
 	isNDKStubLibrary() bool
 	useClangLld(actx ModuleContext) bool
 	isForPlatform() bool
@@ -1314,6 +1315,13 @@
 	return false
 }
 
+func (c *Module) isCfi() bool {
+	if sanitize := c.sanitize; sanitize != nil {
+		return Bool(sanitize.Properties.Sanitize.Cfi)
+	}
+	return false
+}
+
 func (c *Module) isNDKStubLibrary() bool {
 	if _, ok := c.compiler.(*stubDecorator); ok {
 		return true
@@ -1592,6 +1600,10 @@
 	return ctx.mod.isPgoCompile()
 }
 
+func (ctx *moduleContextImpl) isCfi() bool {
+	return ctx.mod.isCfi()
+}
+
 func (ctx *moduleContextImpl) isNDKStubLibrary() bool {
 	return ctx.mod.isNDKStubLibrary()
 }
@@ -1888,6 +1900,8 @@
 
 	if c.Properties.Clang != nil && *c.Properties.Clang == false {
 		ctx.PropertyErrorf("clang", "false (GCC) is no longer supported")
+	} else if c.Properties.Clang != nil && !ctx.DeviceConfig().BuildBrokenClangProperty() {
+		ctx.PropertyErrorf("clang", "property is deprecated, see Changes.md file")
 	}
 
 	flags := Flags{
@@ -2184,6 +2198,24 @@
 	}
 }
 
+func GetApiImports(c LinkableInterface, actx android.BottomUpMutatorContext) multitree.ApiImportInfo {
+	apiImportInfo := multitree.ApiImportInfo{}
+
+	if c.Device() {
+		var apiImportModule []blueprint.Module
+		if actx.OtherModuleExists("api_imports") {
+			apiImportModule = actx.AddDependency(c, nil, "api_imports")
+			if len(apiImportModule) > 0 && apiImportModule[0] != nil {
+				apiInfo := actx.OtherModuleProvider(apiImportModule[0], multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+				apiImportInfo = apiInfo
+				actx.SetProvider(multitree.ApiImportsProvider, apiInfo)
+			}
+		}
+	}
+
+	return apiImportInfo
+}
+
 func GetSnapshot(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext) SnapshotInfo {
 	// Only device modules with BOARD_VNDK_VERSION uses snapshot.  Others use the zero value of
 	// SnapshotInfo, which provides no mappings.
@@ -2209,8 +2241,8 @@
 	return **snapshotInfo
 }
 
-func RewriteSnapshotLib(lib string, snapshotMap map[string]string) string {
-	if snapshot, ok := snapshotMap[lib]; ok {
+func GetReplaceModuleName(lib string, replaceMap map[string]string) string {
+	if snapshot, ok := replaceMap[lib]; ok {
 		return snapshot
 	}
 
@@ -2221,13 +2253,18 @@
 // of names:
 //
 // 1. Name of an NDK library that refers to a prebuilt module.
-//    For each of these, it adds the name of the prebuilt module (which will be in
-//    prebuilts/ndk) to the list of nonvariant libs.
+//
+//	For each of these, it adds the name of the prebuilt module (which will be in
+//	prebuilts/ndk) to the list of nonvariant libs.
+//
 // 2. Name of an NDK library that refers to an ndk_library module.
-//    For each of these, it adds the name of the ndk_library module to the list of
-//    variant libs.
+//
+//	For each of these, it adds the name of the ndk_library module to the list of
+//	variant libs.
+//
 // 3. Anything else (so anything that isn't an NDK library).
-//    It adds these to the nonvariantLibs list.
+//
+//	It adds these to the nonvariantLibs list.
 //
 // The caller can then know to add the variantLibs dependencies differently from the
 // nonvariantLibs
@@ -2239,11 +2276,11 @@
 		// strip #version suffix out
 		name, _ := StubsLibNameAndVersion(entry)
 		if c.InRecovery() {
-			nonvariantLibs = append(nonvariantLibs, RewriteSnapshotLib(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
+			nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
 		} else if c.UseSdk() && inList(name, *getNDKKnownLibs(config)) {
 			variantLibs = append(variantLibs, name+ndkLibrarySuffix)
 		} else if c.UseVndk() {
-			nonvariantLibs = append(nonvariantLibs, RewriteSnapshotLib(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
+			nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
 		} else {
 			// put name#version back
 			nonvariantLibs = append(nonvariantLibs, entry)
@@ -2252,6 +2289,25 @@
 	return nonvariantLibs, variantLibs
 }
 
+func updateDepsWithApiImports(deps Deps, apiImports multitree.ApiImportInfo) Deps {
+	for idx, lib := range deps.SharedLibs {
+		deps.SharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+	}
+
+	for idx, lib := range deps.LateSharedLibs {
+		deps.LateSharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+	}
+
+	for idx, lib := range deps.RuntimeLibs {
+		deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+	}
+
+	for idx, lib := range deps.HeaderLibs {
+		deps.HeaderLibs[idx] = GetReplaceModuleName(lib, apiImports.HeaderLibs)
+	}
+	return deps
+}
+
 func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
 	if !c.Enabled() {
 		return
@@ -2267,6 +2323,9 @@
 
 	deps := c.deps(ctx)
 
+	apiImportInfo := GetApiImports(c, actx)
+	deps = updateDepsWithApiImports(deps, apiImportInfo)
+
 	c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
 
 	var snapshotInfo *SnapshotInfo
@@ -2279,7 +2338,7 @@
 		deps.ReexportSharedLibHeaders, _ = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.ReexportSharedLibHeaders)
 
 		for idx, lib := range deps.RuntimeLibs {
-			deps.RuntimeLibs[idx] = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs)
+			deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs)
 		}
 	}
 
@@ -2289,7 +2348,7 @@
 			depTag.reexportFlags = true
 		}
 
-		lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
+		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
 
 		if c.IsStubs() {
 			actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()),
@@ -2302,10 +2361,20 @@
 	if c.isNDKStubLibrary() {
 		// NDK stubs depend on their implementation because the ABI dumps are
 		// generated from the implementation library.
-		actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
-			c.ImageVariation(),
-			blueprint.Variation{Mutator: "link", Variation: "shared"},
-		), stubImplementation, c.BaseModuleName())
+		apiImportName := c.BaseModuleName() + multitree.GetApiImportSuffix()
+
+		// If original library exists as imported API, set dependency on the imported library
+		if actx.OtherModuleExists(apiImportName) {
+			actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+				c.ImageVariation(),
+				blueprint.Variation{Mutator: "link", Variation: "shared"},
+			), stubImplementation, apiImportName)
+		} else {
+			actx.AddFarVariationDependencies(append(ctx.Target().Variations(),
+				c.ImageVariation(),
+				blueprint.Variation{Mutator: "link", Variation: "shared"},
+			), stubImplementation, c.BaseModuleName())
+		}
 	}
 
 	// sysprop_library has to support both C++ and Java. So sysprop_library internally creates one
@@ -2321,7 +2390,7 @@
 			lib = impl
 		}
 
-		lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
+		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
 
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
@@ -2341,7 +2410,7 @@
 			lib = impl
 		}
 
-		lib = RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
+		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
 
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
@@ -2355,7 +2424,7 @@
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true}
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, depTag, RewriteSnapshotLib(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+		}, depTag, GetReplaceModuleName(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
 	}
 
 	// shared lib names without the #version suffix
@@ -2387,14 +2456,14 @@
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency}
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, depTag, RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+		}, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
 	}
 
 	for _, lib := range deps.UnexportedStaticLibs {
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency, unexportedSymbols: true}
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, depTag, RewriteSnapshotLib(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+		}, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
 	}
 
 	for _, lib := range deps.LateSharedLibs {
@@ -2435,11 +2504,11 @@
 	actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...)
 	for _, crt := range deps.CrtBegin {
 		actx.AddVariationDependencies(crtVariations, CrtBeginDepTag,
-			RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+			GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
 	}
 	for _, crt := range deps.CrtEnd {
 		actx.AddVariationDependencies(crtVariations, CrtEndDepTag,
-			RewriteSnapshotLib(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+			GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
 	}
 	if deps.DynamicLinker != "" {
 		actx.AddDependency(c, dynamicLinkerDepTag, deps.DynamicLinker)
@@ -2464,7 +2533,7 @@
 			actx.AddVariationDependencies([]blueprint.Variation{
 				c.ImageVariation(),
 				{Mutator: "link", Variation: "shared"},
-			}, vndkExtDepTag, RewriteSnapshotLib(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
+			}, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
 		}
 	}
 }
@@ -3186,6 +3255,11 @@
 
 			return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix()
 		}
+
+		// Remove API import suffix if exists
+		if _, ok := ccDepModule.linker.(*apiLibraryDecorator); ok {
+			libName = strings.TrimSuffix(libName, multitree.GetApiImportSuffix())
+		}
 	}
 
 	if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() &&
@@ -3521,6 +3595,10 @@
 	if _, ok := c.linker.(prebuiltLinkerInterface); ok {
 		return nil
 	}
+	if _, ok := c.linker.(*apiLibraryDecorator); ok {
+		return nil
+	}
+
 	minSdkVersion := c.MinSdkVersion()
 	if minSdkVersion == "apex_inherit" {
 		return nil
@@ -3638,9 +3716,7 @@
 	}
 }
 
-//
 // Defaults
-//
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 24732bf..5d569cc 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
 	"path/filepath"
 	"reflect"
 	"regexp"
+	"runtime"
 	"strings"
 	"testing"
 
@@ -3342,9 +3343,9 @@
 	`)
 }
 
-func TestAFLFuzzTarget(t *testing.T) {
-	ctx := testCc(t, `
-		cc_afl_fuzz {
+func VerifyAFLFuzzTargetVariant(t *testing.T, variant string) {
+	bp := `
+		cc_fuzz {
 			name: "test_afl_fuzz_target",
 			srcs: ["foo.c"],
 			host_supported: true,
@@ -3354,17 +3355,10 @@
 			shared_libs: [
 				"afl_fuzz_shared_lib",
 			],
-		}
-		cc_fuzz {
-			name: "test_fuzz_target",
-			srcs: ["foo.c"],
-			static_libs: [
-				"afl_fuzz_static_lib",
-				"libfuzzer_only_static_lib",
-			],
-			shared_libs: [
-				"afl_fuzz_shared_lib",
-			],
+			fuzzing_frameworks: {
+				afl: true,
+				libfuzzer: false,
+			},
 		}
 		cc_library {
 			name: "afl_fuzz_static_lib",
@@ -3409,12 +3403,19 @@
 			host_supported: true,
 			srcs: ["second_file.c"],
 		}
-		filegroup {
+		cc_object {
 			name: "aflpp_driver",
+			host_supported: true,
 			srcs: [
 				"aflpp_driver.c",
 			],
-		}`)
+		}`
+
+	testEnv := map[string]string{
+		"FUZZ_FRAMEWORK": "AFL",
+	}
+
+	ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp)
 
 	checkPcGuardFlag := func(
 		modName string, variantName string, shouldHave bool) {
@@ -3434,31 +3435,33 @@
 		}
 	}
 
-	for _, vnt := range ctx.ModuleVariantsForTests("libfuzzer_only_static_lib") {
-		if strings.Contains(vnt, "fuzzer_afl") {
-			t.Errorf("libfuzzer_only_static_lib has afl variant and should not")
-		}
-	}
-
 	moduleName := "test_afl_fuzz_target"
-	variantName := "android_arm64_armv8-a_fuzzer_afl"
-	checkPcGuardFlag(moduleName, variantName, true)
+	checkPcGuardFlag(moduleName, variant+"_fuzzer", true)
 
 	moduleName = "afl_fuzz_static_lib"
-	variantName = "android_arm64_armv8-a_static"
-	checkPcGuardFlag(moduleName, variantName, false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer", false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer_afl", true)
+	checkPcGuardFlag(moduleName, variant+"_static", false)
+	checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
 
 	moduleName = "second_static_lib"
-	checkPcGuardFlag(moduleName, variantName, false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer", false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer_afl", true)
+	checkPcGuardFlag(moduleName, variant+"_static", false)
+	checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
 
 	ctx.ModuleForTests("afl_fuzz_shared_lib",
 		"android_arm64_armv8-a_shared").Rule("cc")
 	ctx.ModuleForTests("afl_fuzz_shared_lib",
-		"android_arm64_armv8-a_shared_fuzzer_afl").Rule("cc")
+		"android_arm64_armv8-a_shared_fuzzer").Rule("cc")
+}
+
+func TestAFLFuzzTargetForDevice(t *testing.T) {
+	VerifyAFLFuzzTargetVariant(t, "android_arm64_armv8-a")
+}
+
+func TestAFLFuzzTargetForLinuxHost(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("requires linux")
+	}
+
+	VerifyAFLFuzzTargetVariant(t, "linux_glibc_x86_64")
 }
 
 // Simple smoke test for the cc_fuzz target that ensures the rule compiles
@@ -4108,7 +4111,7 @@
 			name: "libfoo",
 			srcs: [
 				"foo.c",
-				"a.sysprop",
+				"path/to/a.sysprop",
 				"b.aidl",
 				"a.proto",
 			],
@@ -4121,11 +4124,11 @@
 			`),
 			expectedSystemIncludeDirs(``),
 			expectedGeneratedHeaders(`
-				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include/a.sysprop.h
+				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include/path/to/a.sysprop.h
 			`),
 			expectedOrderOnlyDeps(`
-				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include/a.sysprop.h
-				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/public/include/a.sysprop.h
+				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include/path/to/a.sysprop.h
+				.intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/public/include/path/to/a.sysprop.h
 			`),
 		)
 	})
@@ -4142,7 +4145,7 @@
 		"${config.ArmArmv7ANeonCflags}",
 		"${config.ArmGenericCflags}",
 		"-target",
-		"armv7a-linux-androideabi20",
+		"armv7a-linux-androideabi21",
 	}
 
 	expectedIncludes := []string{
@@ -4173,7 +4176,6 @@
 		"external/foo/lib32",
 		"external/foo/libandroid_arm",
 		"defaults/cc/common/ndk_libc++_shared",
-		"defaults/cc/common/ndk_libandroid_support",
 	}
 
 	conly := []string{"-fPIC", "${config.CommonGlobalConlyflags}"}
@@ -4266,20 +4268,20 @@
 				},
 			},
 			stl: "libc++",
-			sdk_version: "20",
+			sdk_version: "minimum",
 		}
 
 		cc_library_headers {
 			name: "libheader1",
 			export_include_dirs: ["libheader1"],
-			sdk_version: "20",
+			sdk_version: "minimum",
 			stl: "none",
 		}
 
 		cc_library_headers {
 			name: "libheader2",
 			export_include_dirs: ["libheader2"],
-			sdk_version: "20",
+			sdk_version: "minimum",
 			stl: "none",
 		}
 	`, tc.src)
@@ -4303,7 +4305,7 @@
 			cc_library {
 				name: "%s",
 				export_include_dirs: ["%s"],
-				sdk_version: "20",
+				sdk_version: "minimum",
 				stl: "none",
 			}
 		`, lib, lib)
@@ -4334,3 +4336,53 @@
 	}
 
 }
+
+func TestCcBuildBrokenClangProperty(t *testing.T) {
+	tests := []struct {
+		name                     string
+		clang                    bool
+		BuildBrokenClangProperty bool
+		err                      string
+	}{
+		{
+			name:  "error when clang is set to false",
+			clang: false,
+			err:   "is no longer supported",
+		},
+		{
+			name:  "error when clang is set to true",
+			clang: true,
+			err:   "property is deprecated, see Changes.md",
+		},
+		{
+			name:                     "no error when BuildBrokenClangProperty is explicitly set to true",
+			clang:                    true,
+			BuildBrokenClangProperty: true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			bp := fmt.Sprintf(`
+			cc_library {
+			   name: "foo",
+			   clang: %t,
+			}`, test.clang)
+
+			if test.err == "" {
+				android.GroupFixturePreparers(
+					prepareForCcTest,
+					android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+						if test.BuildBrokenClangProperty {
+							variables.BuildBrokenClangProperty = test.BuildBrokenClangProperty
+						}
+					}),
+				).RunTestWithBp(t, bp)
+			} else {
+				prepareForCcTest.
+					ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(test.err)).
+					RunTestWithBp(t, bp)
+			}
+		})
+	}
+}
diff --git a/cc/config/global.go b/cc/config/global.go
index 26d93ab..357ea44 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -59,6 +59,10 @@
 		"-Werror=string-plus-int",
 		"-Werror=unreachable-code-loop-increment",
 
+		// Force deprecation warnings to be warnings for code that compiles with -Werror.
+		// Making deprecated usages an error causes extreme pain when trying to deprecate anything.
+		"-Wno-error=deprecated-declarations",
+
 		"-D__compiler_offsetof=__builtin_offsetof",
 
 		// Emit address-significance table which allows linker to perform safe ICF. Clang does
@@ -286,8 +290,7 @@
 		"-Wno-deprecated-non-prototype",
 	}
 
-	llvmNextExtraCommonGlobalCflags = []string{
-	}
+	llvmNextExtraCommonGlobalCflags = []string{}
 
 	IllegalFlags = []string{
 		"-w",
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index 674edad..232e686 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -37,16 +37,22 @@
 		// http://b/216364337 - TODO: Follow-up after compiler update to
 		// disable or fix individual instances.
 		"-cert-err33-c",
+		// http://b/241125373
+		"-bugprone-unchecked-optional-access",
 	}
 
 	// Some clang-tidy checks are included in some tidy_checks_as_errors lists,
 	// but not all warnings are fixed/suppressed yet. These checks are not
 	// disabled in the TidyGlobalNoChecks list, so we can see them and fix/suppress them.
 	globalNoErrorCheckList = []string{
-		// http://b/155034563
-		"-bugprone-signed-char-misuse",
+		// http://b/241997913
+		"-bugprone-assignment-in-if-condition",
 		// http://b/155034972
 		"-bugprone-branch-clone",
+		// http://b/155034563
+		"-bugprone-signed-char-misuse",
+		// http://b/241819232
+		"-misc-const-correctness",
 	}
 )
 
@@ -80,8 +86,10 @@
 			"misc-*",
 			"performance-*",
 			"portability-*",
+			"-bugprone-assignment-in-if-condition",
 			"-bugprone-easily-swappable-parameters",
 			"-bugprone-narrowing-conversions",
+			"-misc-const-correctness",
 			"-misc-no-recursion",
 			"-misc-non-private-member-variables-in-classes",
 			"-misc-unused-parameters",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index d6af97f..8a8c107 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -27,15 +27,12 @@
 )
 
 func init() {
-	android.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
 	android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
 	android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
-	android.RegisterSingletonType("cc_afl_fuzz_packaging", fuzzAFLPackagingFactory)
 }
 
 type FuzzProperties struct {
-	AFLEnabled  bool `blueprint:"mutated"`
-	AFLAddFlags bool `blueprint:"mutated"`
+	FuzzFramework fuzz.Framework `blueprint:"mutated"`
 }
 
 type fuzzer struct {
@@ -43,8 +40,13 @@
 }
 
 func (fuzzer *fuzzer) flags(ctx ModuleContext, flags Flags) Flags {
-	if fuzzer.Properties.AFLAddFlags {
-		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-coverage=trace-pc-guard")
+	if fuzzer.Properties.FuzzFramework == fuzz.AFL {
+		flags.Local.CFlags = append(flags.Local.CFlags, []string{
+			"-fsanitize-coverage=trace-pc-guard",
+			"-Wno-unused-result",
+			"-Wno-unused-parameter",
+			"-Wno-unused-function",
+		}...)
 	}
 
 	return flags
@@ -60,7 +62,7 @@
 		return
 	}
 
-	if currentModule.fuzzer == nil || !currentModule.fuzzer.Properties.AFLEnabled {
+	if currentModule.fuzzer == nil {
 		return
 	}
 
@@ -83,48 +85,16 @@
 			return false
 		}
 
-		c.fuzzer.Properties.AFLEnabled = true
-		c.fuzzer.Properties.AFLAddFlags = true
+		c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework
 		return true
 	})
 }
 
-func fuzzMutator(mctx android.BottomUpMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.fuzzer != nil {
-		if !c.fuzzer.Properties.AFLEnabled {
-			return
-		}
-
-		if c.Binary() {
-			m := mctx.CreateVariations("afl")
-			m[0].(*Module).fuzzer.Properties.AFLEnabled = true
-			m[0].(*Module).fuzzer.Properties.AFLAddFlags = true
-		} else {
-			m := mctx.CreateVariations("", "afl")
-			m[0].(*Module).fuzzer.Properties.AFLEnabled = false
-			m[0].(*Module).fuzzer.Properties.AFLAddFlags = false
-
-			m[1].(*Module).fuzzer.Properties.AFLEnabled = true
-			m[1].(*Module).fuzzer.Properties.AFLAddFlags = true
-		}
-	}
-}
-
 // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
 // $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
 // your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
 func LibFuzzFactory() android.Module {
-	module := NewFuzzer(android.HostAndDeviceSupported, fuzz.Cc)
-	return module.Init()
-}
-
-// cc_afl_fuzz creates a host/device AFL++ fuzzer binary.
-// AFL++ is an open source framework used to fuzz libraries
-// Host binaries can be found at $ANDROID_HOST_OUT/afl_fuzz/ and device
-// binaries can be found at $ANDROID_PRODUCT_OUT/data/afl_fuzz in your
-// build tree
-func AFLFuzzFactory() android.Module {
-	module := NewFuzzer(android.HostAndDeviceSupported, fuzz.AFL)
+	module := NewFuzzer(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
@@ -133,7 +103,6 @@
 	*baseCompiler
 	fuzzPackagedModule  fuzz.FuzzPackagedModule
 	installedSharedDeps []string
-	fuzzType            fuzz.FuzzType
 }
 
 func (fuzz *fuzzBinary) fuzzBinary() bool {
@@ -143,6 +112,7 @@
 func (fuzz *fuzzBinary) linkerProps() []interface{} {
 	props := fuzz.binaryDecorator.linkerProps()
 	props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties)
+
 	return props
 }
 
@@ -151,16 +121,14 @@
 }
 
 func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
-	if fuzzBin.fuzzType == fuzz.AFL {
+	if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" {
 		deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers")
-		deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
-		return deps
-
 	} else {
 		deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
-		deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
-		return deps
 	}
+
+	deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
+	return deps
 }
 
 func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
@@ -184,10 +152,10 @@
 // IsValidSharedDependency takes a module and determines if it is a unique shared library
 // that should be installed in the fuzz target output directories. This function
 // returns true, unless:
-//  - The module is not an installable shared library, or
-//  - The module is a header or stub, or
-//  - The module is a prebuilt and its source is available, or
-//  - The module is a versioned member of an SDK snapshot.
+//   - The module is not an installable shared library, or
+//   - The module is a header or stub, or
+//   - The module is a prebuilt and its source is available, or
+//   - The module is a versioned member of an SDK snapshot.
 func IsValidSharedDependency(dependency android.Module) bool {
 	// TODO(b/144090547): We should be parsing these modules using
 	// ModuleDependencyTag instead of the current brute-force checking.
@@ -257,9 +225,6 @@
 
 func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
 	installBase := "fuzz"
-	if fuzzBin.fuzzType == fuzz.AFL {
-		installBase = "afl_fuzz"
-	}
 
 	fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join(
 		installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -333,12 +298,9 @@
 	}
 }
 
-func NewFuzzer(hod android.HostOrDeviceSupported, fuzzType fuzz.FuzzType) *Module {
+func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
 	module, binary := newBinary(hod, false)
 	baseInstallerPath := "fuzz"
-	if fuzzType == fuzz.AFL {
-		baseInstallerPath = "afl_fuzz"
-	}
 
 	binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData)
 	module.sanitize.SetSanitizer(Fuzzer, true)
@@ -346,12 +308,13 @@
 	fuzzBin := &fuzzBinary{
 		binaryDecorator: binary,
 		baseCompiler:    NewBaseCompiler(),
-		fuzzType:        fuzzType,
 	}
 	module.compiler = fuzzBin
 	module.linker = fuzzBin
 	module.installer = fuzzBin
 
+	module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer
+
 	// The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
 		disableDarwinAndLinuxBionic := struct {
@@ -367,18 +330,18 @@
 		disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
 		disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
 		ctx.AppendProperties(&disableDarwinAndLinuxBionic)
-	})
 
-	if fuzzType == fuzz.AFL {
-		// Add cc_objects to Srcs
-		fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt")
-		module.fuzzer.Properties.AFLEnabled = true
-		module.compiler.appendCflags([]string{
-			"-Wno-unused-result",
-			"-Wno-unused-parameter",
-			"-Wno-unused-function",
-		})
-	}
+		targetFramework := fuzz.GetFramework(ctx, fuzz.Cc)
+		if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) {
+			ctx.Module().Disable()
+			return
+		}
+
+		if targetFramework == fuzz.AFL {
+			fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt")
+			module.fuzzer.Properties.FuzzFramework = fuzz.AFL
+		}
+	})
 
 	return module
 }
@@ -399,17 +362,6 @@
 		fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
 		allFuzzTargetsName:               "ALL_FUZZ_TARGETS",
 	}
-	fuzzPackager.FuzzType = fuzz.Cc
-	return fuzzPackager
-}
-
-func fuzzAFLPackagingFactory() android.Singleton {
-	fuzzPackager := &ccFuzzPackager{
-		fuzzPackagingArchModules:         "SOONG_AFL_FUZZ_PACKAGING_ARCH_MODULES",
-		fuzzTargetSharedDepsInstallPairs: "AFL_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
-		allFuzzTargetsName:               "ALL_AFL_FUZZ_TARGETS",
-	}
-	fuzzPackager.FuzzType = fuzz.AFL
 	return fuzzPackager
 }
 
@@ -440,7 +392,7 @@
 
 		sharedLibsInstallDirPrefix := "lib"
 		fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
-		if !ok || fuzzModule.fuzzType != s.FuzzType {
+		if !ok {
 			return
 		}
 
@@ -455,9 +407,6 @@
 		}
 
 		intermediatePath := "fuzz"
-		if s.FuzzType == fuzz.AFL {
-			intermediatePath = "afl_fuzz"
-		}
 
 		archString := ccModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
@@ -484,7 +433,7 @@
 		}
 	})
 
-	s.CreateFuzzPackage(ctx, archDirs, s.FuzzType, pctx)
+	s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
 }
 
 func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
@@ -511,9 +460,6 @@
 	var files []fuzz.FileToZip
 
 	fuzzDir := "fuzz"
-	if s.FuzzType == fuzz.AFL {
-		fuzzDir = "afl_fuzz"
-	}
 
 	for _, library := range sharedLibraries {
 		files = append(files, fuzz.FileToZip{library, destinationPathPrefix})
diff --git a/cc/gen_test.go b/cc/gen_test.go
index 40a5716..85df333 100644
--- a/cc/gen_test.go
+++ b/cc/gen_test.go
@@ -74,4 +74,26 @@
 
 	})
 
+	t.Run("sysprop", func(t *testing.T) {
+		ctx := testCc(t, `
+		cc_library {
+			name: "libsysprop",
+			srcs: [
+				"path/to/foo.sysprop",
+			],
+		}`)
+
+		outDir := "out/soong/.intermediates/libsysprop/android_arm64_armv8-a_static/gen"
+		syspropBuildParams := ctx.ModuleForTests("libsysprop", "android_arm64_armv8-a_static").Rule("sysprop")
+
+		android.AssertStringEquals(t, "header output directory does not match", outDir+"/sysprop/include/path/to", syspropBuildParams.Args["headerOutDir"])
+		android.AssertStringEquals(t, "public output directory does not match", outDir+"/sysprop/public/include/path/to", syspropBuildParams.Args["publicOutDir"])
+		android.AssertStringEquals(t, "src output directory does not match", outDir+"/sysprop/path/to", syspropBuildParams.Args["srcOutDir"])
+		android.AssertStringEquals(t, "output include name does not match", "path/to/foo.sysprop.h", syspropBuildParams.Args["includeName"])
+		android.AssertStringEquals(t, "Input file does not match", "path/to/foo.sysprop", syspropBuildParams.Input.String())
+		android.AssertStringEquals(t, "Output file does not match", outDir+"/sysprop/path/to/foo.sysprop.cpp", syspropBuildParams.Output.String())
+		android.AssertStringListContains(t, "Implicit outputs does not contain header file", syspropBuildParams.ImplicitOutputs.Strings(), outDir+"/sysprop/include/path/to/foo.sysprop.h")
+		android.AssertStringListContains(t, "Implicit outputs does not contain public header file", syspropBuildParams.ImplicitOutputs.Strings(), outDir+"/sysprop/public/include/path/to/foo.sysprop.h")
+		android.AssertIntEquals(t, "Implicit outputs contains the incorrect number of elements", 2, len(syspropBuildParams.ImplicitOutputs.Strings()))
+	})
 }
diff --git a/cc/genrule.go b/cc/genrule.go
index 239064f..4ef990c 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -41,13 +41,13 @@
 // variations.  The following environment variables will be set when the command
 // execute:
 //
-//   CC_ARCH           the name of the architecture the command is being executed for
+//	CC_ARCH           the name of the architecture the command is being executed for
 //
-//   CC_MULTILIB       "lib32" if the architecture the command is being executed for is 32-bit,
-//                     "lib64" if it is 64-bit.
+//	CC_MULTILIB       "lib32" if the architecture the command is being executed for is 32-bit,
+//	                  "lib64" if it is 64-bit.
 //
-//   CC_NATIVE_BRIDGE  the name of the subdirectory that native bridge libraries are stored in if
-//                     the architecture has native bridge enabled, empty if it is disabled.
+//	CC_NATIVE_BRIDGE  the name of the subdirectory that native bridge libraries are stored in if
+//	                  the architecture has native bridge enabled, empty if it is disabled.
 func GenRuleFactory() android.Module {
 	module := genrule.NewGenRule()
 
diff --git a/cc/image.go b/cc/image.go
index 921b2bb..e65a9aa 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/cc/library.go b/cc/library.go
index bd6ccb5..fc03fa2 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -270,6 +270,15 @@
 	Features bazel.StringListAttribute
 }
 
+type aidlLibraryAttributes struct {
+	Srcs        bazel.LabelListAttribute
+	Include_dir *string
+}
+
+type ccAidlLibraryAttributes struct {
+	Deps bazel.LabelListAttribute
+}
+
 type stripAttributes struct {
 	Keep_symbols                 bazel.BoolAttribute
 	Keep_symbols_and_debug_frame bazel.BoolAttribute
@@ -282,7 +291,7 @@
 	// For some cc_library modules, their static variants are ready to be
 	// converted, but not their shared variants. For these modules, delegate to
 	// the cc_library_static bp2build converter temporarily instead.
-	if android.GenerateCcLibraryStaticOnly(ctx.Module().Name()) {
+	if android.GetBp2BuildAllowList().GenerateCcLibraryStaticOnly(ctx.Module().Name()) {
 		sharedOrStaticLibraryBp2Build(ctx, m, true)
 		return
 	}
@@ -319,6 +328,7 @@
 		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
 		Whole_archive_deps:                *linkerAttrs.wholeArchiveDeps.Clone().Append(staticAttrs.Whole_archive_deps),
 		System_dynamic_deps:               *linkerAttrs.systemDynamicDeps.Clone().Append(staticAttrs.System_dynamic_deps),
+		Runtime_deps:                      linkerAttrs.runtimeDeps,
 		sdkAttributes:                     bp2BuildParseSdkAttributes(m),
 	}
 
@@ -335,6 +345,7 @@
 		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),
 	}
 
@@ -357,7 +368,7 @@
 		C_std:                    compilerAttrs.cStd,
 		Use_version_lib:          linkerAttrs.useVersionLib,
 
-		Features: linkerAttrs.features,
+		Features: baseAttributes.features,
 	}
 
 	sharedTargetAttrs := &bazelCcLibrarySharedAttributes{
@@ -389,10 +400,12 @@
 			All:                          linkerAttrs.stripAll,
 			None:                         linkerAttrs.stripNone,
 		},
-		Features: linkerAttrs.features,
+		Features: baseAttributes.features,
+	}
 
-		Stubs_symbol_file: compilerAttrs.stubsSymbolFile,
-		Stubs_versions:    compilerAttrs.stubsVersions,
+	if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
+		hasStubs := true
+		sharedTargetAttrs.Has_stubs.SetValue(&hasStubs)
 	}
 
 	for axis, configToProps := range m.GetArchVariantProperties(ctx, &LibraryProperties{}) {
@@ -400,7 +413,7 @@
 			if props, ok := props.(*LibraryProperties); ok {
 				if props.Inject_bssl_hash != nil {
 					// This is an edge case applies only to libcrypto
-					if m.Name() == "libcrypto" {
+					if m.Name() == "libcrypto" || m.Name() == "libcrypto_for_testing" {
 						sharedTargetAttrs.Inject_bssl_hash.SetSelectValue(axis, config, props.Inject_bssl_hash)
 					} else {
 						ctx.PropertyErrorf("inject_bssl_hash", "only applies to libcrypto")
@@ -425,6 +438,25 @@
 	ctx.CreateBazelTargetModuleWithRestrictions(sharedProps,
 		android.CommonAttributes{Name: m.Name()},
 		sharedTargetAttrs, sharedAttrs.Enabled)
+
+	if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
+		stubSuitesProps := bazel.BazelTargetModuleProperties{
+			Rule_class:        "cc_stub_suite",
+			Bzl_load_location: "//build/bazel/rules/cc:cc_stub_library.bzl",
+		}
+		soname := m.Name() + ".so"
+		stubSuitesAttrs := &bazelCcStubSuiteAttributes{
+			Symbol_file:     compilerAttrs.stubsSymbolFile,
+			Versions:        compilerAttrs.stubsVersions,
+			Export_includes: exportedIncludes.Includes,
+			Soname:          &soname,
+			Source_library:  *bazel.MakeLabelAttribute(":" + m.Name()),
+			Deps:            baseAttributes.deps,
+		}
+		ctx.CreateBazelTargetModule(stubSuitesProps,
+			android.CommonAttributes{Name: m.Name() + "_stub_libs"},
+			stubSuitesAttrs)
+	}
 }
 
 // cc_library creates both static and/or shared libraries for a device and/or
@@ -613,6 +645,9 @@
 	// Source Abi Diff
 	sAbiDiff android.OptionalPath
 
+	// Source Abi Diff against previous SDK version
+	prevSAbiDiff android.OptionalPath
+
 	// Location of the static library in the sysroot. Empty if the library is
 	// not included in the NDK.
 	ndkSysrootPath android.Path
@@ -771,6 +806,12 @@
 		if strings.HasPrefix(dir, android.PathForOutput(ctx).String()) {
 			continue
 		}
+
+		// Filter out the generated headers from bazel.
+		if strings.HasPrefix(dir, android.PathForBazelOut(ctx, "bazel-out").String()) {
+			continue
+		}
+
 		// libeigen wrongly exports the root directory "external/eigen". But only two
 		// subdirectories "Eigen" and "unsupported" contain exported header files. Even worse
 		// some of them have no extension. So we need special treatment for libeigen in order
@@ -1039,9 +1080,7 @@
 		if ctx.Module().(android.ApexModule).NotInPlatform() {
 			flag = "--apex"
 		} else {
-			// TODO(b/239274367) drop --apex when #apex is replaced with #systemapi
-			// in the map.txt files of platform libraries
-			flag = "--systemapi --apex"
+			flag = "--systemapi"
 		}
 		nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
 			android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
@@ -1614,16 +1653,51 @@
 	return nil
 }
 
+func prevDumpRefVersion(ctx ModuleContext) string {
+	sdkVersionInt := ctx.Config().PlatformSdkVersion().FinalInt()
+	sdkVersionStr := ctx.Config().PlatformSdkVersion().String()
+
+	if ctx.Config().PlatformSdkFinal() {
+		return strconv.Itoa(sdkVersionInt - 1)
+	} else {
+		var dirName string
+
+		isNdk := ctx.isNdk(ctx.Config())
+		if isNdk {
+			dirName = "ndk"
+		} else {
+			dirName = "platform"
+		}
+
+		// The platform SDK version can be upgraded before finalization while the corresponding abi dumps hasn't
+		// been generated. Thus the Cross-Version Check chooses PLATFORM_SDK_VERION - 1 as previous version.
+		// This situation could be identified by checking the existence of the PLATFORM_SDK_VERION dump directory.
+		refDumpDir := android.ExistentPathForSource(ctx, "prebuilts", "abi-dumps", dirName, sdkVersionStr)
+		if refDumpDir.Valid() {
+			return sdkVersionStr
+		} else {
+			return strconv.Itoa(sdkVersionInt - 1)
+		}
+	}
+}
+
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
 	if library.sabi.shouldCreateSourceAbiDump() {
-		var vndkVersion string
+		var version string
+		var prevVersion string
 
 		if ctx.useVndk() {
 			// For modules linking against vndk, follow its vndk version
-			vndkVersion = ctx.Module().(*Module).VndkVersion()
+			version = ctx.Module().(*Module).VndkVersion()
 		} else {
-			// Regard the other modules as PLATFORM_VNDK_VERSION
-			vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
+			// After sdk finalizatoin, the ABI of the latest API level must be consistent with the source code
+			// so the chosen reference dump is the PLATFORM_SDK_VERSION.
+			if ctx.Config().PlatformSdkFinal() {
+				version = ctx.Config().PlatformSdkVersion().String()
+			} else {
+				version = "current"
+			}
+			prevVersion = prevDumpRefVersion(ctx)
 		}
 
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
@@ -1642,13 +1716,24 @@
 
 		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
 
-		refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
+		if prevVersion != "" {
+			prevRefAbiDumpFile := getRefAbiDumpFile(ctx, prevVersion, fileName)
+			if prevRefAbiDumpFile != nil {
+				library.prevSAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
+					prevRefAbiDumpFile, fileName, prevVersion, exportedHeaderFlags,
+					library.Properties.Header_abi_checker.Diff_flags,
+					Bool(library.Properties.Header_abi_checker.Check_all_apis),
+					ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt(), true)
+			}
+		}
+
+		refAbiDumpFile := getRefAbiDumpFile(ctx, version, fileName)
 		if refAbiDumpFile != nil {
 			library.sAbiDiff = sourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
-				refAbiDumpFile, fileName, exportedHeaderFlags,
+				refAbiDumpFile, fileName, "", exportedHeaderFlags,
 				library.Properties.Header_abi_checker.Diff_flags,
 				Bool(library.Properties.Header_abi_checker.Check_all_apis),
-				ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt())
+				ctx.IsLlndk(), ctx.isNdk(ctx.Config()), ctx.IsVndkExt(), false)
 		}
 	}
 }
@@ -2497,6 +2582,7 @@
 		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
 		System_dynamic_deps:               linkerAttrs.systemDynamicDeps,
 		sdkAttributes:                     bp2BuildParseSdkAttributes(module),
+		Runtime_deps:                      linkerAttrs.runtimeDeps,
 	}
 
 	var attrs interface{}
@@ -2523,12 +2609,12 @@
 			Conlyflags: compilerAttrs.conlyFlags,
 			Asflags:    asFlags,
 
-			Features: linkerAttrs.features,
+			Features: baseAttributes.features,
 		}
 	} else {
 		commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
 
-		attrs = &bazelCcLibrarySharedAttributes{
+		sharedLibAttrs := &bazelCcLibrarySharedAttributes{
 			staticOrSharedAttributes: commonAttrs,
 
 			Cppflags:   compilerAttrs.cppFlags,
@@ -2560,11 +2646,13 @@
 				None:                         linkerAttrs.stripNone,
 			},
 
-			Features: linkerAttrs.features,
-
-			Stubs_symbol_file: compilerAttrs.stubsSymbolFile,
-			Stubs_versions:    compilerAttrs.stubsVersions,
+			Features: baseAttributes.features,
 		}
+		if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
+			hasStubs := true
+			sharedLibAttrs.Has_stubs.SetValue(&hasStubs)
+		}
+		attrs = sharedLibAttrs
 	}
 
 	var modType string
@@ -2638,7 +2726,16 @@
 
 	Features bazel.StringListAttribute
 
-	Stubs_symbol_file *string
-	Stubs_versions    bazel.StringListAttribute
-	Inject_bssl_hash  bazel.BoolAttribute
+	Has_stubs bazel.BoolAttribute
+
+	Inject_bssl_hash bazel.BoolAttribute
+}
+
+type bazelCcStubSuiteAttributes struct {
+	Symbol_file     *string
+	Versions        bazel.StringListAttribute
+	Export_includes bazel.StringListAttribute
+	Source_library  bazel.LabelAttribute
+	Soname          *string
+	Deps            bazel.LabelListAttribute
 }
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 970d8d1..a683f58 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -126,6 +126,7 @@
 	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &baseAttributes.includes)
 	linkerAttrs := baseAttributes.linkerAttributes
 	(&linkerAttrs.deps).Append(linkerAttrs.dynamicDeps)
+	(&linkerAttrs.deps).Append(linkerAttrs.wholeArchiveDeps)
 
 	attrs := &bazelCcLibraryHeadersAttributes{
 		Export_includes:          exportedIncludes.Includes,
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 4d0148d..fa6c279 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/multitree"
+	"strings"
 )
 
 func init() {
@@ -25,10 +26,99 @@
 
 func RegisterLibraryStubBuildComponents(ctx android.RegistrationContext) {
 	// cc_api_stub_library shares a lot of ndk_library, and this will be refactored later
+	ctx.RegisterModuleType("cc_api_library", CcApiLibraryFactory)
 	ctx.RegisterModuleType("cc_api_stub_library", CcApiStubLibraryFactory)
 	ctx.RegisterModuleType("cc_api_contribution", CcApiContributionFactory)
 }
 
+// 'cc_api_library' is a module type which is from the exported API surface
+// with C shared library type. The module will replace original module, and
+// offer a link to the module that generates shared library object from the
+// map file.
+type apiLibraryProperties struct {
+	Src *string `android:"arch_variant"`
+}
+
+type apiLibraryDecorator struct {
+	*libraryDecorator
+	properties apiLibraryProperties
+}
+
+func CcApiLibraryFactory() android.Module {
+	module, decorator := NewLibrary(android.DeviceSupported)
+	apiLibraryDecorator := &apiLibraryDecorator{
+		libraryDecorator: decorator,
+	}
+	apiLibraryDecorator.BuildOnlyShared()
+
+	module.stl = nil
+	module.sanitize = nil
+	decorator.disableStripping()
+
+	module.compiler = nil
+	module.linker = apiLibraryDecorator
+	module.installer = nil
+	module.AddProperties(&module.Properties, &apiLibraryDecorator.properties)
+
+	// Mark module as stub, so APEX would not include this stub in the package.
+	module.library.setBuildStubs(true)
+
+	// Prevent default system libs (libc, libm, and libdl) from being linked
+	if apiLibraryDecorator.baseLinker.Properties.System_shared_libs == nil {
+		apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
+	}
+
+	apiLibraryDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true)
+	apiLibraryDecorator.baseLinker.Properties.Nocrt = BoolPtr(true)
+
+	module.Init()
+
+	return module
+}
+
+func (d *apiLibraryDecorator) Name(basename string) string {
+	return basename + multitree.GetApiImportSuffix()
+}
+
+func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
+	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
+	d.libraryDecorator.flagExporter.exportIncludes(ctx)
+	d.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
+	d.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
+	d.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
+	d.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+	d.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+	d.libraryDecorator.flagExporter.setProvider(ctx)
+
+	in := android.PathForModuleSrc(ctx, *d.properties.Src)
+
+	d.unstrippedOutputFile = in
+	libName := d.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
+
+	tocFile := android.PathForModuleOut(ctx, libName+".toc")
+	d.tocFile = android.OptionalPathForPath(tocFile)
+	TransformSharedObjectToToc(ctx, in, tocFile)
+
+	ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+		SharedLibrary: in,
+		Target:        ctx.Target(),
+
+		TableOfContents: d.tocFile,
+	})
+
+	return in
+}
+
+func (d *apiLibraryDecorator) availableFor(what string) bool {
+	// Stub from API surface should be available for any APEX.
+	return true
+}
+
+func (d *apiLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+	d.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), multitree.GetApiImportSuffix())
+	return d.libraryDecorator.linkerFlags(ctx, flags)
+}
+
 func CcApiStubLibraryFactory() android.Module {
 	module, decorator := NewLibrary(android.DeviceSupported)
 	apiStubDecorator := &apiStubDecorator{
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 15b56d2..c2ac941 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -22,6 +22,8 @@
 
 	"android/soong/android"
 	"android/soong/multitree"
+
+	"github.com/google/blueprint"
 )
 
 func TestCcApiStubLibraryOutputFiles(t *testing.T) {
@@ -106,3 +108,111 @@
 	android.AssertStringEquals(t, "name", "foo.mysdk", api_surface_gen_rule_args["name"])
 	android.AssertStringEquals(t, "symbol_file", "foo.map.txt", api_surface_gen_rule_args["symbol_file"])*/
 }
+
+func hasDirectDependency(t *testing.T, ctx *android.TestResult, from android.Module, to android.Module) bool {
+	t.Helper()
+	var found bool
+	ctx.VisitDirectDeps(from, func(dep blueprint.Module) {
+		if dep == to {
+			found = true
+		}
+	})
+	return found
+}
+
+func TestApiLibraryReplacesExistingModule(t *testing.T) {
+	bp := `
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libbar"],
+		}
+
+		cc_library {
+			name: "libbar",
+		}
+
+		cc_api_library {
+			name: "libbar",
+			src: "libbar.so",
+		}
+
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libbar",
+			],
+			header_libs: [],
+		}
+	`
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+	libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+	android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbar))
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
+
+func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) {
+	bp := `
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libbar"],
+		}
+
+		cc_api_library {
+			name: "libbar",
+			src: "libbar.so",
+		}
+
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libbar",
+			],
+			header_libs: [],
+		}
+	`
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
+
+func TestApiLibraryShouldNotReplaceWithoutApiImport(t *testing.T) {
+	bp := `
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libbar"],
+		}
+
+		cc_library {
+			name: "libbar",
+		}
+
+		cc_api_library {
+			name: "libbar",
+			src: "libbar.so",
+		}
+
+		api_imports {
+			name: "api_imports",
+			shared_libs: [],
+			header_libs: [],
+		}
+	`
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+	libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
+	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
+
+	android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar))
+	android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+}
diff --git a/cc/lto.go b/cc/lto.go
index 2c274bd..455ff7e 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -136,9 +136,16 @@
 }
 
 func (lto *lto) DefaultThinLTO(ctx BaseModuleContext) bool {
+	// LP32 has many subtle issues and less test coverage.
+	lib32 := ctx.Arch().ArchType.Multilib == "lib32"
+	// CFI enables full LTO.
+	cfi := ctx.isCfi()
+	// Performance and binary size are less important for host binaries.
 	host := ctx.Host()
-	vndk := ctx.isVndk() // b/169217596
-	return GlobalThinLTO(ctx) && !lto.Never() && !host && !vndk
+	// FIXME: ThinLTO for VNDK produces different output.
+	// b/169217596
+	vndk := ctx.isVndk()
+	return GlobalThinLTO(ctx) && !lto.Never() && !lib32 && !cfi && !host && !vndk
 }
 
 func (lto *lto) FullLTO() bool {
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 56fd5fc..ef38a06 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -148,12 +148,12 @@
 // to the sysroot base + "usr/include" + to directory + directory component.
 // ndk_headers requires the license file to be specified. Example:
 //
-//    Given:
-//    sysroot base = "ndk/sysroot"
-//    from = "include/foo"
-//    to = "bar"
-//    header = "include/foo/woodly/doodly.h"
-//    output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
+//	Given:
+//	sysroot base = "ndk/sysroot"
+//	from = "include/foo"
+//	to = "bar"
+//	header = "include/foo/woodly/doodly.h"
+//	output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
 func ndkHeadersFactory() android.Module {
 	module := &headerModule{}
 	module.AddProperties(&module.properties)
@@ -275,15 +275,17 @@
 	return module
 }
 
-// preprocessed_ndk_header {
-//     name: "foo",
-//     preprocessor: "foo.sh",
-//     srcs: [...],
-//     to: "android",
-// }
+//	preprocessed_ndk_header {
+//	    name: "foo",
+//	    preprocessor: "foo.sh",
+//	    srcs: [...],
+//	    to: "android",
+//	}
 //
 // Will invoke the preprocessor as:
-//     $preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
+//
+//	$preprocessor -o $SYSROOT/usr/include/android/needs_preproc.h $src
+//
 // For each src in srcs.
 type preprocessedHeadersProperties struct {
 	// The preprocessor to run. Must be a program inside the source directory
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 0879257..2bbfc4a 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -84,12 +84,11 @@
 //
 // Example:
 //
-// ndk_library {
-//     name: "libfoo",
-//     symbol_file: "libfoo.map.txt",
-//     first_version: "9",
-// }
-//
+//	ndk_library {
+//	    name: "libfoo",
+//	    symbol_file: "libfoo.map.txt",
+//	    first_version: "9",
+//	}
 type libraryProperties struct {
 	// Relative path to the symbol map.
 	// An example file can be seen here: TODO(danalbert): Make an example.
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 8c404d3..867c36c 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -51,6 +51,9 @@
 	// symbols, etc), default true.
 	Check_elf_files *bool
 
+	// if set, add an extra objcopy --prefix-symbols= step
+	Prefix_symbols *string
+
 	// Optionally provide an import library if this is a Windows PE DLL prebuilt.
 	// This is needed only if this library is linked by other modules in build time.
 	// Only makes sense for the Windows target.
@@ -130,6 +133,13 @@
 
 		in := android.PathForModuleSrc(ctx, srcs[0])
 
+		if String(p.prebuiltLinker.properties.Prefix_symbols) != "" {
+			prefixed := android.PathForModuleOut(ctx, "prefixed", srcs[0])
+			transformBinaryPrefixSymbols(ctx, String(p.prebuiltLinker.properties.Prefix_symbols),
+				in, flagsToBuilderFlags(flags), prefixed)
+			in = prefixed
+		}
+
 		if p.static() {
 			depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
 			ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
@@ -348,10 +358,10 @@
 
 // TODO(b/228623543): The below is not entirely true until the bug is fixed. For now, both targets are always generated
 // Implements bp2build for cc_prebuilt_library modules. This will generate:
-// * Only a prebuilt_library_static if the shared.enabled property is set to false across all variants.
-// * Only a prebuilt_library_shared if the static.enabled property is set to false across all variants
-// * Both a prebuilt_library_static and prebuilt_library_shared if the aforementioned properties are not false across
-//   all variants
+//   - Only a prebuilt_library_static if the shared.enabled property is set to false across all variants.
+//   - Only a prebuilt_library_shared if the static.enabled property is set to false across all variants
+//   - Both a prebuilt_library_static and prebuilt_library_shared if the aforementioned properties are not false across
+//     all variants
 //
 // In all cases, prebuilt_library_static target names will be appended with "_bp2build_cc_library_static".
 func prebuiltLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module) {
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index 9d40ad0..792ffe3 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
@@ -263,12 +263,12 @@
 // version, snapshot arch, etc. It also adds a special suffix to Soong module name, so it doesn't
 // collide with source modules. e.g. the following example module,
 //
-// vendor_snapshot_static {
-//     name: "libbase",
-//     arch: "arm64",
-//     version: 30,
-//     ...
-// }
+//	vendor_snapshot_static {
+//	    name: "libbase",
+//	    arch: "arm64",
+//	    version: 30,
+//	    ...
+//	}
 //
 // will be seen as "libbase.vendor_static.30.arm64" by Soong.
 type BaseSnapshotDecorator struct {
@@ -370,7 +370,6 @@
 	}
 }
 
-//
 // Module definitions for snapshots of libraries (shared, static, header).
 //
 // Modules (vendor|recovery)_snapshot_(shared|static|header) are defined here. Shared libraries and
@@ -630,7 +629,6 @@
 
 var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
 
-//
 // Module definitions for snapshots of executable binaries.
 //
 // Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable
@@ -728,7 +726,6 @@
 	return module.Init()
 }
 
-//
 // Module definitions for snapshots of object files (*.o).
 //
 // Modules (vendor|recovery)_snapshot_object are defined here. They have their prebuilt object
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index de50ef5..cf4617d 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/cc/test.go b/cc/test.go
index 5703571..f5abc45 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -43,6 +43,8 @@
 
 // Test option struct.
 type TestOptions struct {
+	android.CommonTestOptions
+
 	// The UID that you want to run the test as on a device.
 	Run_test_as *string
 
@@ -52,9 +54,6 @@
 	// a list of extra test configuration files that should be installed with the module.
 	Extra_test_configs []string `android:"path,arch_variant"`
 
-	// If the test is a hostside(no device required) unittest that shall be run during presubmit check.
-	Unit_test *bool
-
 	// Add ShippingApiLevelModuleController to auto generated test config. If the device properties
 	// for the shipping api level is less than the min_shipping_api_level, skip this module.
 	Min_shipping_api_level *int64
diff --git a/cc/testing.go b/cc/testing.go
index d70ec9b..44a865d 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -20,6 +20,7 @@
 
 	"android/soong/android"
 	"android/soong/genrule"
+	"android/soong/multitree"
 	"android/soong/snapshot"
 )
 
@@ -31,6 +32,8 @@
 	RegisterLibraryHeadersBuildComponents(ctx)
 	RegisterLibraryStubBuildComponents(ctx)
 
+	multitree.RegisterApiImportsModule(ctx)
+
 	ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
 	ctx.RegisterModuleType("cc_object", ObjectFactory)
 	ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
@@ -531,7 +534,6 @@
 	android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
 	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
-		ctx.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
 		ctx.RegisterModuleType("cc_test", TestFactory)
 		ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
 		ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
@@ -646,7 +648,6 @@
 	ctx := android.NewTestArchContext(config)
 	genrule.RegisterGenruleBuildComponents(ctx)
 	ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
-	ctx.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
 	ctx.RegisterModuleType("cc_test", TestFactory)
 	ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index 65a2b0c..f2c8545 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -28,17 +28,16 @@
 //
 // Example:
 //
-// vendor_public_library {
-//     name: "libfoo",
-//     symbol_file: "libfoo.map.txt",
-//     export_public_headers: ["libfoo_headers"],
-// }
+//	vendor_public_library {
+//	    name: "libfoo",
+//	    symbol_file: "libfoo.map.txt",
+//	    export_public_headers: ["libfoo_headers"],
+//	}
 //
-// cc_headers {
-//     name: "libfoo_headers",
-//     export_include_dirs: ["include"],
-// }
-//
+//	cc_headers {
+//	    name: "libfoo_headers",
+//	    export_include_dirs: ["include"],
+//	}
 type vendorPublicLibraryProperties struct {
 	// Relative path to the symbol map.
 	Symbol_file *string
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index e7c05ac..77e6f6f 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 31b6d10..37819a4 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -29,26 +29,25 @@
 //
 // Example:
 //
-// vndk_prebuilt_shared {
-//     name: "libfoo",
-//     version: "27",
-//     target_arch: "arm64",
-//     vendor_available: true,
-//     product_available: true,
-//     vndk: {
-//         enabled: true,
-//     },
-//     export_include_dirs: ["include/external/libfoo/vndk_include"],
-//     arch: {
-//         arm64: {
-//             srcs: ["arm/lib64/libfoo.so"],
-//         },
-//         arm: {
-//             srcs: ["arm/lib/libfoo.so"],
-//         },
-//     },
-// }
-//
+//	vndk_prebuilt_shared {
+//	    name: "libfoo",
+//	    version: "27",
+//	    target_arch: "arm64",
+//	    vendor_available: true,
+//	    product_available: true,
+//	    vndk: {
+//	        enabled: true,
+//	    },
+//	    export_include_dirs: ["include/external/libfoo/vndk_include"],
+//	    arch: {
+//	        arm64: {
+//	            srcs: ["arm/lib64/libfoo.so"],
+//	        },
+//	        arm: {
+//	            srcs: ["arm/lib/libfoo.so"],
+//	        },
+//	    },
+//	}
 type vndkPrebuiltProperties struct {
 	// VNDK snapshot version.
 	Version *string
@@ -250,25 +249,25 @@
 // vndk_prebuilt_shared installs Vendor Native Development kit (VNDK) snapshot
 // shared libraries for system build. Example:
 //
-//    vndk_prebuilt_shared {
-//        name: "libfoo",
-//        version: "27",
-//        target_arch: "arm64",
-//        vendor_available: true,
-//        product_available: true,
-//        vndk: {
-//            enabled: true,
-//        },
-//        export_include_dirs: ["include/external/libfoo/vndk_include"],
-//        arch: {
-//            arm64: {
-//                srcs: ["arm/lib64/libfoo.so"],
-//            },
-//            arm: {
-//                srcs: ["arm/lib/libfoo.so"],
-//            },
-//        },
-//    }
+//	vndk_prebuilt_shared {
+//	    name: "libfoo",
+//	    version: "27",
+//	    target_arch: "arm64",
+//	    vendor_available: true,
+//	    product_available: true,
+//	    vndk: {
+//	        enabled: true,
+//	    },
+//	    export_include_dirs: ["include/external/libfoo/vndk_include"],
+//	    arch: {
+//	        arm64: {
+//	            srcs: ["arm/lib64/libfoo.so"],
+//	        },
+//	        arm: {
+//	            srcs: ["arm/lib/libfoo.so"],
+//	        },
+//	    },
+//	}
 func VndkPrebuiltSharedFactory() android.Module {
 	module := vndkPrebuiltSharedLibrary()
 	return module.Init()
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index f8844fc..d4a57bf 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -824,6 +824,7 @@
 
 	var regen string
 	var pom2build bool
+	var prepend string
 
 	flag.Var(&excludes, "exclude", "Exclude module")
 	flag.Var(&extraStaticLibs, "extra-static-libs", "Extra static dependencies needed when depending on a module")
@@ -839,6 +840,7 @@
 	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")
+	flag.StringVar(&prepend, "prepend", "", "Path to a file containing text to insert at the beginning of the generated build file")
 	flag.Parse()
 
 	if regen != "" {
@@ -965,6 +967,15 @@
 	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)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, "Error reading", prepend, err)
+			os.Exit(1)
+		}
+		fmt.Fprintln(buf, string(contents))
+	}
+
 	depsTemplate := bpDepsTemplate
 	template := bpTemplate
 	if pom2build {
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 4f7451d..91e3540 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -208,7 +208,6 @@
 //
 // returns an exec.Cmd that can be ran from within sbox context if no error, or nil if error.
 // caller must ensure script is cleaned up if function succeeds.
-//
 func createCommandScript(rawCommand, scriptPath, scriptPathInSandbox string) (*exec.Cmd, error) {
 	err := os.WriteFile(scriptPath, []byte(rawCommand), 0644)
 	if err != nil {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 53422cd..0b8cc88 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -84,6 +84,8 @@
 	flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
 	flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
 	flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
+	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
+	flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
 
 	// Flags that probably shouldn't be flags of soong_build but we haven't found
 	// the time to remove them yet
@@ -121,7 +123,25 @@
 }
 
 func newConfig(availableEnv map[string]string) android.Config {
-	configuration, err := android.NewConfig(cmdlineArgs.ModuleListFile, runGoTests, outDir, soongOutDir, availableEnv)
+	var buildMode android.SoongBuildMode
+
+	if bp2buildMarker != "" {
+		buildMode = android.Bp2build
+	} else if bazelQueryViewDir != "" {
+		buildMode = android.GenerateQueryView
+	} else if moduleGraphFile != "" {
+		buildMode = android.GenerateModuleGraph
+	} else if docFile != "" {
+		buildMode = android.GenerateDocFile
+	} else if cmdlineArgs.BazelModeDev {
+		buildMode = android.BazelDevMode
+	} else if cmdlineArgs.BazelMode {
+		buildMode = android.BazelProdMode
+	} else {
+		buildMode = android.AnalysisNoBazel
+	}
+
+	configuration, err := android.NewConfig(cmdlineArgs.ModuleListFile, buildMode, runGoTests, outDir, soongOutDir, availableEnv)
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
 		os.Exit(1)
@@ -220,53 +240,41 @@
 // doChosenActivity runs Soong for a specific activity, like bp2build, queryview
 // or the actual Soong build for the build.ninja file. Returns the top level
 // output file of the specific activity.
-func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string, logDir string) string {
-	mixedModeBuild := configuration.BazelContext.BazelEnabled()
-	generateBazelWorkspace := bp2buildMarker != ""
-	generateQueryView := bazelQueryViewDir != ""
-	generateModuleGraphFile := moduleGraphFile != ""
-	generateDocFile := docFile != ""
-
-	if generateBazelWorkspace {
+func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string) string {
+	if configuration.BuildMode == android.Bp2build {
 		// Run the alternate pipeline of bp2build mutators and singleton to convert
 		// Blueprint to BUILD files before everything else.
 		runBp2Build(configuration, extraNinjaDeps)
 		return bp2buildMarker
-	}
-
-	blueprintArgs := cmdlineArgs
-
-	if mixedModeBuild {
+	} else if configuration.IsMixedBuildsEnabled() {
 		runMixedModeBuild(configuration, ctx, extraNinjaDeps)
 	} else {
 		var stopBefore bootstrap.StopBefore
-		if generateModuleGraphFile {
+		if configuration.BuildMode == android.GenerateModuleGraph {
 			stopBefore = bootstrap.StopBeforeWriteNinja
-		} else if generateQueryView {
-			stopBefore = bootstrap.StopBeforePrepareBuildActions
-		} else if generateDocFile {
+		} else if configuration.BuildMode == android.GenerateQueryView || configuration.BuildMode == android.GenerateDocFile {
 			stopBefore = bootstrap.StopBeforePrepareBuildActions
 		} else {
 			stopBefore = bootstrap.DoEverything
 		}
 
-		ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, stopBefore, ctx.Context, configuration)
+		ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs, stopBefore, ctx.Context, configuration)
 		ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
 		globListFiles := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
 		ninjaDeps = append(ninjaDeps, globListFiles...)
 
 		// Convert the Soong module graph into Bazel BUILD files.
-		if generateQueryView {
+		if configuration.BuildMode == android.GenerateQueryView {
 			queryviewMarkerFile := bazelQueryViewDir + ".marker"
 			runQueryView(bazelQueryViewDir, queryviewMarkerFile, configuration, ctx)
 			writeDepFile(queryviewMarkerFile, *ctx.EventHandler, ninjaDeps)
 			return queryviewMarkerFile
-		} else if generateModuleGraphFile {
+		} else if configuration.BuildMode == android.GenerateModuleGraph {
 			writeJsonModuleGraphAndActions(ctx, moduleGraphFile, moduleActionsFile)
 			writeDepFile(moduleGraphFile, *ctx.EventHandler, ninjaDeps)
 			return moduleGraphFile
-		} else if generateDocFile {
+		} else if configuration.BuildMode == android.GenerateDocFile {
 			// TODO: we could make writeDocs() return the list of documentation files
 			// written and add them to the .d file. Then soong_docs would be re-run
 			// whenever one is deleted.
@@ -345,7 +353,7 @@
 	ctx := newContext(configuration)
 	ctx.EventHandler.Begin("soong_build")
 
-	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps, logDir)
+	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps)
 
 	ctx.EventHandler.End("soong_build")
 	writeMetrics(configuration, *ctx.EventHandler, logDir)
@@ -398,14 +406,10 @@
 	}
 }
 
-// Find BUILD files in the srcDir which...
-//
-// - are not on the allow list (android/bazel.go#ShouldKeepExistingBuildFileForDir())
-//
-// - won't be overwritten by corresponding bp2build generated files
-//
-// And return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
-func getPathsToIgnoredBuildFiles(topDir string, generatedRoot string, srcDirBazelFiles []string, verbose bool) []string {
+// Find BUILD files in the srcDir which are not in the allowlist
+// (android.Bp2BuildConversionAllowlist#ShouldKeepExistingBuildFileForDir)
+// and return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
+func getPathsToIgnoredBuildFiles(config android.Bp2BuildConversionAllowlist, topDir string, srcDirBazelFiles []string, verbose bool) []string {
 	paths := make([]string, 0)
 
 	for _, srcDirBazelFileRelativePath := range srcDirBazelFiles {
@@ -420,21 +424,14 @@
 			// Don't ignore entire directories
 			continue
 		}
-		if !(fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") {
+		if fileInfo.Name() != "BUILD" && fileInfo.Name() != "BUILD.bazel" {
 			// Don't ignore this file - it is not a build file
 			continue
 		}
-		srcDirBazelFileDir := filepath.Dir(srcDirBazelFileRelativePath)
-		if android.ShouldKeepExistingBuildFileForDir(srcDirBazelFileDir) {
+		if config.ShouldKeepExistingBuildFileForDir(filepath.Dir(srcDirBazelFileRelativePath)) {
 			// Don't ignore this existing build file
 			continue
 		}
-		correspondingBp2BuildFile := shared.JoinPath(topDir, generatedRoot, srcDirBazelFileRelativePath)
-		if _, err := os.Stat(correspondingBp2BuildFile); err == nil {
-			// If bp2build generated an alternate BUILD file, don't exclude this workspace path
-			// BUILD file clash resolution happens later in the symlink forest creation
-			continue
-		}
 		if verbose {
 			fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath)
 		}
@@ -491,11 +488,6 @@
 		// conversion for Bazel conversion.
 		bp2buildCtx := android.NewContext(configuration)
 
-		// Soong internals like LoadHooks behave differently when running as
-		// bp2build. This is the bit to differentiate between Soong-as-Soong and
-		// Soong-as-bp2build.
-		bp2buildCtx.SetRunningAsBp2build()
-
 		// Propagate "allow misssing dependencies" bit. This is normally set in
 		// newContext(), but we create bp2buildCtx without calling that method.
 		bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
@@ -550,7 +542,7 @@
 			os.Exit(1)
 		}
 
-		pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(topDir, generatedRoot, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
+		pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(configuration.Bp2buildPackageConfig, topDir, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
 		excludes = append(excludes, pathsToIgnoredBuildFiles...)
 
 		excludes = append(excludes, getTemporaryExcludes()...)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 16f994d..cb85634 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -66,11 +66,9 @@
 	{
 		flag:        "--make-mode",
 		description: "build the modules by the target name (i.e. soong_docs)",
-		config: func(ctx build.Context, args ...string) build.Config {
-			return build.NewConfig(ctx, args...)
-		},
-		stdio: stdio,
-		run:   runMake,
+		config:      build.NewConfig,
+		stdio:       stdio,
+		run:         runMake,
 	}, {
 		flag:         "--dumpvar-mode",
 		description:  "print the value of the legacy make variable VAR to stdout",
@@ -114,7 +112,7 @@
 
 // Main execution of soong_ui. The command format is as follows:
 //
-//    soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
+//	soong_ui <command> [<arg 1> <arg 2> ... <arg n>]
 //
 // Command is the type of soong_ui execution. Only one type of
 // execution is specified. The args are specific to the command.
@@ -270,6 +268,8 @@
 
 func dumpVar(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
+	flags.SetOutput(ctx.Writer)
+
 	flags.Usage = func() {
 		fmt.Fprintf(ctx.Writer, "usage: %s --dumpvar-mode [--abs] <VAR>\n\n", os.Args[0])
 		fmt.Fprintln(ctx.Writer, "In dumpvar mode, print the value of the legacy make variable VAR to stdout")
@@ -320,6 +320,8 @@
 
 func dumpVars(ctx build.Context, config build.Config, args []string, _ string) {
 	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
+	flags.SetOutput(ctx.Writer)
+
 	flags.Usage = func() {
 		fmt.Fprintf(ctx.Writer, "usage: %s --dumpvars-mode [--vars=\"VAR VAR ...\"]\n\n", os.Args[0])
 		fmt.Fprintln(ctx.Writer, "In dumpvars mode, dump the values of one or more legacy make variables, in")
@@ -403,6 +405,8 @@
 
 func buildActionConfig(ctx build.Context, args ...string) build.Config {
 	flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
+	flags.SetOutput(ctx.Writer)
+
 	flags.Usage = func() {
 		fmt.Fprintf(ctx.Writer, "usage: %s --build-mode --dir=<path> <build action> [<build arg 1> <build arg 2> ...]\n\n", os.Args[0])
 		fmt.Fprintln(ctx.Writer, "In build mode, build the set of modules based on the specified build")
@@ -455,21 +459,32 @@
 	const numBuildActionFlags = 2
 	if len(args) < numBuildActionFlags {
 		flags.Usage()
-		ctx.Fatalln("Improper build action arguments.")
+		ctx.Fatalln("Improper build action arguments: too few arguments")
 	}
-	flags.Parse(args[0:numBuildActionFlags])
+	parseError := flags.Parse(args[0:numBuildActionFlags])
 
 	// The next block of code is to validate that exactly one build action is set and the dir flag
 	// is specified.
-	buildActionCount := 0
+	buildActionFound := false
 	var buildAction build.BuildAction
-	for _, flag := range buildActionFlags {
-		if flag.set {
-			buildActionCount++
-			buildAction = flag.action
+	for _, f := range buildActionFlags {
+		if f.set {
+			if buildActionFound {
+				if parseError == nil {
+					//otherwise Parse() already called Usage()
+					flags.Usage()
+				}
+				ctx.Fatalf("Build action already specified, omit: --%s\n", f.name)
+			}
+			buildActionFound = true
+			buildAction = f.action
 		}
 	}
-	if buildActionCount != 1 {
+	if !buildActionFound {
+		if parseError == nil {
+			//otherwise Parse() already called Usage()
+			flags.Usage()
+		}
 		ctx.Fatalln("Build action not defined.")
 	}
 	if *dir == "" {
@@ -491,11 +506,7 @@
 		fmt.Fprintln(writer, "!")
 		fmt.Fprintln(writer, "! Older versions are saved in verbose.log.#.gz files")
 		fmt.Fprintln(writer, "")
-		select {
-		case <-time.After(5 * time.Second):
-		case <-ctx.Done():
-			return
-		}
+		ctx.Fatal("done")
 	}
 
 	if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
@@ -515,8 +526,16 @@
 // getCommand finds the appropriate command based on args[1] flag. args[0]
 // is the soong_ui filename.
 func getCommand(args []string) (*command, []string, error) {
+	listFlags := func() []string {
+		flags := make([]string, len(commands))
+		for i, c := range commands {
+			flags[i] = c.flag
+		}
+		return flags
+	}
+
 	if len(args) < 2 {
-		return nil, nil, fmt.Errorf("Too few arguments: %q", args)
+		return nil, nil, fmt.Errorf("Too few arguments: %q\nUse one of these: %q", args, listFlags())
 	}
 
 	for _, c := range commands {
@@ -524,13 +543,7 @@
 			return &c, args[2:], nil
 		}
 	}
-
-	// command not found
-	flags := make([]string, len(commands))
-	for i, c := range commands {
-		flags[i] = c.flag
-	}
-	return nil, nil, fmt.Errorf("Command not found: %q\nDid you mean one of these: %q", args, flags)
+	return nil, nil, fmt.Errorf("Command not found: %q\nDid you mean one of these: %q", args[1], listFlags())
 }
 
 // For Bazel support, this moves files and directories from e.g. out/dist/$f to DIST_DIR/$f if necessary.
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index 7bc9ab2..afb3de3 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -25,11 +25,11 @@
 )
 
 // This comment describes the following:
-//   1. the concept of class loader context (CLC) and its relation to classpath
-//   2. how PackageManager constructs CLC from shared libraries and their dependencies
-//   3. build-time vs. run-time CLC and why this matters for dexpreopt
-//   4. manifest fixer: a tool that adds missing <uses-library> tags to the manifests
-//   5. build system support for CLC
+//  1. the concept of class loader context (CLC) and its relation to classpath
+//  2. how PackageManager constructs CLC from shared libraries and their dependencies
+//  3. build-time vs. run-time CLC and why this matters for dexpreopt
+//  4. manifest fixer: a tool that adds missing <uses-library> tags to the manifests
+//  5. build system support for CLC
 //
 // 1. Class loader context
 // -----------------------
@@ -59,15 +59,16 @@
 // loaders are not duplicated (at runtime there is a single class loader instance for each library).
 //
 // Example: A has <uses-library> tags B, C and D; C has <uses-library tags> B and D;
-//          D has <uses-library> E; B and E have no <uses-library> dependencies. The CLC is:
-//    A
-//    ├── B
-//    ├── C
-//    │   ├── B
-//    │   └── D
-//    │       └── E
-//    └── D
-//        └── E
+//
+//	      D has <uses-library> E; B and E have no <uses-library> dependencies. The CLC is:
+//	A
+//	├── B
+//	├── C
+//	│   ├── B
+//	│   └── D
+//	│       └── E
+//	└── D
+//	    └── E
 //
 // CLC defines the lookup order of libraries when resolving Java classes used by the library/app.
 // The lookup order is important because libraries may contain duplicate classes, and the class is
@@ -188,7 +189,6 @@
 // rule generation phase.
 //
 // ClassLoaderContext is a structure that represents CLC.
-//
 type ClassLoaderContext struct {
 	// The name of the library.
 	Name string
@@ -249,7 +249,6 @@
 // generates a build rule that includes conditional CLC for all versions, extracts the target SDK
 // version from the manifest, and filters the CLCs based on that version. Exact final CLC that is
 // passed to dex2oat is unknown to the build system, and gets known only at Ninja stage.
-//
 type ClassLoaderContextMap map[int][]*ClassLoaderContext
 
 // Compatibility libraries. Some are optional, and some are required: this is the default that
@@ -485,7 +484,6 @@
 // constructs class loader context on device.
 //
 // TODO(b/132357300): remove "android.hidl.manager" and "android.hidl.base" for non-system apps.
-//
 func fixClassLoaderContext(clcMap ClassLoaderContextMap) {
 	required, optional := clcMap.UsesLibs()
 	usesLibs := append(required, optional...)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 64cd46a..eefda19 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -522,7 +522,7 @@
 	return &GlobalSoongConfig{
 		Profman:          ctx.Config().HostToolPath(ctx, "profman"),
 		Dex2oat:          dex2oatPathFromDep(ctx),
-		Aapt:             ctx.Config().HostToolPath(ctx, "aapt"),
+		Aapt:             ctx.Config().HostToolPath(ctx, "aapt2"),
 		SoongZip:         ctx.Config().HostToolPath(ctx, "soong_zip"),
 		Zip2zip:          ctx.Config().HostToolPath(ctx, "zip2zip"),
 		ManifestCheck:    ctx.Config().HostToolPath(ctx, "manifest_check"),
@@ -724,7 +724,7 @@
 	return &GlobalSoongConfig{
 		Profman:          android.PathForTesting("profman"),
 		Dex2oat:          android.PathForTesting("dex2oat"),
-		Aapt:             android.PathForTesting("aapt"),
+		Aapt:             android.PathForTesting("aapt2"),
 		SoongZip:         android.PathForTesting("soong_zip"),
 		Zip2zip:          android.PathForTesting("zip2zip"),
 		ManifestCheck:    android.PathForTesting("manifest_check"),
diff --git a/etc/snapshot_etc.go b/etc/snapshot_etc.go
index b54a8a6..0d65ab6 100644
--- a/etc/snapshot_etc.go
+++ b/etc/snapshot_etc.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/finder/finder.go b/finder/finder.go
index c5196c8..054ccd6 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -736,15 +736,15 @@
 // because we know this separator won't appear in the json that we're parsing.
 //
 // The newline byte can only appear in a UTF-8 stream if the newline character appears, because:
-// - The newline character is encoded as "0000 1010" in binary ("0a" in hex)
-// - UTF-8 dictates that bytes beginning with a "0" bit are never emitted as part of a multibyte
-//   character.
+//   - The newline character is encoded as "0000 1010" in binary ("0a" in hex)
+//   - UTF-8 dictates that bytes beginning with a "0" bit are never emitted as part of a multibyte
+//     character.
 //
 // We know that the newline character will never appear in our json string, because:
-// - If a newline character appears as part of a data string, then json encoding will
-//   emit two characters instead: '\' and 'n'.
-// - The json encoder that we use doesn't emit the optional newlines between any of its
-//   other outputs.
+//   - If a newline character appears as part of a data string, then json encoding will
+//     emit two characters instead: '\' and 'n'.
+//   - The json encoder that we use doesn't emit the optional newlines between any of its
+//     other outputs.
 const lineSeparator = byte('\n')
 
 func (f *Finder) readLine(reader *bufio.Reader) ([]byte, error) {
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 1a87b30..c8cd21b 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -27,13 +27,21 @@
 	"android/soong/android"
 )
 
-type FuzzType string
+type Lang string
 
 const (
-	Cc   FuzzType = ""
-	Rust FuzzType = "rust"
-	Java FuzzType = "java"
-	AFL  FuzzType = "AFL"
+	Cc   Lang = "cc"
+	Rust Lang = "rust"
+	Java Lang = "java"
+)
+
+type Framework string
+
+const (
+	AFL              Framework = "afl"
+	LibFuzzer        Framework = "libfuzzer"
+	Jazzer           Framework = "jazzer"
+	UnknownFramework Framework = "unknownframework"
 )
 
 var BoolDefault = proptools.BoolDefault
@@ -48,7 +56,6 @@
 	Packages                android.Paths
 	FuzzTargets             map[string]bool
 	SharedLibInstallStrings []string
-	FuzzType                FuzzType
 }
 
 type FileToZip struct {
@@ -106,21 +113,21 @@
 	// A brief description of what the fuzzed code does.
 	Description string `json:"description,omitempty"`
 	// Can this code be triggered remotely or only locally.
-	Remotely_accessible bool `json:"remotely_accessible,omitempty"`
+	Remotely_accessible *bool `json:"remotely_accessible,omitempty"`
 	// Is the fuzzed code host only, i.e. test frameworks or support utilities.
-	Host_only bool `json:"host_only,omitempty"`
+	Host_only *bool `json:"host_only,omitempty"`
 	// Can third party/untrusted apps supply data to fuzzed code.
-	Untrusted_data bool `json:"untrusted_data,omitempty"`
+	Untrusted_data *bool `json:"untrusted_data,omitempty"`
 	// Is the code being fuzzed in a privileged, constrained or any other
 	// context from:
 	// https://source.android.com/security/overview/updates-resources#context_types.
 	Privilege_level PrivilegedLevel `json:"privilege_level,omitempty"`
 	// Can the fuzzed code isolated or can be called by multiple users/processes.
-	Isolated bool `json:"users_isolation,omitempty"`
+	Isolated *bool `json:"users_isolation,omitempty"`
 	// When code was relaeased or will be released.
 	Production_date string `json:"production_date,omitempty"`
 	// Prevents critical service functionality like phone calls, bluetooth, etc.
-	Critical bool `json:"critical,omitempty"`
+	Critical *bool `json:"critical,omitempty"`
 	// Specify whether to enable continuous fuzzing on devices. Defaults to true.
 	Fuzz_on_haiku_device *bool `json:"fuzz_on_haiku_device,omitempty"`
 	// Specify whether to enable continuous fuzzing on host. Defaults to true.
@@ -146,6 +153,12 @@
 	IsJni *bool `json:"is_jni,omitempty"`
 }
 
+type FuzzFrameworks struct {
+	Afl       *bool
+	Libfuzzer *bool
+	Jazzer    *bool
+}
+
 type FuzzProperties struct {
 	// Optional list of seed files to be installed to the fuzz target's output
 	// directory.
@@ -155,6 +168,10 @@
 	Data []string `android:"path"`
 	// Optional dictionary to be installed to the fuzz target's output directory.
 	Dictionary *string `android:"path"`
+	// Define the fuzzing frameworks this fuzz target can be built for. If
+	// empty then the fuzz target will be available to be  built for all fuzz
+	// frameworks available
+	Fuzzing_frameworks *FuzzFrameworks
 	// Config for running the target on fuzzing infrastructure.
 	Fuzz_config *FuzzConfig
 }
@@ -169,6 +186,49 @@
 	DataIntermediateDir   android.Path
 }
 
+func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
+	framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")
+
+	if lang == Cc {
+		switch strings.ToLower(framework) {
+		case "":
+			return LibFuzzer
+		case "libfuzzer":
+			return LibFuzzer
+		case "afl":
+			return AFL
+		}
+	} else if lang == Rust {
+		return LibFuzzer
+	} else if lang == Java {
+		return Jazzer
+	}
+
+	ctx.ModuleErrorf(fmt.Sprintf("%s is not a valid fuzzing framework for %s", framework, lang))
+	return UnknownFramework
+}
+
+func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrameworks *FuzzFrameworks) bool {
+	if targetFramework == UnknownFramework {
+		return false
+	}
+
+	if moduleFrameworks == nil {
+		return true
+	}
+
+	switch targetFramework {
+	case LibFuzzer:
+		return proptools.BoolDefault(moduleFrameworks.Libfuzzer, true)
+	case AFL:
+		return proptools.BoolDefault(moduleFrameworks.Afl, true)
+	case Jazzer:
+		return proptools.BoolDefault(moduleFrameworks.Jazzer, true)
+	default:
+		panic("%s is not supported as a fuzz framework")
+	}
+}
+
 func IsValid(fuzzModule FuzzModule) bool {
 	// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
 	// fuzz targets we're going to package anyway.
@@ -267,7 +327,7 @@
 	return string(b)
 }
 
-func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType FuzzType, pctx android.PackageContext) {
+func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType Lang, pctx android.PackageContext) {
 	var archOsList []ArchOs
 	for archOs := range archDirs {
 		archOsList = append(archOsList, archOs)
@@ -286,9 +346,7 @@
 		if fuzzType == Java {
 			zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip"
 		}
-		if fuzzType == AFL {
-			zipFileName = "fuzz-afl-" + hostOrTarget + "-" + arch + ".zip"
-		}
+
 		outputFile := android.PathForOutput(ctx, zipFileName)
 
 		s.Packages = append(s.Packages, outputFile)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index b796877..7a0dac3 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -26,6 +26,7 @@
 	"strings"
 
 	"android/soong/bazel/cquery"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
@@ -468,6 +469,7 @@
 				return "SOONG_ERROR", nil
 			}
 
+			// Apply shell escape to each cases to prevent source file paths containing $ from being evaluated in shell
 			switch name {
 			case "location":
 				if len(g.properties.Tools) == 0 && len(g.properties.Tool_files) == 0 {
@@ -481,15 +483,15 @@
 					return reportError("default label %q has multiple files, use $(locations %s) to reference it",
 						firstLabel, firstLabel)
 				}
-				return paths[0], nil
+				return proptools.ShellEscape(paths[0]), nil
 			case "in":
-				return strings.Join(cmd.PathsForInputs(srcFiles), " "), nil
+				return strings.Join(proptools.ShellEscapeList(cmd.PathsForInputs(srcFiles)), " "), nil
 			case "out":
 				var sandboxOuts []string
 				for _, out := range task.out {
 					sandboxOuts = append(sandboxOuts, cmd.PathForOutput(out))
 				}
-				return strings.Join(sandboxOuts, " "), nil
+				return strings.Join(proptools.ShellEscapeList(sandboxOuts), " "), nil
 			case "depfile":
 				referencedDepfile = true
 				if !Bool(g.properties.Depfile) {
@@ -497,7 +499,7 @@
 				}
 				return "__SBOX_DEPFILE__", nil
 			case "genDir":
-				return cmd.PathForOutput(task.genDir), nil
+				return proptools.ShellEscape(cmd.PathForOutput(task.genDir)), nil
 			default:
 				if strings.HasPrefix(name, "location ") {
 					label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
@@ -509,7 +511,7 @@
 							return reportError("label %q has multiple files, use $(locations %s) to reference it",
 								label, label)
 						}
-						return paths[0], nil
+						return proptools.ShellEscape(paths[0]), nil
 					} else {
 						return reportError("unknown location label %q is not in srcs, out, tools or tool_files.", label)
 					}
@@ -520,7 +522,7 @@
 						if len(paths) == 0 {
 							return reportError("label %q has no files", label)
 						}
-						return strings.Join(paths, " "), nil
+						return proptools.ShellEscape(strings.Join(paths, " ")), nil
 					} else {
 						return reportError("unknown locations label %q is not in srcs, out, tools or tool_files.", label)
 					}
@@ -976,9 +978,7 @@
 var Bool = proptools.Bool
 var String = proptools.String
 
-//
 // Defaults
-//
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index b9be1f7..cd941cc 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -422,7 +422,7 @@
 
 			allowMissingDependencies: true,
 
-			expect: "cat ***missing srcs :missing*** > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "cat '***missing srcs :missing***' > __SBOX_SANDBOX_DIR__/out/out",
 		},
 		{
 			name: "tool allow missing dependencies",
@@ -434,7 +434,7 @@
 
 			allowMissingDependencies: true,
 
-			expect: "***missing tool :missing*** > __SBOX_SANDBOX_DIR__/out/out",
+			expect: "'***missing tool :missing***' > __SBOX_SANDBOX_DIR__/out/out",
 		},
 	}
 
@@ -878,6 +878,92 @@
 	android.AssertDeepEquals(t, "output deps", expectedOutputFiles, gen.outputDeps.Strings())
 }
 
+func TestGenruleWithGlobPaths(t *testing.T) {
+	testcases := []struct {
+		name            string
+		bp              string
+		additionalFiles android.MockFS
+		expectedCmd     string
+	}{
+		{
+			name: "single file in directory with $ sign",
+			bp: `
+				genrule {
+					name: "gen",
+					srcs: ["inn*.txt"],
+					out: ["out.txt"],
+					cmd: "cp $(in) $(out)",
+				}
+				`,
+			additionalFiles: android.MockFS{"inn$1.txt": nil},
+			expectedCmd:     "cp 'inn$1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
+		},
+		{
+			name: "multiple file in directory with $ sign",
+			bp: `
+				genrule {
+					name: "gen",
+					srcs: ["inn*.txt"],
+					out: ["."],
+					cmd: "cp $(in) $(out)",
+				}
+				`,
+			additionalFiles: android.MockFS{"inn$1.txt": nil, "inn$2.txt": nil},
+			expectedCmd:     "cp 'inn$1.txt' 'inn$2.txt' __SBOX_SANDBOX_DIR__/out",
+		},
+		{
+			name: "file in directory with other shell unsafe character",
+			bp: `
+				genrule {
+					name: "gen",
+					srcs: ["inn*.txt"],
+					out: ["out.txt"],
+					cmd: "cp $(in) $(out)",
+				}
+				`,
+			additionalFiles: android.MockFS{"inn@1.txt": nil},
+			expectedCmd:     "cp 'inn@1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
+		},
+		{
+			name: "glob location param with filepath containing $",
+			bp: `
+				genrule {
+					name: "gen",
+					srcs: ["**/inn*"],
+					out: ["."],
+					cmd: "cp $(in) $(location **/inn*)",
+				}
+				`,
+			additionalFiles: android.MockFS{"a/inn$1.txt": nil},
+			expectedCmd:     "cp 'a/inn$1.txt' 'a/inn$1.txt'",
+		},
+		{
+			name: "glob locations param with filepath containing $",
+			bp: `
+				genrule {
+					name: "gen",
+					tool_files: ["**/inn*"],
+					out: ["out.txt"],
+					cmd: "cp $(locations  **/inn*) $(out)",
+				}
+				`,
+			additionalFiles: android.MockFS{"a/inn$1.txt": nil},
+			expectedCmd:     "cp '__SBOX_SANDBOX_DIR__/tools/src/a/inn$1.txt' __SBOX_SANDBOX_DIR__/out/out.txt",
+		},
+	}
+
+	for _, test := range testcases {
+		t.Run(test.name, func(t *testing.T) {
+			result := android.GroupFixturePreparers(
+				prepareForGenRuleTest,
+				android.FixtureMergeMockFs(test.additionalFiles),
+			).RunTestWithBp(t, test.bp)
+			gen := result.Module("gen", "").(*Module)
+			android.AssertStringEquals(t, "command", test.expectedCmd, gen.rawCommands[0])
+		})
+	}
+}
+
 type testTool struct {
 	android.ModuleBase
 	outputFile android.Path
diff --git a/java/Android.bp b/java/Android.bp
index e25accf..9df4ab4 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -76,6 +76,7 @@
         "tradefed.go",
     ],
     testSrcs: [
+        "aar_test.go",
         "androidmk_test.go",
         "app_import_test.go",
         "app_set_test.go",
diff --git a/java/aar.go b/java/aar.go
index dadfc6a..d5996ba 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -21,6 +21,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/dexpreopt"
 
 	"github.com/google/blueprint"
@@ -105,6 +106,7 @@
 	noticeFile              android.OptionalPath
 	assetPackage            android.OptionalPath
 	isLibrary               bool
+	defaultManifestVersion  string
 	useEmbeddedNativeLibs   bool
 	useEmbeddedDex          bool
 	usesNonSdkApis          bool
@@ -281,14 +283,15 @@
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
 	manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
-		SdkContext:            sdkContext,
-		ClassLoaderContexts:   classLoaderContexts,
-		IsLibrary:             a.isLibrary,
-		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,
 	})
 
 	// Add additional manifest files to transitive manifests.
@@ -488,6 +491,7 @@
 type AndroidLibrary struct {
 	Library
 	aapt
+	android.BazelModuleBase
 
 	androidLibraryProperties androidLibraryProperties
 
@@ -570,12 +574,24 @@
 
 	a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
 	a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages)
+
+	prebuiltJniPackages := android.Paths{}
+	ctx.VisitDirectDeps(func(module android.Module) {
+		if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+			prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
+		}
+	})
+	if len(prebuiltJniPackages) > 0 {
+		ctx.SetProvider(JniPackageProvider, JniPackageInfo{
+			JniPackages: prebuiltJniPackages,
+		})
+	}
 }
 
 // android_library builds and links sources into a `.jar` file for the device along with Android resources.
 //
 // An android_library has a single variant that produces a `.jar` file containing `.class` files that were
-// compiled against the device bootclasspath, along with a `package-res.apk` file containing  Android resources compiled
+// compiled against the device bootclasspath, along with a `package-res.apk` file containing Android resources compiled
 // with aapt2.  This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of
 // an android_app module.
 func AndroidLibraryFactory() android.Module {
@@ -591,6 +607,7 @@
 
 	android.InitApexModule(module)
 	InitJavaModule(module, android.DeviceSupported)
+	android.InitBazelModule(module)
 	return module
 }
 
@@ -619,12 +636,17 @@
 	Libs []string
 	// If set to true, run Jetifier against .aar file. Defaults to false.
 	Jetifier *bool
+	// If true, extract JNI libs from AAR archive. These libs will be accessible to android_app modules and
+	// will be passed transitively through android_libraries to an android_app.
+	//TODO(b/241138093) evaluate whether we can have this flag default to true for Bazel conversion
+	Extract_jni *bool
 }
 
 type AARImport struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
+	android.BazelModuleBase
 	prebuilt android.Prebuilt
 
 	// Functionality common to Module and Import.
@@ -643,7 +665,8 @@
 
 	hideApexVariantFromMake bool
 
-	aarPath android.Path
+	aarPath     android.Path
+	jniPackages android.Paths
 
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.SdkSpec
@@ -751,6 +774,28 @@
 	ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...)
 }
 
+type JniPackageInfo struct {
+	// List of zip files containing JNI libraries
+	// Zip files should have directory structure jni/<arch>/*.so
+	JniPackages android.Paths
+}
+
+var JniPackageProvider = blueprint.NewProvider(JniPackageInfo{})
+
+// Unzip an AAR and extract the JNI libs for $archString.
+var extractJNI = pctx.AndroidStaticRule("extractJNI",
+	blueprint.RuleParams{
+		Command: `rm -rf $out $outDir && touch $out && ` +
+			`unzip -qoDD -d $outDir $in "jni/${archString}/*" && ` +
+			`jni_files=$$(find $outDir/jni -type f) && ` +
+			// print error message if there are no JNI libs for this arch
+			`[ -n "$$jni_files" ] || (echo "ERROR: no JNI libs found for arch ${archString}" && exit 1) && ` +
+			`${config.SoongZipCmd} -o $out -P 'lib/${archString}' ` +
+			`-C $outDir/jni/${archString} $$(echo $$jni_files | xargs -n1 printf " -f %s")`,
+		CommandDeps: []string{"${config.SoongZipCmd}"},
+	},
+	"outDir", "archString")
+
 // Unzip an AAR into its constituent files and directories.  Any files in Outputs that don't exist in the AAR will be
 // touched to create an empty file. The res directory is not extracted, as it will be extracted in its own rule.
 var unzipAAR = pctx.AndroidStaticRule("unzipAAR",
@@ -858,6 +903,31 @@
 		ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
 		ImplementationJars:             android.PathsIfNonNil(a.classpathFile),
 	})
+
+	if proptools.Bool(a.properties.Extract_jni) {
+		for _, t := range ctx.MultiTargets() {
+			arch := t.Arch.Abi[0]
+			path := android.PathForModuleOut(ctx, arch+"_jni.zip")
+			a.jniPackages = append(a.jniPackages, path)
+
+			outDir := android.PathForModuleOut(ctx, "aarForJni")
+			aarPath := android.PathForModuleSrc(ctx, a.properties.Aars[0])
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        extractJNI,
+				Input:       aarPath,
+				Outputs:     android.WritablePaths{path},
+				Description: "extract JNI from AAR",
+				Args: map[string]string{
+					"outDir":     outDir.String(),
+					"archString": arch,
+				},
+			})
+		}
+
+		ctx.SetProvider(JniPackageProvider, JniPackageInfo{
+			JniPackages: a.jniPackages,
+		})
+	}
 }
 
 func (a *AARImport) HeaderJars() android.Paths {
@@ -906,6 +976,97 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Aars)
 	android.InitApexModule(module)
-	InitJavaModule(module, android.DeviceSupported)
+	InitJavaModuleMultiTargets(module, android.DeviceSupported)
+	android.InitBazelModule(module)
 	return module
 }
+
+type bazelAapt struct {
+	Manifest       bazel.Label
+	Resource_files bazel.LabelListAttribute
+}
+
+type bazelAndroidLibrary struct {
+	*javaLibraryAttributes
+	*bazelAapt
+}
+
+type bazelAndroidLibraryImport struct {
+	Aar     bazel.Label
+	Deps    bazel.LabelListAttribute
+	Exports bazel.LabelListAttribute
+}
+
+func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) *bazelAapt {
+	manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
+
+	resourceFiles := bazel.LabelList{
+		Includes: []bazel.Label{},
+	}
+	for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") {
+		files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
+		resourceFiles.Includes = append(resourceFiles.Includes, files...)
+	}
+	return &bazelAapt{
+		android.BazelLabelForModuleSrcSingle(ctx, manifest),
+		bazel.MakeLabelListAttribute(resourceFiles),
+	}
+}
+
+func (a *AARImport) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	aars := android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Aars, []string{})
+	exportableStaticLibs := []string{}
+	// TODO(b/240716882): investigate and handle static_libs deps that are not imports. They are not supported for export by Bazel.
+	for _, depName := range a.properties.Static_libs {
+		if dep, ok := ctx.ModuleFromName(depName); ok {
+			switch dep.(type) {
+			case *AARImport, *Import:
+				exportableStaticLibs = append(exportableStaticLibs, depName)
+			}
+		}
+	}
+	name := android.RemoveOptionalPrebuiltPrefix(a.Name())
+	deps := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(append(a.properties.Static_libs, a.properties.Libs...))))
+	exports := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(exportableStaticLibs))
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "aar_import",
+			Bzl_load_location: "@rules_android//rules:rules.bzl",
+		},
+		android.CommonAttributes{Name: name},
+		&bazelAndroidLibraryImport{
+			Aar:     aars.Includes[0],
+			Deps:    bazel.MakeLabelListAttribute(deps),
+			Exports: bazel.MakeLabelListAttribute(exports),
+		},
+	)
+
+}
+
+func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx)
+
+	deps := depLabels.Deps
+	if !commonAttrs.Srcs.IsEmpty() {
+		deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
+	} else if !depLabels.Deps.IsEmpty() {
+		ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
+	}
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "android_library",
+			Bzl_load_location: "@rules_android//rules:rules.bzl",
+		},
+		android.CommonAttributes{Name: a.Name()},
+		&bazelAndroidLibrary{
+			&javaLibraryAttributes{
+				javaCommonAttributes: commonAttrs,
+				Deps:                 deps,
+				Exports:              depLabels.StaticDeps,
+			},
+			a.convertAaptAttrsWithBp2Build(ctx),
+		},
+	)
+}
diff --git a/java/aar_test.go b/java/aar_test.go
new file mode 100644
index 0000000..8afa039
--- /dev/null
+++ b/java/aar_test.go
@@ -0,0 +1,83 @@
+// 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"
+	"testing"
+)
+
+func TestAarImportProducesJniPackages(t *testing.T) {
+	ctx := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, `
+		android_library_import {
+			name: "aar-no-jni",
+			aars: ["aary.aar"],
+		}
+		android_library_import {
+			name: "aar-jni",
+			aars: ["aary.aar"],
+			extract_jni: true,
+		}`)
+
+	testCases := []struct {
+		name       string
+		hasPackage bool
+	}{
+		{
+			name:       "aar-no-jni",
+			hasPackage: false,
+		},
+		{
+			name:       "aar-jni",
+			hasPackage: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			appMod := ctx.Module(tc.name, "android_common")
+			appTestMod := ctx.ModuleForTests(tc.name, "android_common")
+
+			info, ok := ctx.ModuleProvider(appMod, JniPackageProvider).(JniPackageInfo)
+			if !ok {
+				t.Errorf("expected android_library_import to have JniPackageProvider")
+			}
+
+			if !tc.hasPackage {
+				if len(info.JniPackages) != 0 {
+					t.Errorf("expected JniPackages to be empty, but got %v", info.JniPackages)
+				}
+				outputFile := "arm64-v8a_jni.zip"
+				jniOutputLibZip := appTestMod.MaybeOutput(outputFile)
+				if jniOutputLibZip.Rule != nil {
+					t.Errorf("did not expect an output file, but found %v", outputFile)
+				}
+				return
+			}
+
+			if len(info.JniPackages) != 1 {
+				t.Errorf("expected a single JniPackage, but got %v", info.JniPackages)
+			}
+
+			outputFile := info.JniPackages[0].String()
+			jniOutputLibZip := appTestMod.Output(outputFile)
+			if jniOutputLibZip.Rule == nil {
+				t.Errorf("did not find output file %v", outputFile)
+			}
+		})
+	}
+}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index c61823d..522b664 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -45,7 +45,11 @@
 // 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)
-	if ctx.Config().UnbundledBuildApps() && targetSdkVersionSpec.ApiLevel.IsPreview() {
+	// 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
+	// TODO(b/240294501): Determine the rules for handling test apexes
+	if targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) {
 		return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt())
 	}
 	targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx)
@@ -55,16 +59,26 @@
 	return targetSdkVersion
 }
 
+// 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 {
+	if test, ok := module.(androidTestApp); ok {
+		return test.includedInTestSuite("mts")
+	}
+	return false
+}
+
 type ManifestFixerParams struct {
-	SdkContext            android.SdkContext
-	ClassLoaderContexts   dexpreopt.ClassLoaderContextMap
-	IsLibrary             bool
-	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
 }
 
 // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
@@ -153,6 +167,9 @@
 		args = append(args, "--replaceMaxSdkVersionPlaceholder ", strconv.Itoa(replaceMaxSdkVersionPlaceholder.FinalOrFutureInt()))
 		args = append(args, "--raise-min-sdk-version")
 	}
+	if params.DefaultManifestVersion != "" {
+		args = append(args, "--override-placeholder-version", params.DefaultManifestVersion)
+	}
 
 	fixedManifest := android.PathForModuleOut(ctx, "manifest_fixer", "AndroidManifest.xml")
 	argsMapper["args"] = strings.Join(args, " ")
diff --git a/java/androidmk.go b/java/androidmk.go
index 82ef413..75ac0e7 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -167,9 +167,8 @@
 			entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true")
 		}
 		entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", j.testProperties.Test_mainline_modules...)
-		if Bool(j.testProperties.Test_options.Unit_test) {
-			entries.SetBool("LOCAL_IS_UNIT_TEST", true)
-		}
+
+		j.testProperties.Test_options.CommonTestOptions.SetAndroidMkEntries(entries)
 	})
 
 	return entriesList
@@ -419,7 +418,15 @@
 				entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports)
 			},
 		},
-	}}
+		ExtraFooters: []android.AndroidMkExtraFootersFunc{
+			func(w io.Writer, name, prefix, moduleDir string) {
+				if app.javaApiUsedByOutputFile.String() != "" {
+					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s/$(notdir %s))\n",
+						app.installApkName, app.javaApiUsedByOutputFile.String(), "java_apis_used_by_apex", app.javaApiUsedByOutputFile.String())
+				}
+			},
+		}},
+	}
 }
 
 func (a *AndroidApp) getOverriddenPackages() []string {
diff --git a/java/app.go b/java/app.go
index 23a9816..bccd37f 100755
--- a/java/app.go
+++ b/java/app.go
@@ -117,6 +117,9 @@
 	// Name of the signing certificate lineage file or filegroup module.
 	Lineage *string `android:"path"`
 
+	// For overriding the --rotation-min-sdk-version property of apksig
+	RotationMinSdkVersion *string
+
 	// the package name of this app. The package name in the manifest file is used if one was not given.
 	Package_name *string
 
@@ -165,6 +168,8 @@
 	overriddenManifestPackageName string
 
 	android.ApexBundleDepsInfo
+
+	javaApiUsedByOutputFile android.ModuleOutPath
 }
 
 func (a *AndroidApp) IsInstallable() bool {
@@ -273,6 +278,7 @@
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.checkAppSdkVersions(ctx)
 	a.generateAndroidBuildActions(ctx)
+	a.generateJavaUsedByApex(ctx)
 }
 
 func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
@@ -417,6 +423,9 @@
 
 	a.aapt.splitNames = a.appProperties.Package_splits
 	a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent)
+	if a.Updatable() {
+		a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion
+	}
 	a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts,
 		a.usesLibraryProperties.Exclude_uses_libs, aaptLinkFlags...)
 
@@ -472,14 +481,14 @@
 	return a.dexJarFile.PathOrNil()
 }
 
-func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
+func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath {
 	var jniJarFile android.WritablePath
-	if len(jniLibs) > 0 {
+	if len(jniLibs) > 0 || len(prebuiltJniPackages) > 0 {
 		a.jniLibs = jniLibs
 		if a.shouldEmbedJnis(ctx) {
 			jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
 			a.installPathForJNISymbols = a.installPath(ctx)
-			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.useEmbeddedNativeLibs(ctx))
+			TransformJniLibsToJar(ctx, jniJarFile, jniLibs, prebuiltJniPackages, a.useEmbeddedNativeLibs(ctx))
 			for _, jni := range jniLibs {
 				if jni.coverageFile.Valid() {
 					// Only collect coverage for the first target arch if this is a multilib target.
@@ -623,8 +632,8 @@
 
 	dexJarFile := a.dexBuildActions(ctx)
 
-	jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
-	jniJarFile := a.jniBuildActions(jniLibs, ctx)
+	jniLibs, prebuiltJniPackages, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
+	jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx)
 
 	if ctx.Failed() {
 		return
@@ -658,7 +667,10 @@
 	if lineage := String(a.overridableAppProperties.Lineage); lineage != "" {
 		lineageFile = android.PathForModuleSrc(ctx, lineage)
 	}
-	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile)
+
+	rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion)
+
+	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
 	a.outputFile = packageFile
 	if v4SigningRequested {
 		a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
@@ -687,7 +699,7 @@
 		if v4SigningRequested {
 			v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
 		}
-		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile)
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
 		if v4SigningRequested {
 			a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
@@ -724,9 +736,10 @@
 
 func collectAppDeps(ctx android.ModuleContext, app appDepsInterface,
 	shouldCollectRecursiveNativeDeps bool,
-	checkNativeSdkVersion bool) ([]jniLib, []Certificate) {
+	checkNativeSdkVersion bool) ([]jniLib, android.Paths, []Certificate) {
 
 	var jniLibs []jniLib
+	var prebuiltJniPackages android.Paths
 	var certificates []Certificate
 	seenModulePaths := make(map[string]bool)
 
@@ -775,6 +788,10 @@
 			return shouldCollectRecursiveNativeDeps
 		}
 
+		if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+			prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
+		}
+
 		if tag == certificateTag {
 			if dep, ok := module.(*AndroidAppCertificate); ok {
 				certificates = append(certificates, dep.Certificate)
@@ -786,7 +803,7 @@
 		return false
 	})
 
-	return jniLibs, certificates
+	return jniLibs, prebuiltJniPackages, certificates
 }
 
 func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
@@ -954,6 +971,18 @@
 	return true
 }
 
+type androidTestApp interface {
+	includedInTestSuite(searchPrefix string) bool
+}
+
+func (a *AndroidTest) includedInTestSuite(searchPrefix string) bool {
+	return android.PrefixInList(a.testProperties.Test_suites, searchPrefix)
+}
+
+func (a *AndroidTestHelperApp) includedInTestSuite(searchPrefix string) bool {
+	return android.PrefixInList(a.appTestHelperAppProperties.Test_suites, searchPrefix)
+}
+
 func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	var configs []tradefed.Config
 	if a.appTestProperties.Instrumentation_target_package != nil {
@@ -1035,7 +1064,7 @@
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
 	module.appProperties.AlwaysPackageNativeLibs = true
 	module.Module.dexpreopter.isTest = true
-	module.Module.linter.test = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
 
 	module.addHostAndDeviceProperties()
 	module.AddProperties(
@@ -1088,7 +1117,7 @@
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
 	module.appProperties.AlwaysPackageNativeLibs = true
 	module.Module.dexpreopter.isTest = true
-	module.Module.linter.test = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
 
 	module.addHostAndDeviceProperties()
 	module.AddProperties(
@@ -1357,7 +1386,7 @@
 		Flag("--enforce-uses-libraries").
 		Input(inputFile).
 		FlagWithOutput("--enforce-uses-libraries-status ", statusFile).
-		FlagWithInput("--aapt ", ctx.Config().HostToolPath(ctx, "aapt"))
+		FlagWithInput("--aapt ", ctx.Config().HostToolPath(ctx, "aapt2"))
 
 	if outputFile != nil {
 		cmd.FlagWithOutput("-o ", outputFile)
@@ -1424,10 +1453,9 @@
 
 type bazelAndroidAppAttributes struct {
 	*javaCommonAttributes
+	*bazelAapt
 	Deps             bazel.LabelListAttribute
-	Manifest         bazel.Label
 	Custom_package   *string
-	Resource_files   bazel.LabelListAttribute
 	Certificate      *bazel.Label
 	Certificate_name *string
 }
@@ -1437,23 +1465,9 @@
 	commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx)
 
 	deps := depLabels.Deps
-	if !commonAttrs.Srcs.IsEmpty() {
-		deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
-	} else if !deps.IsEmpty() || !depLabels.StaticDeps.IsEmpty() {
-		ctx.ModuleErrorf("android_app has dynamic or static dependencies but no sources." +
-			" Bazel does not allow direct dependencies without sources nor exported" +
-			" dependencies on android_binary rule.")
-	}
+	deps.Append(depLabels.StaticDeps)
 
-	manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
-
-	resourceFiles := bazel.LabelList{
-		Includes: []bazel.Label{},
-	}
-	for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") {
-		files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
-		resourceFiles.Includes = append(resourceFiles.Includes, files...)
-	}
+	aapt := a.convertAaptAttrsWithBp2Build(ctx)
 
 	var certificate *bazel.Label
 	certificateNamePtr := a.overridableAppProperties.Certificate
@@ -1464,14 +1478,12 @@
 		certificate = &c
 		certificateNamePtr = nil
 	}
-
 	attrs := &bazelAndroidAppAttributes{
 		commonAttrs,
+		aapt,
 		deps,
-		android.BazelLabelForModuleSrcSingle(ctx, manifest),
 		// TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
 		a.overridableAppProperties.Package_name,
-		bazel.MakeLabelListAttribute(resourceFiles),
 		certificate,
 		certificateNamePtr,
 	}
@@ -1480,7 +1492,6 @@
 		Rule_class:        "android_binary",
 		Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
 	}
-
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: a.Name()}, attrs)
 
 }
diff --git a/java/app_builder.go b/java/app_builder.go
index 4a18dca..18a9751 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) {
+	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
 	unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -73,10 +73,10 @@
 		Implicits: deps,
 	})
 
-	SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile)
+	SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion)
 }
 
-func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path) {
+func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
 
 	var certificateArgs []string
 	var deps android.Paths
@@ -97,6 +97,10 @@
 		deps = append(deps, lineageFile)
 	}
 
+	if rotationMinSdkVersion != "" {
+		flags = append(flags, "--rotation-min-sdk-version", rotationMinSdkVersion)
+	}
+
 	rule := Signapk
 	args := map[string]string{
 		"certificates": strings.Join(certificateArgs, " "),
@@ -218,8 +222,14 @@
 	})
 }
 
-func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
-	jniLibs []jniLib, uncompressJNI bool) {
+const jniJarOutputPathString = "jniJarOutput.zip"
+
+func TransformJniLibsToJar(
+	ctx android.ModuleContext,
+	outputFile android.WritablePath,
+	jniLibs []jniLib,
+	prebuiltJniPackages android.Paths,
+	uncompressJNI bool) {
 
 	var deps android.Paths
 	jarArgs := []string{
@@ -245,13 +255,32 @@
 		rule = zipRE
 		args["implicits"] = strings.Join(deps.Strings(), ",")
 	}
+	jniJarPath := android.PathForModuleOut(ctx, jniJarOutputPathString)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "zip jni libs",
-		Output:      outputFile,
+		Output:      jniJarPath,
 		Implicits:   deps,
 		Args:        args,
 	})
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        mergeAssetsRule,
+		Description: "merge prebuilt JNI packages",
+		Inputs:      append(prebuiltJniPackages, jniJarPath),
+		Output:      outputFile,
+	})
+}
+
+func (a *AndroidApp) generateJavaUsedByApex(ctx android.ModuleContext) {
+	javaApiUsedByOutputFile := android.PathForModuleOut(ctx, a.installApkName+"_using.xml")
+	javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+	javaUsedByRule.Command().
+		Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+		BuiltTool("dexdeps").
+		Output(javaApiUsedByOutputFile).
+		Input(a.Library.Module.outputFile)
+	javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+	a.javaApiUsedByOutputFile = javaApiUsedByOutputFile
 }
 
 func targetToJniDir(target android.Target) string {
diff --git a/java/app_import.go b/java/app_import.go
index b017eca..d6dca38 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -80,6 +80,9 @@
 	// Name of the signing certificate lineage file or filegroup module.
 	Lineage *string `android:"path"`
 
+	// For overriding the --rotation-min-sdk-version property of apksig
+	RotationMinSdkVersion *string
+
 	// Sign with the default system dev certificate. Must be used judiciously. Most imported apps
 	// need to either specify a specific certificate or be presigned.
 	Default_dev_cert *bool
@@ -256,7 +259,7 @@
 		ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
 	}
 
-	_, certificates := collectAppDeps(ctx, a, false, false)
+	_, _, certificates := collectAppDeps(ctx, a, false, false)
 
 	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
 	// TODO: LOCAL_PACKAGE_SPLITS
@@ -333,7 +336,10 @@
 		if lineage := String(a.properties.Lineage); lineage != "" {
 			lineageFile = android.PathForModuleSrc(ctx, lineage)
 		}
-		SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile)
+
+		rotationMinSdkVersion := String(a.properties.RotationMinSdkVersion)
+
+		SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion)
 		a.outputFile = signed
 	} else {
 		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
@@ -455,19 +461,19 @@
 // android_app_import imports a prebuilt apk with additional processing specified in the module.
 // DPI-specific apk source files can be specified using dpi_variants. Example:
 //
-//     android_app_import {
-//         name: "example_import",
-//         apk: "prebuilts/example.apk",
-//         dpi_variants: {
-//             mdpi: {
-//                 apk: "prebuilts/example_mdpi.apk",
-//             },
-//             xhdpi: {
-//                 apk: "prebuilts/example_xhdpi.apk",
-//             },
-//         },
-//         presigned: true,
-//     }
+//	android_app_import {
+//	    name: "example_import",
+//	    apk: "prebuilts/example.apk",
+//	    dpi_variants: {
+//	        mdpi: {
+//	            apk: "prebuilts/example_mdpi.apk",
+//	        },
+//	        xhdpi: {
+//	            apk: "prebuilts/example_xhdpi.apk",
+//	        },
+//	    },
+//	    presigned: true,
+//	}
 func AndroidAppImportFactory() android.Module {
 	module := &AndroidAppImport{}
 	module.AddProperties(&module.properties)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 8f6c75f..41be092 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -129,6 +129,7 @@
 			certificate: "platform",
 			additional_certificates: [":additional_certificate"],
 			lineage: "lineage.bin",
+			rotationMinSdkVersion: "32",
 		}
 
 		android_app_certificate {
@@ -148,11 +149,12 @@
 	if expected != certificatesFlag {
 		t.Errorf("Incorrect certificates flags, expected: %q, got: %q", expected, certificatesFlag)
 	}
-	// Check cert signing lineage flag.
-	signingFlag := signedApk.Args["flags"]
-	expected = "--lineage lineage.bin"
-	if expected != signingFlag {
-		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+
+	// Check cert signing flags.
+	actualCertSigningFlags := signedApk.Args["flags"]
+	expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32"
+	if expectedCertSigningFlags != actualCertSigningFlags {
+		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags)
 	}
 
 	rule := variant.Rule("genProvenanceMetaData")
diff --git a/java/app_test.go b/java/app_test.go
index c4ac4df..23635b9 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1218,7 +1218,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.Output("jnilibs.zip")
+			jniLibZip := app.Output(jniJarOutputPathString)
 			var abis []string
 			args := strings.Fields(jniLibZip.Args["jarArgs"])
 			for i := 0; i < len(args); i++ {
@@ -1351,7 +1351,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.MaybeOutput("jnilibs.zip")
+			jniLibZip := app.MaybeOutput(jniJarOutputPathString)
 			if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
 				t.Errorf("expected jni packaged %v, got %v", w, g)
 			}
@@ -1442,7 +1442,7 @@
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
 
-			jniLibZip := app.MaybeOutput("jnilibs.zip")
+			jniLibZip := app.MaybeOutput(jniJarOutputPathString)
 			if len(jniLibZip.Implicits) != 1 {
 				t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings())
 			}
@@ -1488,11 +1488,11 @@
 
 func TestCertificates(t *testing.T) {
 	testCases := []struct {
-		name                string
-		bp                  string
-		certificateOverride string
-		expectedLineage     string
-		expectedCertificate string
+		name                     string
+		bp                       string
+		certificateOverride      string
+		expectedCertSigningFlags string
+		expectedCertificate      string
 	}{
 		{
 			name: "default",
@@ -1503,9 +1503,9 @@
 					sdk_version: "current",
 				}
 			`,
-			certificateOverride: "",
-			expectedLineage:     "",
-			expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
+			certificateOverride:      "",
+			expectedCertSigningFlags: "",
+			expectedCertificate:      "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
 		},
 		{
 			name: "module certificate property",
@@ -1522,9 +1522,9 @@
 					certificate: "cert/new_cert",
 				}
 			`,
-			certificateOverride: "",
-			expectedLineage:     "",
-			expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+			certificateOverride:      "",
+			expectedCertSigningFlags: "",
+			expectedCertificate:      "cert/new_cert.x509.pem cert/new_cert.pk8",
 		},
 		{
 			name: "path certificate property",
@@ -1536,9 +1536,9 @@
 					sdk_version: "current",
 				}
 			`,
-			certificateOverride: "",
-			expectedLineage:     "",
-			expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			certificateOverride:      "",
+			expectedCertSigningFlags: "",
+			expectedCertificate:      "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
 		},
 		{
 			name: "certificate overrides",
@@ -1555,18 +1555,19 @@
 					certificate: "cert/new_cert",
 				}
 			`,
-			certificateOverride: "foo:new_certificate",
-			expectedLineage:     "",
-			expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+			certificateOverride:      "foo:new_certificate",
+			expectedCertSigningFlags: "",
+			expectedCertificate:      "cert/new_cert.x509.pem cert/new_cert.pk8",
 		},
 		{
-			name: "certificate lineage",
+			name: "certificate signing flags",
 			bp: `
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
 					certificate: ":new_certificate",
 					lineage: "lineage.bin",
+					rotationMinSdkVersion: "32",
 					sdk_version: "current",
 				}
 
@@ -1575,18 +1576,19 @@
 					certificate: "cert/new_cert",
 				}
 			`,
-			certificateOverride: "",
-			expectedLineage:     "--lineage lineage.bin",
-			expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+			certificateOverride:      "",
+			expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+			expectedCertificate:      "cert/new_cert.x509.pem cert/new_cert.pk8",
 		},
 		{
-			name: "lineage from filegroup",
+			name: "cert signing flags from filegroup",
 			bp: `
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
 					certificate: ":new_certificate",
 					lineage: ":lineage_bin",
+					rotationMinSdkVersion: "32",
 					sdk_version: "current",
 				}
 
@@ -1600,9 +1602,9 @@
 					srcs: ["lineage.bin"],
 				}
 			`,
-			certificateOverride: "",
-			expectedLineage:     "--lineage lineage.bin",
-			expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
+			certificateOverride:      "",
+			expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+			expectedCertificate:      "cert/new_cert.x509.pem cert/new_cert.pk8",
 		},
 	}
 
@@ -1623,8 +1625,8 @@
 			signCertificateFlags := signapk.Args["certificates"]
 			android.AssertStringEquals(t, "certificates flags", test.expectedCertificate, signCertificateFlags)
 
-			signFlags := signapk.Args["flags"]
-			android.AssertStringEquals(t, "signing flags", test.expectedLineage, signFlags)
+			certSigningFlags := signapk.Args["flags"]
+			android.AssertStringEquals(t, "cert signing flags", test.expectedCertSigningFlags, certSigningFlags)
 		})
 	}
 }
@@ -1819,6 +1821,7 @@
 			base: "foo",
 			certificate: ":new_certificate",
 			lineage: "lineage.bin",
+			rotationMinSdkVersion: "32",
 			logging_parent: "bah",
 		}
 
@@ -1864,89 +1867,89 @@
 		`)
 
 	expectedVariants := []struct {
-		name            string
-		moduleName      string
-		variantName     string
-		apkName         string
-		apkPath         string
-		certFlag        string
-		lineageFlag     string
-		overrides       []string
-		packageFlag     string
-		renameResources bool
-		logging_parent  string
+		name             string
+		moduleName       string
+		variantName      string
+		apkName          string
+		apkPath          string
+		certFlag         string
+		certSigningFlags string
+		overrides        []string
+		packageFlag      string
+		renameResources  bool
+		logging_parent   string
 	}{
 		{
-			name:            "foo",
-			moduleName:      "foo",
-			variantName:     "android_common",
-			apkPath:         "out/soong/target/product/test_device/system/app/foo/foo.apk",
-			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:     "",
-			overrides:       []string{"qux"},
-			packageFlag:     "",
-			renameResources: false,
-			logging_parent:  "",
+			name:             "foo",
+			moduleName:       "foo",
+			variantName:      "android_common",
+			apkPath:          "out/soong/target/product/test_device/system/app/foo/foo.apk",
+			certFlag:         "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			certSigningFlags: "",
+			overrides:        []string{"qux"},
+			packageFlag:      "",
+			renameResources:  false,
+			logging_parent:   "",
 		},
 		{
-			name:            "foo",
-			moduleName:      "bar",
-			variantName:     "android_common_bar",
-			apkPath:         "out/soong/target/product/test_device/system/app/bar/bar.apk",
-			certFlag:        "cert/new_cert.x509.pem cert/new_cert.pk8",
-			lineageFlag:     "--lineage lineage.bin",
-			overrides:       []string{"qux", "foo"},
-			packageFlag:     "",
-			renameResources: false,
-			logging_parent:  "bah",
+			name:             "foo",
+			moduleName:       "bar",
+			variantName:      "android_common_bar",
+			apkPath:          "out/soong/target/product/test_device/system/app/bar/bar.apk",
+			certFlag:         "cert/new_cert.x509.pem cert/new_cert.pk8",
+			certSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32",
+			overrides:        []string{"qux", "foo"},
+			packageFlag:      "",
+			renameResources:  false,
+			logging_parent:   "bah",
 		},
 		{
-			name:            "foo",
-			moduleName:      "baz",
-			variantName:     "android_common_baz",
-			apkPath:         "out/soong/target/product/test_device/system/app/baz/baz.apk",
-			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:     "",
-			overrides:       []string{"qux", "foo"},
-			packageFlag:     "org.dandroid.bp",
-			renameResources: true,
-			logging_parent:  "",
+			name:             "foo",
+			moduleName:       "baz",
+			variantName:      "android_common_baz",
+			apkPath:          "out/soong/target/product/test_device/system/app/baz/baz.apk",
+			certFlag:         "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			certSigningFlags: "",
+			overrides:        []string{"qux", "foo"},
+			packageFlag:      "org.dandroid.bp",
+			renameResources:  true,
+			logging_parent:   "",
 		},
 		{
-			name:            "foo",
-			moduleName:      "baz_no_rename_resources",
-			variantName:     "android_common_baz_no_rename_resources",
-			apkPath:         "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
-			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:     "",
-			overrides:       []string{"qux", "foo"},
-			packageFlag:     "org.dandroid.bp",
-			renameResources: false,
-			logging_parent:  "",
+			name:             "foo",
+			moduleName:       "baz_no_rename_resources",
+			variantName:      "android_common_baz_no_rename_resources",
+			apkPath:          "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
+			certFlag:         "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			certSigningFlags: "",
+			overrides:        []string{"qux", "foo"},
+			packageFlag:      "org.dandroid.bp",
+			renameResources:  false,
+			logging_parent:   "",
 		},
 		{
-			name:            "foo_no_rename_resources",
-			moduleName:      "baz_base_no_rename_resources",
-			variantName:     "android_common_baz_base_no_rename_resources",
-			apkPath:         "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
-			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:     "",
-			overrides:       []string{"qux", "foo_no_rename_resources"},
-			packageFlag:     "org.dandroid.bp",
-			renameResources: false,
-			logging_parent:  "",
+			name:             "foo_no_rename_resources",
+			moduleName:       "baz_base_no_rename_resources",
+			variantName:      "android_common_baz_base_no_rename_resources",
+			apkPath:          "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
+			certFlag:         "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			certSigningFlags: "",
+			overrides:        []string{"qux", "foo_no_rename_resources"},
+			packageFlag:      "org.dandroid.bp",
+			renameResources:  false,
+			logging_parent:   "",
 		},
 		{
-			name:            "foo_no_rename_resources",
-			moduleName:      "baz_override_base_rename_resources",
-			variantName:     "android_common_baz_override_base_rename_resources",
-			apkPath:         "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
-			certFlag:        "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
-			lineageFlag:     "",
-			overrides:       []string{"qux", "foo_no_rename_resources"},
-			packageFlag:     "org.dandroid.bp",
-			renameResources: true,
-			logging_parent:  "",
+			name:             "foo_no_rename_resources",
+			moduleName:       "baz_override_base_rename_resources",
+			variantName:      "android_common_baz_override_base_rename_resources",
+			apkPath:          "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
+			certFlag:         "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+			certSigningFlags: "",
+			overrides:        []string{"qux", "foo_no_rename_resources"},
+			packageFlag:      "org.dandroid.bp",
+			renameResources:  true,
+			logging_parent:   "",
 		},
 	}
 	for _, expected := range expectedVariants {
@@ -1960,9 +1963,9 @@
 		certFlag := signapk.Args["certificates"]
 		android.AssertStringEquals(t, "certificates flags", expected.certFlag, certFlag)
 
-		// Check the lineage flags
-		lineageFlag := signapk.Args["flags"]
-		android.AssertStringEquals(t, "signing flags", expected.lineageFlag, lineageFlag)
+		// Check the cert signing flags
+		certSigningFlags := signapk.Args["flags"]
+		android.AssertStringEquals(t, "cert signing flags", expected.certSigningFlags, certSigningFlags)
 
 		// Check if the overrides field values are correctly aggregated.
 		mod := variant.Module().(*AndroidApp)
@@ -2425,7 +2428,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.Output("jnilibs.zip")
+			jniLibZip := app.Output(jniJarOutputPathString)
 			var jnis []string
 			args := strings.Fields(jniLibZip.Args["jarArgs"])
 			for i := 0; i < len(args); i++ {
@@ -3074,3 +3077,151 @@
 	}
 	android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n")
 }
+
+func TestAppIncludesJniPackages(t *testing.T) {
+	ctx := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, `
+		android_library_import {
+			name: "aary-nodeps",
+			aars: ["aary.aar"],
+			extract_jni: true,
+		}
+
+		android_library {
+			name: "aary-lib",
+			sdk_version: "current",
+			min_sdk_version: "21",
+			static_libs: ["aary-nodeps"],
+		}
+
+		android_app {
+			name: "aary-lib-dep",
+			sdk_version: "current",
+			min_sdk_version: "21",
+			manifest: "AndroidManifest.xml",
+			static_libs: ["aary-lib"],
+			use_embedded_native_libs: true,
+		}
+
+		android_app {
+			name: "aary-import-dep",
+			sdk_version: "current",
+			min_sdk_version: "21",
+			manifest: "AndroidManifest.xml",
+			static_libs: ["aary-nodeps"],
+			use_embedded_native_libs: true,
+		}
+
+		android_app {
+			name: "aary-no-use-embedded",
+			sdk_version: "current",
+			min_sdk_version: "21",
+			manifest: "AndroidManifest.xml",
+			static_libs: ["aary-nodeps"],
+		}`)
+
+	testCases := []struct {
+		name       string
+		hasPackage bool
+	}{
+		{
+			name:       "aary-import-dep",
+			hasPackage: true,
+		},
+		{
+			name:       "aary-lib-dep",
+			hasPackage: true,
+		},
+		{
+			name:       "aary-no-use-embedded",
+			hasPackage: false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			app := ctx.ModuleForTests(tc.name, "android_common")
+
+			outputFile := "jnilibs.zip"
+			jniOutputLibZip := app.MaybeOutput(outputFile)
+			if jniOutputLibZip.Rule == nil && !tc.hasPackage {
+				return
+			}
+
+			jniPackage := "arm64-v8a_jni.zip"
+			inputs := jniOutputLibZip.Inputs
+			foundPackage := false
+			for i := 0; i < len(inputs); i++ {
+				if strings.Contains(inputs[i].String(), jniPackage) {
+					foundPackage = true
+				}
+			}
+			if foundPackage != tc.hasPackage {
+				t.Errorf("expected to find %v in %v inputs; inputs = %v", jniPackage, outputFile, inputs)
+			}
+		})
+	}
+}
+
+func TestTargetSdkVersionMtsTests(t *testing.T) {
+	platformSdkCodename := "Tiramisu"
+	android_test := "android_test"
+	android_test_helper_app := "android_test_helper_app"
+	bpTemplate := `
+	%v {
+		name: "mytest",
+		target_sdk_version: "%v",
+		test_suites: ["othersuite", "%v"],
+	}
+	`
+	testCases := []struct {
+		desc                     string
+		moduleType               string
+		targetSdkVersionInBp     string
+		targetSdkVersionExpected string
+		testSuites               string
+	}{
+		{
+			desc:                     "Non-MTS android_test_apps targeting current should not be upgraded to 10000",
+			moduleType:               android_test,
+			targetSdkVersionInBp:     "current",
+			targetSdkVersionExpected: platformSdkCodename,
+			testSuites:               "non-mts-suite",
+		},
+		{
+			desc:                     "MTS android_test_apps targeting released sdks should not be upgraded to 10000",
+			moduleType:               android_test,
+			targetSdkVersionInBp:     "29",
+			targetSdkVersionExpected: "29",
+			testSuites:               "mts-suite",
+		},
+		{
+			desc:                     "MTS android_test_apps targeting current should be upgraded to 10000",
+			moduleType:               android_test,
+			targetSdkVersionInBp:     "current",
+			targetSdkVersionExpected: "10000",
+			testSuites:               "mts-suite",
+		},
+		{
+			desc:                     "MTS android_test_helper_apps targeting current should be upgraded to 10000",
+			moduleType:               android_test_helper_app,
+			targetSdkVersionInBp:     "current",
+			targetSdkVersionExpected: "10000",
+			testSuites:               "mts-suite",
+		},
+	}
+	fixture := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_sdk_codename = &platformSdkCodename
+			variables.Platform_version_active_codenames = []string{platformSdkCodename}
+		}),
+	)
+	for _, testCase := range testCases {
+		result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites))
+		mytest := result.ModuleForTests("mytest", "android_common")
+		manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+		android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion  "+testCase.targetSdkVersionExpected)
+	}
+}
diff --git a/java/base.go b/java/base.go
index 94daf37..cf3b3d5 100644
--- a/java/base.go
+++ b/java/base.go
@@ -267,6 +267,9 @@
 	// Only for libraries created by a sysprop_library module, SyspropPublicStub is the name of the
 	// public stubs library.
 	SyspropPublicStub string `blueprint:"mutated"`
+
+	HiddenAPIPackageProperties
+	HiddenAPIFlagFileProperties
 }
 
 // Device properties that can be overridden by overriding module (e.g. override_android_app)
@@ -564,6 +567,20 @@
 	)
 }
 
+// provideHiddenAPIPropertyInfo populates a HiddenAPIPropertyInfo from hidden API properties and
+// makes it available through the hiddenAPIPropertyInfoProvider.
+func (j *Module) provideHiddenAPIPropertyInfo(ctx android.ModuleContext) {
+	hiddenAPIInfo := newHiddenAPIPropertyInfo()
+
+	// Populate with flag file paths from the properties.
+	hiddenAPIInfo.extractFlagFilesFromProperties(ctx, &j.deviceProperties.HiddenAPIFlagFileProperties)
+
+	// Populate with package rules from the properties.
+	hiddenAPIInfo.extractPackageRulesFromProperties(&j.deviceProperties.HiddenAPIPackageProperties)
+
+	ctx.SetProvider(hiddenAPIPropertyInfoProvider, hiddenAPIInfo)
+}
+
 func (j *Module) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
@@ -803,7 +820,7 @@
 }
 
 func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
-	aidlIncludeDirs android.Paths) (string, android.Paths) {
+	aidlIncludeDirs android.Paths, aidlSrcs android.Paths) (string, android.Paths) {
 
 	aidlIncludes := android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Local_include_dirs)
 	aidlIncludes = append(aidlIncludes,
@@ -813,6 +830,7 @@
 
 	var flags []string
 	var deps android.Paths
+	var includeDirs android.Paths
 
 	flags = append(flags, j.deviceProperties.Aidl.Flags...)
 
@@ -820,21 +838,24 @@
 		flags = append(flags, "-p"+aidlPreprocess.String())
 		deps = append(deps, aidlPreprocess.Path())
 	} else if len(aidlIncludeDirs) > 0 {
-		flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
+		includeDirs = append(includeDirs, aidlIncludeDirs...)
 	}
 
 	if len(j.exportAidlIncludeDirs) > 0 {
-		flags = append(flags, android.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
+		includeDirs = append(includeDirs, j.exportAidlIncludeDirs...)
 	}
 
 	if len(aidlIncludes) > 0 {
-		flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
+		includeDirs = append(includeDirs, aidlIncludes...)
 	}
 
-	flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
+	includeDirs = append(includeDirs, android.PathForModuleSrc(ctx))
 	if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
-		flags = append(flags, "-I"+src.String())
+		includeDirs = append(includeDirs, src.Path())
 	}
+	flags = append(flags, android.JoinWithPrefix(includeDirs.Strings(), "-I"))
+	// add flags for dirs containing AIDL srcs that haven't been specified yet
+	flags = append(flags, genAidlIncludeFlags(ctx, aidlSrcs, includeDirs))
 
 	if Bool(j.deviceProperties.Aidl.Generate_traces) {
 		flags = append(flags, "-t")
@@ -918,9 +939,6 @@
 	// systemModules
 	flags.systemModules = deps.systemModules
 
-	// aidl flags.
-	flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
-
 	return flags
 }
 
@@ -1029,6 +1047,9 @@
 		ctx.PropertyErrorf("common_srcs", "common_srcs must be .kt files")
 	}
 
+	aidlSrcs := srcFiles.FilterByExt(".aidl")
+	flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs, aidlSrcs)
+
 	nonGeneratedSrcJars := srcFiles.FilterByExt(".srcjar")
 	srcFiles = j.genSources(ctx, srcFiles, flags)
 
@@ -1178,12 +1199,21 @@
 		}
 	}
 	if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
+		hasErrorproneableFiles := false
+		for _, ext := range j.sourceExtensions {
+			if ext != ".proto" && ext != ".aidl" {
+				// Skip running errorprone on pure proto or pure aidl modules. Some modules take a long time to
+				// compile, and it's not useful to have warnings on these generated sources.
+				hasErrorproneableFiles = true
+				break
+			}
+		}
 		var extraJarDeps android.Paths
 		if Bool(j.properties.Errorprone.Enabled) {
 			// If error-prone is enabled, enable errorprone flags on the regular
 			// build.
 			flags = enableErrorproneFlags(flags)
-		} else if ctx.Config().RunErrorProne() && j.properties.Errorprone.Enabled == nil {
+		} else if hasErrorproneableFiles && ctx.Config().RunErrorProne() && j.properties.Errorprone.Enabled == nil {
 			// Otherwise, if the RUN_ERROR_PRONE environment variable is set, create
 			// a new jar file just for compiling with the errorprone compiler to.
 			// This is because we don't want to cause the java files to get completely
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index f08b64b..9316807 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -128,7 +128,7 @@
 	Coverage BootclasspathFragmentCoverageAffectedProperties
 
 	// Hidden API related properties.
-	Hidden_api HiddenAPIFlagFileProperties
+	HiddenAPIFlagFileProperties
 
 	// The list of additional stub libraries which this fragment's contents use but which are not
 	// provided by another bootclasspath_fragment.
@@ -145,7 +145,7 @@
 	BootclasspathFragmentsDepsProperties
 }
 
-type HiddenApiPackageProperties struct {
+type HiddenAPIPackageProperties struct {
 	Hidden_api struct {
 		// Contains prefixes of a package hierarchy that is provided solely by this
 		// bootclasspath_fragment.
@@ -222,8 +222,8 @@
 }
 
 type SourceOnlyBootclasspathProperties struct {
-	HiddenApiPackageProperties
-	Coverage HiddenApiPackageProperties
+	HiddenAPIPackageProperties
+	Coverage HiddenAPIPackageProperties
 }
 
 type BootclasspathFragmentModule struct {
@@ -293,7 +293,7 @@
 				return
 			}
 
-			err = proptools.AppendProperties(&m.sourceOnlyProperties.HiddenApiPackageProperties, &m.sourceOnlyProperties.Coverage, nil)
+			err = proptools.AppendProperties(&m.sourceOnlyProperties.HiddenAPIPackageProperties, &m.sourceOnlyProperties.Coverage, nil)
 			if err != nil {
 				ctx.PropertyErrorf("coverage", "error trying to append hidden api coverage specific properties: %s", err)
 				return
@@ -723,6 +723,10 @@
 	} else if global.ApexBootJars.Len() != 0 && !android.IsModuleInVersionedSdk(ctx.Module()) {
 		unknown = android.RemoveListFromList(unknown, b.properties.Coverage.Contents)
 		_, unknown = android.RemoveFromList("core-icu4j", unknown)
+		// This module only exists in car products.
+		// So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
+		// TODO(b/202896428): Add better way to handle this.
+		_, unknown = android.RemoveFromList("android.car-module", unknown)
 		if len(unknown) > 0 {
 			ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
 		}
@@ -821,7 +825,12 @@
 	input.gatherStubLibInfo(ctx, contents)
 
 	// Populate with flag file paths from the properties.
-	input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
+	input.extractFlagFilesFromProperties(ctx, &b.properties.HiddenAPIFlagFileProperties)
+
+	// Populate with package rules from the properties.
+	input.extractPackageRulesFromProperties(&b.sourceOnlyProperties.HiddenAPIPackageProperties)
+
+	input.gatherPropertyInfo(ctx, contents)
 
 	// Add the stub dex jars from this module's fragment dependencies.
 	input.DependencyStubDexJarsByScope.addStubDexJarsByModule(dependencyHiddenApiInfo.TransitiveStubDexJarsByScope)
@@ -858,9 +867,9 @@
 
 	// If the module specifies split_packages or package_prefixes then use those to generate the
 	// signature patterns.
-	splitPackages := b.sourceOnlyProperties.Hidden_api.Split_packages
-	packagePrefixes := b.sourceOnlyProperties.Hidden_api.Package_prefixes
-	singlePackages := b.sourceOnlyProperties.Hidden_api.Single_packages
+	splitPackages := input.SplitPackages
+	packagePrefixes := input.PackagePrefixes
+	singlePackages := input.SinglePackages
 	if splitPackages != nil || packagePrefixes != nil || singlePackages != nil {
 		output.SignaturePatternsPath = buildRuleSignaturePatternsFile(
 			ctx, output.AllFlagsPath, splitPackages, packagePrefixes, singlePackages)
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 83beb6d..f95c83f 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -285,6 +286,119 @@
 	android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
 }
 
+func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForTestWithBootclasspathFragment,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"),
+		FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"),
+		android.MockFS{
+			"my-blocked.txt":                   nil,
+			"my-max-target-o-low-priority.txt": nil,
+			"my-max-target-p.txt":              nil,
+			"my-max-target-q.txt":              nil,
+			"my-max-target-r-low-priority.txt": nil,
+			"my-removed.txt":                   nil,
+			"my-unsupported-packages.txt":      nil,
+			"my-unsupported.txt":               nil,
+			"my-new-max-target-q.txt":          nil,
+		}.AddToFixture(),
+		android.FixtureWithRootAndroidBp(`
+			bootclasspath_fragment {
+				name: "mybootclasspathfragment",
+				apex_available: ["myapex"],
+				contents: ["mybootlib", "mynewlibrary"],
+				hidden_api: {
+					unsupported: [
+							"my-unsupported.txt",
+					],
+					removed: [
+							"my-removed.txt",
+					],
+					max_target_r_low_priority: [
+							"my-max-target-r-low-priority.txt",
+					],
+					max_target_q: [
+							"my-max-target-q.txt",
+					],
+					max_target_p: [
+							"my-max-target-p.txt",
+					],
+					max_target_o_low_priority: [
+							"my-max-target-o-low-priority.txt",
+					],
+					blocked: [
+							"my-blocked.txt",
+					],
+					unsupported_packages: [
+							"my-unsupported-packages.txt",
+					],
+					split_packages: ["sdklibrary"],
+					package_prefixes: ["sdklibrary.all.mine"],
+					single_packages: ["sdklibrary.mine"],
+				},
+			}
+
+			java_library {
+				name: "mybootlib",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				system_modules: "none",
+				sdk_version: "none",
+				min_sdk_version: "1",
+				compile_dex: true,
+				permitted_packages: ["mybootlib"],
+			}
+
+			java_sdk_library {
+				name: "mynewlibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				min_sdk_version: "10",
+				compile_dex: true,
+				public: {enabled: true},
+				permitted_packages: ["mysdklibrary"],
+				hidden_api: {
+					max_target_q: [
+							"my-new-max-target-q.txt",
+					],
+					split_packages: ["sdklibrary", "newlibrary"],
+					package_prefixes: ["newlibrary.all.mine"],
+					single_packages: ["newlibrary.mine"],
+				},
+			}
+		`),
+	).RunTest(t)
+
+	// Make sure that the library exports hidden API properties for use by the bootclasspath_fragment.
+	library := result.Module("mynewlibrary", "android_common")
+	info := result.ModuleProvider(library, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo)
+	android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages)
+	android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes)
+	android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages)
+	for _, c := range HiddenAPIFlagFileCategories {
+		expectedMaxTargetQPaths := []string(nil)
+		if c.PropertyName == "max_target_q" {
+			expectedMaxTargetQPaths = []string{"my-new-max-target-q.txt"}
+		}
+		android.AssertPathsRelativeToTopEquals(t, c.PropertyName, expectedMaxTargetQPaths, info.FlagFilesByCategory[c])
+	}
+
+	// Make sure that the signature-patterns.csv is passed all the appropriate package properties
+	// from the bootclasspath_fragment and its contents.
+	fragment := result.ModuleForTests("mybootclasspathfragment", "android_common")
+	rule := fragment.Output("modular-hiddenapi/signature-patterns.csv")
+	expectedCommand := strings.Join([]string{
+		"--split-package newlibrary",
+		"--split-package sdklibrary",
+		"--package-prefix newlibrary.all.mine",
+		"--package-prefix sdklibrary.all.mine",
+		"--single-package newlibrary.mine",
+		"--single-package sdklibrary",
+	}, " ")
+	android.AssertStringDoesContain(t, "signature patterns command", rule.RuleParams.Command, expectedCommand)
+}
+
 func TestBootclasspathFragment_Test(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
diff --git a/java/classpath_element.go b/java/classpath_element.go
index 753e7f8..4962916 100644
--- a/java/classpath_element.go
+++ b/java/classpath_element.go
@@ -97,11 +97,11 @@
 // the list with its Contents field.
 //
 // Requirements/Assumptions:
-// * A fragment can be associated with more than one apex but each apex must only be associated with
-//   a single fragment from the fragments list.
-// * All of a fragment's contents must appear as a contiguous block in the same order in the
-//   libraries list.
-// * Each library must only appear in a single fragment.
+//   - A fragment can be associated with more than one apex but each apex must only be associated with
+//     a single fragment from the fragments list.
+//   - All of a fragment's contents must appear as a contiguous block in the same order in the
+//     libraries list.
+//   - Each library must only appear in a single fragment.
 //
 // The apex is used to identify which libraries belong to which fragment. First a mapping is created
 // from apex to fragment. Then the libraries are iterated over and any library in an apex is
@@ -109,13 +109,15 @@
 // standalone and have their own element.
 //
 // e.g. Given the following input:
-//     libraries: com.android.art:core-oj, com.android.art:core-libart, framework, ext
-//     fragments: com.android.art:art-bootclasspath-fragment
+//
+//	libraries: com.android.art:core-oj, com.android.art:core-libart, framework, ext
+//	fragments: com.android.art:art-bootclasspath-fragment
 //
 // Then this will return:
-//     ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]),
-//     ClasspathLibraryElement(framework),
-//     ClasspathLibraryElement(ext),
+//
+//	ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]),
+//	ClasspathLibraryElement(framework),
+//	ClasspathLibraryElement(ext),
 func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module) ClasspathElements {
 	// Create a map from apex name to the fragment module. This makes it easy to find the fragment
 	// associated with a particular apex.
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index ca27528..259e977 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -131,14 +131,14 @@
 					// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
 					if s.minSdkVersion.Specified() {
 						if s.minSdkVersion.ApiLevel.IsCurrent() {
-							jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+							jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
 						} else {
 							jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
 						}
 					}
 					if s.maxSdkVersion.Specified() {
 						if s.maxSdkVersion.ApiLevel.IsCurrent() {
-							jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
+							jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
 						} else {
 							jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String()
 						}
diff --git a/java/config/config.go b/java/config/config.go
index 1d4b242..3ca9bad 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -89,7 +89,7 @@
 	// D8 invocations are shorter lived, so we restrict their JIT tiering relative to R8.
 	// Note that the `-JXX` prefix syntax is specific to the R8/D8 invocation wrappers.
 	exportedVars.ExportStringListStaticVariable("D8Flags", append([]string{
-		"-JXmx2048M",
+		"-JXmx4096M",
 		"-JXX:+TieredCompilation",
 		"-JXX:TieredStopAtLevel=1",
 	}, dexerJavaVmFlagsList...))
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index 513c606..bfd5cf8 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -84,12 +84,36 @@
     ],
 }
 
+// Same as core-current-stubs-for-system-modules, but android annotations are
+// stripped.
+java_library {
+    name: "core-current-stubs-for-system-modules-no-annotations",
+    visibility: ["//development/sdk"],
+    static_libs: [
+        "core-current-stubs-for-system-modules",
+    ],
+    sdk_version: "none",
+    system_modules: "none",
+    dists: [
+        {
+            // Legacy dist location for the public file.
+            dest: "core-for-system-modules-no-annotations.jar",
+            targets: dist_targets,
+        },
+        {
+            dest: "system-modules/public/core-for-system-modules-no-annotations.jar",
+            targets: dist_targets,
+        },
+    ],
+    jarjar_rules: "jarjar-strip-annotations-rules.txt",
+}
+
 // Used when compiling higher-level code against core.current.stubs.
 java_system_modules {
     name: "core-public-stubs-system-modules",
     visibility: ["//visibility:public"],
     libs: [
-        "core-current-stubs-for-system-modules",
+        "core-current-stubs-for-system-modules-no-annotations",
     ],
 }
 
diff --git a/java/dex.go b/java/dex.go
index c943938..a44d792 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -42,6 +42,9 @@
 		// True if the module containing this has it set by default.
 		EnabledByDefault bool `blueprint:"mutated"`
 
+		// Whether to continue building even if warnings are emitted.  Defaults to true.
+		Ignore_warnings *bool
+
 		// If true, runs R8 in Proguard compatibility mode (default).
 		// Otherwise, runs R8 in full mode.
 		Proguard_compatibility *bool
@@ -293,7 +296,10 @@
 	}
 
 	// TODO(b/180878971): missing classes should be added to the relevant builds.
-	r8Flags = append(r8Flags, "-ignorewarnings")
+	// TODO(b/229727645): do not use true as default for Android platform builds.
+	if proptools.BoolDefault(opt.Ignore_warnings, true) {
+		r8Flags = append(r8Flags, "-ignorewarnings")
+	}
 
 	return r8Flags, r8Deps
 }
diff --git a/java/dex_test.go b/java/dex_test.go
index fbdccb6..a3e2ded 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -59,6 +59,36 @@
 		appR8.Args["r8Flags"], libHeader.String())
 	android.AssertStringDoesNotContain(t, "expected no  static_lib header jar in app javac classpath",
 		appR8.Args["r8Flags"], staticLibHeader.String())
+	android.AssertStringDoesContain(t, "expected -ignorewarnings in app r8 flags",
+		appR8.Args["r8Flags"], "-ignorewarnings")
+}
+
+func TestR8Flags(t *testing.T) {
+	result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, `
+		android_app {
+			name: "app",
+			srcs: ["foo.java"],
+			platform_apis: true,
+			optimize: {
+				shrink: false,
+				optimize: false,
+				obfuscate: false,
+				ignore_warnings: false,
+			},
+		}
+	`)
+
+	app := result.ModuleForTests("app", "android_common")
+	appR8 := app.Rule("r8")
+	android.AssertStringDoesContain(t, "expected -dontshrink in app r8 flags",
+		appR8.Args["r8Flags"], "-dontshrink")
+	android.AssertStringDoesContain(t, "expected -dontoptimize in app r8 flags",
+		appR8.Args["r8Flags"], "-dontoptimize")
+	android.AssertStringDoesContain(t, "expected -dontobfuscate in app r8 flags",
+		appR8.Args["r8Flags"], "-dontobfuscate")
+	android.AssertStringDoesNotContain(t, "expected no -ignorewarnings in app r8 flags",
+		appR8.Args["r8Flags"], "-ignorewarnings")
+
 }
 
 func TestD8(t *testing.T) {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index b4cd07a..4e416fc 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -418,7 +418,6 @@
 //
 // The location is passed as an argument to the ART tools like dex2oat instead of the real path.
 // ART tools will then reconstruct the architecture-specific real path.
-//
 func (image *bootImageVariant) imageLocations() (imageLocationsOnHost []string, imageLocationsOnDevice []string) {
 	if image.extends != nil {
 		imageLocationsOnHost, imageLocationsOnDevice = image.extends.getVariant(image.target).imageLocations()
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 9663922..9b1f43b 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -158,9 +158,7 @@
 	Compat_config *string `android:"path"`
 }
 
-//
 // Common flags passed down to build rule
-//
 type droiddocBuilderFlags struct {
 	bootClasspathArgs  string
 	classpathArgs      string
@@ -193,9 +191,7 @@
 	return false
 }
 
-//
 // Javadoc
-//
 type Javadoc struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -318,7 +314,7 @@
 	outSrcFiles := make(android.Paths, 0, len(srcFiles))
 	var aidlSrcs android.Paths
 
-	aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
+	aidlIncludeFlags := genAidlIncludeFlags(ctx, srcFiles, android.Paths{})
 
 	for _, srcFile := range srcFiles {
 		switch srcFile.Ext() {
@@ -548,9 +544,7 @@
 	rule.Build("javadoc", "javadoc")
 }
 
-//
 // Droiddoc
-//
 type Droiddoc struct {
 	Javadoc
 
@@ -827,9 +821,7 @@
 	rule.Build("javadoc", desc)
 }
 
-//
 // Exported Droiddoc Directory
-//
 var droiddocTemplateTag = dependencyTag{name: "droiddoc-template"}
 
 type ExportedDroiddocDirProperties struct {
@@ -862,9 +854,7 @@
 	d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")})
 }
 
-//
 // Defaults
-//
 type DocDefaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 932fb19..12590ca 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -42,19 +42,14 @@
 	ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
 }
 
-//
 // Droidstubs
-//
 type Droidstubs struct {
 	Javadoc
 	android.SdkBase
 
 	properties              DroidstubsProperties
-	apiFile                 android.WritablePath
-	apiXmlFile              android.WritablePath
-	lastReleasedApiXmlFile  android.WritablePath
-	privateApiFile          android.WritablePath
-	removedApiFile          android.WritablePath
+	apiFile                 android.Path
+	removedApiFile          android.Path
 	nullabilityWarningsFile android.WritablePath
 
 	checkCurrentApiTimestamp      android.WritablePath
@@ -68,9 +63,6 @@
 	annotationsZip android.WritablePath
 	apiVersionsXml android.WritablePath
 
-	apiFilePath        android.Path
-	removedApiFilePath android.Path
-
 	metadataZip android.WritablePath
 	metadataDir android.WritablePath
 }
@@ -206,9 +198,9 @@
 		return android.Paths{d.docZip}, nil
 	case ".api.txt", android.DefaultDistTag:
 		// This is the default dist path for dist properties that have no tag property.
-		return android.Paths{d.apiFilePath}, nil
+		return android.Paths{d.apiFile}, nil
 	case ".removed-api.txt":
-		return android.Paths{d.removedApiFilePath}, nil
+		return android.Paths{d.removedApiFile}, nil
 	case ".annotations.zip":
 		return android.Paths{d.annotationsZip}, nil
 	case ".api_versions.xml":
@@ -223,11 +215,11 @@
 }
 
 func (d *Droidstubs) ApiFilePath() android.Path {
-	return d.apiFilePath
+	return d.apiFile
 }
 
 func (d *Droidstubs) RemovedApiFilePath() android.Path {
-	return d.removedApiFilePath
+	return d.removedApiFile
 }
 
 func (d *Droidstubs) StubsSrcJar() android.Path {
@@ -270,24 +262,24 @@
 		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Api_filename) != "" {
 		filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
-		d.apiFile = android.PathForModuleOut(ctx, "metalava", filename)
-		cmd.FlagWithOutput("--api ", d.apiFile)
-		d.apiFilePath = d.apiFile
+		uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
+		cmd.FlagWithOutput("--api ", uncheckedApiFile)
+		d.apiFile = uncheckedApiFile
 	} else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
 		// If check api is disabled then make the source file available for export.
-		d.apiFilePath = android.PathForModuleSrc(ctx, sourceApiFile)
+		d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
 	}
 
 	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
 		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
 		String(d.properties.Removed_api_filename) != "" {
 		filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
-		d.removedApiFile = android.PathForModuleOut(ctx, "metalava", filename)
-		cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
-		d.removedApiFilePath = d.removedApiFile
+		uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
+		cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
+		d.removedApiFile = uncheckedRemovedFile
 	} else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
 		// If check api is disabled then make the source removed api file available for export.
-		d.removedApiFilePath = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
+		d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
 	}
 
 	if Bool(d.properties.Write_sdk_values) {
@@ -697,16 +689,87 @@
 
 	zipSyncCleanupCmd(rule, srcJarDir)
 
-	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
-		d.generateCheckCurrentCheckedInApiIsUpToDateBuildRules(ctx)
-
-		// Make sure that whenever the API stubs are generated that the current checked in API files are
-		// checked to make sure that they are up-to-date.
-		cmd.Validation(d.checkCurrentApiTimestamp)
-	}
-
 	rule.Build("metalava", "metalava merged")
 
+	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
+
+		if len(d.Javadoc.properties.Out) > 0 {
+			ctx.PropertyErrorf("out", "out property may not be combined with check_api")
+		}
+
+		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
+		baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
+
+		if baselineFile.Valid() {
+			ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
+		}
+
+		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
+
+		rule := android.NewRuleBuilder(pctx, ctx)
+
+		// Diff command line.
+		// -F matches the closest "opening" line, such as "package android {"
+		// and "  public class Intent {".
+		diff := `diff -u -F '{ *$'`
+
+		rule.Command().Text("( true")
+		rule.Command().
+			Text(diff).
+			Input(apiFile).Input(d.apiFile)
+
+		rule.Command().
+			Text(diff).
+			Input(removedApiFile).Input(d.removedApiFile)
+
+		msg := fmt.Sprintf(`\n******************************\n`+
+			`You have tried to change the API from what has been previously approved.\n\n`+
+			`To make these errors go away, you have two choices:\n`+
+			`   1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
+			`      to the new methods, etc. shown in the above diff.\n\n`+
+			`   2. You can update current.txt and/or removed.txt by executing the following command:\n`+
+			`         m %s-update-current-api\n\n`+
+			`      To submit the revised current.txt to the main Android repository,\n`+
+			`      you will need approval.\n`+
+			`******************************\n`, ctx.ModuleName())
+
+		rule.Command().
+			Text("touch").Output(d.checkCurrentApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build("metalavaCurrentApiCheck", "check current API")
+
+		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
+
+		// update API rule
+		rule = android.NewRuleBuilder(pctx, ctx)
+
+		rule.Command().Text("( true")
+
+		rule.Command().
+			Text("cp").Flag("-f").
+			Input(d.apiFile).Flag(apiFile.String())
+
+		rule.Command().
+			Text("cp").Flag("-f").
+			Input(d.removedApiFile).Flag(removedApiFile.String())
+
+		msg = "failed to update public API"
+
+		rule.Command().
+			Text("touch").Output(d.updateCurrentApiTimestamp).
+			Text(") || (").
+			Text("echo").Flag("-e").Flag(`"` + msg + `"`).
+			Text("; exit 38").
+			Text(")")
+
+		rule.Build("metalavaCurrentApiUpdate", "update current API")
+	}
+
 	if String(d.properties.Check_nullability_warnings) != "" {
 		if d.nullabilityWarningsFile == nil {
 			ctx.PropertyErrorf("check_nullability_warnings",
@@ -743,84 +806,6 @@
 	}
 }
 
-func (d *Droidstubs) generateCheckCurrentCheckedInApiIsUpToDateBuildRules(ctx android.ModuleContext) {
-	if len(d.Javadoc.properties.Out) > 0 {
-		ctx.PropertyErrorf("out", "out property may not be combined with check_api")
-	}
-
-	apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
-	removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
-	baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Current.Baseline_file)
-
-	if baselineFile.Valid() {
-		ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
-	}
-
-	d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
-
-	rule := android.NewRuleBuilder(pctx, ctx)
-
-	// Diff command line.
-	// -F matches the closest "opening" line, such as "package android {"
-	// and "  public class Intent {".
-	diff := `diff -u -F '{ *$'`
-
-	rule.Command().Text("( true")
-	rule.Command().
-		Text(diff).
-		Input(apiFile).Input(d.apiFile)
-
-	rule.Command().
-		Text(diff).
-		Input(removedApiFile).Input(d.removedApiFile)
-
-	msg := fmt.Sprintf(`\n******************************\n`+
-		`You have tried to change the API from what has been previously approved.\n\n`+
-		`To make these errors go away, you have two choices:\n`+
-		`   1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)\n`+
-		`      to the new methods, etc. shown in the above diff.\n\n`+
-		`   2. You can update current.txt and/or removed.txt by executing the following command:\n`+
-		`         m %s-update-current-api\n\n`+
-		`      To submit the revised current.txt to the main Android repository,\n`+
-		`      you will need approval.\n`+
-		`******************************\n`, ctx.ModuleName())
-
-	rule.Command().
-		Text("touch").Output(d.checkCurrentApiTimestamp).
-		Text(") || (").
-		Text("echo").Flag("-e").Flag(`"` + msg + `"`).
-		Text("; exit 38").
-		Text(")")
-
-	rule.Build("metalavaCurrentApiCheck", "check current API")
-
-	d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
-
-	// update API rule
-	rule = android.NewRuleBuilder(pctx, ctx)
-
-	rule.Command().Text("( true")
-
-	rule.Command().
-		Text("cp").Flag("-f").
-		Input(d.apiFile).Flag(apiFile.String())
-
-	rule.Command().
-		Text("cp").Flag("-f").
-		Input(d.removedApiFile).Flag(removedApiFile.String())
-
-	msg = "failed to update public API"
-
-	rule.Command().
-		Text("touch").Output(d.updateCurrentApiTimestamp).
-		Text(") || (").
-		Text("echo").Flag("-e").Flag(`"` + msg + `"`).
-		Text("; exit 38").
-		Text(")")
-
-	rule.Build("metalavaCurrentApiUpdate", "update current API")
-}
-
 func StubsDefaultsFactory() android.Module {
 	module := &DocDefaults{}
 
diff --git a/java/gen.go b/java/gen.go
index 1572bf0..638da25 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"path/filepath"
 	"strconv"
 	"strings"
 
@@ -116,12 +117,31 @@
 	return javaFile
 }
 
-func genAidlIncludeFlags(srcFiles android.Paths) string {
+// genAidlIncludeFlags returns additional include flags based on the relative path
+// of each .aidl file passed in srcFiles. excludeDirs is a list of paths relative to
+// the Android checkout root that should not be included in the returned flags.
+func genAidlIncludeFlags(ctx android.PathContext, srcFiles android.Paths, excludeDirs android.Paths) string {
 	var baseDirs []string
+	excludeDirsStrings := excludeDirs.Strings()
 	for _, srcFile := range srcFiles {
 		if srcFile.Ext() == ".aidl" {
 			baseDir := strings.TrimSuffix(srcFile.String(), srcFile.Rel())
-			if baseDir != "" && !android.InList(baseDir, baseDirs) {
+			baseDir = filepath.Clean(baseDir)
+			baseDirSeen := android.InList(baseDir, baseDirs) || android.InList(baseDir, excludeDirsStrings)
+
+			// For go/bp2build mixed builds, a file may be listed under a
+			// directory in the Bazel output tree that is symlinked to a
+			// directory under the android source tree. We should only
+			// include one copy of this directory so that the AIDL tool
+			// doesn't find multiple definitions of the same AIDL class.
+			// This code comes into effect when filegroups are used in mixed builds.
+			bazelPathPrefix := android.PathForBazelOut(ctx, "").String()
+			bazelBaseDir, err := filepath.Rel(bazelPathPrefix, baseDir)
+			bazelBaseDirSeen := err == nil &&
+				android.InList(bazelBaseDir, baseDirs) ||
+				android.InList(bazelBaseDir, excludeDirsStrings)
+
+			if baseDir != "" && !baseDirSeen && !bazelBaseDirSeen {
 				baseDirs = append(baseDirs, baseDir)
 			}
 		}
@@ -136,8 +156,6 @@
 	var protoSrcs android.Paths
 	var aidlSrcs android.Paths
 
-	aidlIncludeFlags := genAidlIncludeFlags(srcFiles)
-
 	for _, srcFile := range srcFiles {
 		switch srcFile.Ext() {
 		case ".aidl":
@@ -168,7 +186,7 @@
 				individualFlags[aidlSrc.String()] = flags
 			}
 		}
-		srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags+aidlIncludeFlags, individualFlags, flags.aidlDeps)
+		srcJarFiles := genAidl(ctx, aidlSrcs, flags.aidlFlags, individualFlags, flags.aidlDeps)
 		outSrcFiles = append(outSrcFiles, srcJarFiles...)
 	}
 
diff --git a/java/genrule.go b/java/genrule.go
index 5047c41..208e1f4 100644
--- a/java/genrule.go
+++ b/java/genrule.go
@@ -43,23 +43,23 @@
 //
 // Use a java_genrule to package generated java resources:
 //
-//     java_genrule {
-//         name: "generated_resources",
-//         tools: [
-//             "generator",
-//             "soong_zip",
-//         ],
-//         srcs: ["generator_inputs/**/*"],
-//         out: ["generated_android_icu4j_resources.jar"],
-//         cmd: "$(location generator) $(in) -o $(genDir) " +
-//             "&& $(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
-//     }
+//	java_genrule {
+//	    name: "generated_resources",
+//	    tools: [
+//	        "generator",
+//	        "soong_zip",
+//	    ],
+//	    srcs: ["generator_inputs/**/*"],
+//	    out: ["generated_android_icu4j_resources.jar"],
+//	    cmd: "$(location generator) $(in) -o $(genDir) " +
+//	        "&& $(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
+//	}
 //
-//     java_library {
-//         name: "lib_with_generated_resources",
-//         srcs: ["src/**/*.java"],
-//         static_libs: ["generated_resources"],
-//     }
+//	java_library {
+//	    name: "lib_with_generated_resources",
+//	    srcs: ["src/**/*.java"],
+//	    static_libs: ["generated_resources"],
+//	}
 func GenRuleFactory() android.Module {
 	module := genrule.NewGenRule()
 
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index c90b2ff..7b67803 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -378,32 +378,37 @@
 // with one Java package per line. All members of all classes within that package (but not nested
 // packages) will be updated in a property specific way.
 type HiddenAPIFlagFileProperties struct {
-	// Marks each signature in the referenced files as being unsupported.
-	Unsupported []string `android:"path"`
+	Hidden_api struct {
+		// Marks each signature in the referenced files as being unsupported.
+		Unsupported []string `android:"path"`
 
-	// Marks each signature in the referenced files as being unsupported because it has been removed.
-	// Any conflicts with other flags are ignored.
-	Removed []string `android:"path"`
+		// Marks each signature in the referenced files as being unsupported because it has been
+		// removed. Any conflicts with other flags are ignored.
+		Removed []string `android:"path"`
 
-	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
-	// and low priority.
-	Max_target_r_low_priority []string `android:"path"`
+		// Marks each signature in the referenced files as being supported only for
+		// targetSdkVersion <= R and low priority.
+		Max_target_r_low_priority []string `android:"path"`
 
-	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
-	Max_target_q []string `android:"path"`
+		// Marks each signature in the referenced files as being supported only for
+		// targetSdkVersion <= Q.
+		Max_target_q []string `android:"path"`
 
-	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
-	Max_target_p []string `android:"path"`
+		// Marks each signature in the referenced files as being supported only for
+		// targetSdkVersion <= P.
+		Max_target_p []string `android:"path"`
 
-	// Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
-	// and low priority. Any conflicts with other flags are ignored.
-	Max_target_o_low_priority []string `android:"path"`
+		// Marks each signature in the referenced files as being supported only for
+		// targetSdkVersion <= O
+		// and low priority. Any conflicts with other flags are ignored.
+		Max_target_o_low_priority []string `android:"path"`
 
-	// Marks each signature in the referenced files as being blocked.
-	Blocked []string `android:"path"`
+		// Marks each signature in the referenced files as being blocked.
+		Blocked []string `android:"path"`
 
-	// Marks each signature in every package in the referenced files as being unsupported.
-	Unsupported_packages []string `android:"path"`
+		// Marks each signature in every package in the referenced files as being unsupported.
+		Unsupported_packages []string `android:"path"`
+	}
 }
 
 type hiddenAPIFlagFileCategory struct {
@@ -428,19 +433,30 @@
 	// See HiddenAPIFlagFileProperties.Removed
 	PropertyName: "removed",
 	propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-		return properties.Removed
+		return properties.Hidden_api.Removed
 	},
 	commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 		command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
 	},
 }
 
-var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
+type hiddenAPIFlagFileCategories []*hiddenAPIFlagFileCategory
+
+func (c hiddenAPIFlagFileCategories) byProperty(name string) *hiddenAPIFlagFileCategory {
+	for _, category := range c {
+		if category.PropertyName == name {
+			return category
+		}
+	}
+	panic(fmt.Errorf("no category exists with property name %q in %v", name, c))
+}
+
+var HiddenAPIFlagFileCategories = hiddenAPIFlagFileCategories{
 	// See HiddenAPIFlagFileProperties.Unsupported
 	{
 		PropertyName: "unsupported",
 		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Unsupported
+			return properties.Hidden_api.Unsupported
 		},
 		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 			command.FlagWithInput("--unsupported ", path)
@@ -451,7 +467,7 @@
 	{
 		PropertyName: "max_target_r_low_priority",
 		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Max_target_r_low_priority
+			return properties.Hidden_api.Max_target_r_low_priority
 		},
 		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 			command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
@@ -461,7 +477,7 @@
 	{
 		PropertyName: "max_target_q",
 		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Max_target_q
+			return properties.Hidden_api.Max_target_q
 		},
 		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 			command.FlagWithInput("--max-target-q ", path)
@@ -471,7 +487,7 @@
 	{
 		PropertyName: "max_target_p",
 		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Max_target_p
+			return properties.Hidden_api.Max_target_p
 		},
 		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 			command.FlagWithInput("--max-target-p ", path)
@@ -481,7 +497,7 @@
 	{
 		PropertyName: "max_target_o_low_priority",
 		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Max_target_o_low_priority
+			return properties.Hidden_api.Max_target_o_low_priority
 		},
 		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 			command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
@@ -491,7 +507,7 @@
 	{
 		PropertyName: "blocked",
 		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Blocked
+			return properties.Hidden_api.Blocked
 		},
 		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 			command.FlagWithInput("--blocked ", path)
@@ -501,7 +517,7 @@
 	{
 		PropertyName: "unsupported_packages",
 		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Unsupported_packages
+			return properties.Hidden_api.Unsupported_packages
 		},
 		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
 			command.FlagWithInput("--unsupported ", path).Flag("--packages ")
@@ -512,13 +528,20 @@
 // FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
 type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
 
-// append appends the supplied flags files to the corresponding category in this map.
+// append the supplied flags files to the corresponding category in this map.
 func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
 	for _, category := range HiddenAPIFlagFileCategories {
 		s[category] = append(s[category], other[category]...)
 	}
 }
 
+// sort the paths for each category in this map.
+func (s FlagFilesByCategory) sort() {
+	for category, value := range s {
+		s[category] = android.SortedUniquePaths(value)
+	}
+}
+
 // HiddenAPIInfo contains information provided by the hidden API processing.
 //
 // That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
@@ -686,13 +709,70 @@
 	return stubDexJars
 }
 
-// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
-// needed for hidden API flag generation.
-type HiddenAPIFlagInput struct {
+type HiddenAPIPropertyInfo struct {
 	// FlagFilesByCategory contains the flag files that override the initial flags that are derived
 	// from the stub dex files.
 	FlagFilesByCategory FlagFilesByCategory
 
+	// See HiddenAPIFlagFileProperties.Package_prefixes
+	PackagePrefixes []string
+
+	// See HiddenAPIFlagFileProperties.Single_packages
+	SinglePackages []string
+
+	// See HiddenAPIFlagFileProperties.Split_packages
+	SplitPackages []string
+}
+
+var hiddenAPIPropertyInfoProvider = blueprint.NewProvider(HiddenAPIPropertyInfo{})
+
+// newHiddenAPIPropertyInfo creates a new initialized HiddenAPIPropertyInfo struct.
+func newHiddenAPIPropertyInfo() HiddenAPIPropertyInfo {
+	return HiddenAPIPropertyInfo{
+		FlagFilesByCategory: FlagFilesByCategory{},
+	}
+}
+
+// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
+// supplied properties and stores them in this struct.
+func (i *HiddenAPIPropertyInfo) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
+	for _, category := range HiddenAPIFlagFileCategories {
+		paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
+		i.FlagFilesByCategory[category] = paths
+	}
+}
+
+// extractPackageRulesFromProperties extracts the package rules that are specified in the supplied
+// properties and stores them in this struct.
+func (i *HiddenAPIPropertyInfo) extractPackageRulesFromProperties(p *HiddenAPIPackageProperties) {
+	i.PackagePrefixes = p.Hidden_api.Package_prefixes
+	i.SinglePackages = p.Hidden_api.Single_packages
+	i.SplitPackages = p.Hidden_api.Split_packages
+}
+
+func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.Module) {
+	for _, module := range contents {
+		if ctx.OtherModuleHasProvider(module, hiddenAPIPropertyInfoProvider) {
+			info := ctx.OtherModuleProvider(module, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo)
+			i.FlagFilesByCategory.append(info.FlagFilesByCategory)
+			i.PackagePrefixes = append(i.PackagePrefixes, info.PackagePrefixes...)
+			i.SinglePackages = append(i.SinglePackages, info.SinglePackages...)
+			i.SplitPackages = append(i.SplitPackages, info.SplitPackages...)
+		}
+	}
+
+	// Dedup and sort the information to ensure consistent builds.
+	i.FlagFilesByCategory.sort()
+	i.PackagePrefixes = android.SortedUniqueStrings(i.PackagePrefixes)
+	i.SinglePackages = android.SortedUniqueStrings(i.SinglePackages)
+	i.SplitPackages = android.SortedUniqueStrings(i.SplitPackages)
+}
+
+// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
+// needed for hidden API flag generation.
+type HiddenAPIFlagInput struct {
+	HiddenAPIPropertyInfo
+
 	// StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
 	// the initial flags for each dex member.
 	StubDexJarsByScope StubDexJarsByModule
@@ -714,10 +794,10 @@
 	RemovedTxtFiles android.Paths
 }
 
-// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
+// newHiddenAPIFlagInput creates a new initialized HiddenAPIFlagInput struct.
 func newHiddenAPIFlagInput() HiddenAPIFlagInput {
 	input := HiddenAPIFlagInput{
-		FlagFilesByCategory:          FlagFilesByCategory{},
+		HiddenAPIPropertyInfo:        newHiddenAPIPropertyInfo(),
 		StubDexJarsByScope:           StubDexJarsByModule{},
 		DependencyStubDexJarsByScope: StubDexJarsByModule{},
 		AdditionalStubDexJarsByScope: StubDexJarsByModule{},
@@ -773,15 +853,6 @@
 	i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
 }
 
-// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
-// supplied properties and stores them in this struct.
-func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
-	for _, category := range HiddenAPIFlagFileCategories {
-		paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
-		i.FlagFilesByCategory[category] = paths
-	}
-}
-
 func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByModule {
 	transitive := i.DependencyStubDexJarsByScope
 	transitive.addStubDexJarsByModule(i.StubDexJarsByScope)
diff --git a/java/java.go b/java/java.go
index dae69dc..0251b57 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,6 +24,7 @@
 	"strings"
 
 	"android/soong/bazel"
+	"android/soong/bazel/cquery"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -628,6 +629,9 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+
+	j.provideHiddenAPIPropertyInfo(ctx)
+
 	j.sdkVersion = j.SdkVersion(ctx)
 	j.minSdkVersion = j.MinSdkVersion(ctx)
 	j.maxSdkVersion = j.MaxSdkVersion(ctx)
@@ -851,11 +855,10 @@
 
 // Test option struct.
 type TestOptions struct {
+	android.CommonTestOptions
+
 	// a list of extra test configuration files that should be installed with the module.
 	Extra_test_configs []string `android:"path,arch_variant"`
-
-	// If the test is a hostside(no device required) unittest that shall be run during presubmit check.
-	Unit_test *bool
 }
 
 type testProperties struct {
@@ -1261,7 +1264,7 @@
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
-	module.Module.linter.test = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
 
 	android.InitSdkAwareModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
@@ -1277,7 +1280,7 @@
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
-	module.Module.linter.test = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
@@ -1610,7 +1613,8 @@
 	}
 }
 
-func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (j *Import) commonBuildActions(ctx android.ModuleContext) {
+	//TODO(b/231322772) these should come from Bazel once available
 	j.sdkVersion = j.SdkVersion(ctx)
 	j.minSdkVersion = j.MinSdkVersion(ctx)
 
@@ -1621,6 +1625,10 @@
 	if ctx.Windows() {
 		j.HideFromMake()
 	}
+}
+
+func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	j.commonBuildActions(ctx)
 
 	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
 
@@ -1662,19 +1670,7 @@
 		addCLCFromDep(ctx, module, j.classLoaderContexts)
 	})
 
-	if Bool(j.properties.Installable) {
-		var installDir android.InstallPath
-		if ctx.InstallInTestcases() {
-			var archDir string
-			if !ctx.Host() {
-				archDir = ctx.DeviceConfig().DeviceArch()
-			}
-			installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
-		} else {
-			installDir = android.PathForModuleInstall(ctx, "framework")
-		}
-		ctx.InstallFile(installDir, jarName, outputFile)
-	}
+	j.maybeInstall(ctx, jarName, outputFile)
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
 
@@ -1748,6 +1744,24 @@
 	})
 }
 
+func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputFile android.Path) {
+	if !Bool(j.properties.Installable) {
+		return
+	}
+
+	var installDir android.InstallPath
+	if ctx.InstallInTestcases() {
+		var archDir string
+		if !ctx.Host() {
+			archDir = ctx.DeviceConfig().DeviceArch()
+		}
+		installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir)
+	} else {
+		installDir = android.PathForModuleInstall(ctx, "framework")
+	}
+	ctx.InstallFile(installDir, jarName, outputFile)
+}
+
 func (j *Import) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "", ".jar":
@@ -2046,9 +2060,7 @@
 	return module
 }
 
-//
 // Defaults
-//
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
@@ -2063,29 +2075,29 @@
 //
 // Example:
 //
-//     java_defaults {
-//         name: "example_defaults",
-//         srcs: ["common/**/*.java"],
-//         javacflags: ["-Xlint:all"],
-//         aaptflags: ["--auto-add-overlay"],
-//     }
+//	java_defaults {
+//	    name: "example_defaults",
+//	    srcs: ["common/**/*.java"],
+//	    javacflags: ["-Xlint:all"],
+//	    aaptflags: ["--auto-add-overlay"],
+//	}
 //
-//     java_library {
-//         name: "example",
-//         defaults: ["example_defaults"],
-//         srcs: ["example/**/*.java"],
-//     }
+//	java_library {
+//	    name: "example",
+//	    defaults: ["example_defaults"],
+//	    srcs: ["example/**/*.java"],
+//	}
 //
 // is functionally identical to:
 //
-//     java_library {
-//         name: "example",
-//         srcs: [
-//             "common/**/*.java",
-//             "example/**/*.java",
-//         ],
-//         javacflags: ["-Xlint:all"],
-//     }
+//	java_library {
+//	    name: "example",
+//	    srcs: [
+//	        "common/**/*.java",
+//	        "example/**/*.java",
+//	    ],
+//	    javacflags: ["-Xlint:all"],
+//	}
 func DefaultsFactory() android.Module {
 	module := &Defaults{}
 
@@ -2247,16 +2259,27 @@
 	StaticDeps bazel.LabelListAttribute
 }
 
-// convertLibraryAttrsBp2Build converts a few shared attributes from java_* modules
-// and also separates dependencies into dynamic dependencies and static dependencies.
-// Each corresponding Bazel target type, can have a different method for handling
-// dynamic vs. static dependencies, and so these are returned to the calling function.
 type eventLogTagsAttributes struct {
 	Srcs bazel.LabelListAttribute
 }
 
+type aidlLibraryAttributes struct {
+	Srcs bazel.LabelListAttribute
+}
+
+type javaAidlLibraryAttributes struct {
+	Deps bazel.LabelListAttribute
+}
+
+// convertLibraryAttrsBp2Build converts a few shared attributes from java_* modules
+// and also separates dependencies into dynamic dependencies and static dependencies.
+// Each corresponding Bazel target type, can have a different method for handling
+// dynamic vs. static dependencies, and so these are returned to the calling function.
 func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *javaDependencyLabels) {
 	var srcs bazel.LabelListAttribute
+	var deps bazel.LabelList
+	var staticDeps bazel.LabelList
+
 	archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{})
 	for axis, configToProps := range archVariantProps {
 		for config, _props := range configToProps {
@@ -2270,18 +2293,18 @@
 	javaSrcPartition := "java"
 	protoSrcPartition := "proto"
 	logtagSrcPartition := "logtag"
+	aidlSrcPartition := "aidl"
 	srcPartitions := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
 		javaSrcPartition:   bazel.LabelPartition{Extensions: []string{".java"}, Keep_remainder: true},
 		logtagSrcPartition: bazel.LabelPartition{Extensions: []string{".logtags", ".logtag"}},
 		protoSrcPartition:  android.ProtoSrcLabelPartition,
+		aidlSrcPartition:   android.AidlSrcLabelPartition,
 	})
 
 	javaSrcs := srcPartitions[javaSrcPartition]
 
-	var logtagsSrcs bazel.LabelList
 	if !srcPartitions[logtagSrcPartition].IsEmpty() {
 		logtagsLibName := m.Name() + "_logtags"
-		logtagsSrcs = bazel.MakeLabelList([]bazel.Label{{Label: ":" + logtagsLibName}})
 		ctx.CreateBazelTargetModule(
 			bazel.BazelTargetModuleProperties{
 				Rule_class:        "event_log_tags",
@@ -2292,8 +2315,45 @@
 				Srcs: srcPartitions[logtagSrcPartition],
 			},
 		)
+
+		logtagsSrcs := bazel.MakeLabelList([]bazel.Label{{Label: ":" + logtagsLibName}})
+		javaSrcs.Append(bazel.MakeLabelListAttribute(logtagsSrcs))
 	}
-	javaSrcs.Append(bazel.MakeLabelListAttribute(logtagsSrcs))
+
+	if !srcPartitions[aidlSrcPartition].IsEmpty() {
+		aidlLibs, aidlSrcs := srcPartitions[aidlSrcPartition].Partition(func(src bazel.Label) bool {
+			return android.IsConvertedToAidlLibrary(ctx, src.OriginalModuleName)
+		})
+
+		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}})
+		}
+
+		javaAidlLibName := m.Name() + "_java_aidl_library"
+		ctx.CreateBazelTargetModule(
+			bazel.BazelTargetModuleProperties{
+				Rule_class:        "java_aidl_library",
+				Bzl_load_location: "//build/bazel/rules/java:aidl_library.bzl",
+			},
+			android.CommonAttributes{Name: javaAidlLibName},
+			&javaAidlLibraryAttributes{
+				Deps: aidlLibs,
+			},
+		)
+
+		staticDeps.Add(&bazel.Label{Label: ":" + javaAidlLibName})
+	}
 
 	var javacopts []string
 	if m.properties.Javacflags != nil {
@@ -2319,16 +2379,12 @@
 		Javacopts: bazel.MakeStringListAttribute(javacopts),
 	}
 
-	depLabels := &javaDependencyLabels{}
-
-	var deps bazel.LabelList
 	if m.properties.Libs != nil {
-		deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Libs))
+		deps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Libs))))
 	}
 
-	var staticDeps bazel.LabelList
 	if m.properties.Static_libs != nil {
-		staticDeps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs))
+		staticDeps.Append(android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(m.properties.Static_libs))))
 	}
 
 	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
@@ -2340,6 +2396,7 @@
 	// and so this should be a static dependency.
 	staticDeps.Add(protoDepLabel)
 
+	depLabels := &javaDependencyLabels{}
 	depLabels.Deps = bazel.MakeLabelListAttribute(deps)
 	depLabels.StaticDeps = bazel.MakeLabelListAttribute(staticDeps)
 
@@ -2364,7 +2421,7 @@
 			// TODO(b/220869005) remove forced dependency on current public android.jar
 			deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:public_current_android_sdk_java_import"))
 		}
-	} else if !depLabels.Deps.IsEmpty() {
+	} else if !deps.IsEmpty() {
 		ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
 	}
 
@@ -2483,5 +2540,54 @@
 	props := bazel.BazelTargetModuleProperties{Rule_class: "java_import"}
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: android.RemoveOptionalPrebuiltPrefix(i.Name())}, attrs)
+}
 
+var _ android.MixedBuildBuildable = (*Import)(nil)
+
+func (i *Import) getBazelModuleLabel(ctx android.BaseModuleContext) string {
+	return android.RemoveOptionalPrebuiltPrefixFromBazelLabel(i.GetBazelLabel(ctx, i))
+}
+
+func (i *Import) ProcessBazelQueryResponse(ctx android.ModuleContext) {
+	i.commonBuildActions(ctx)
+
+	bazelCtx := ctx.Config().BazelContext
+	filePaths, err := bazelCtx.GetOutputFiles(i.getBazelModuleLabel(ctx), android.GetConfigKey(ctx))
+	if err != nil {
+		ctx.ModuleErrorf(err.Error())
+		return
+	}
+
+	bazelJars := android.Paths{}
+	for _, bazelOutputFile := range filePaths {
+		bazelJars = append(bazelJars, android.PathForBazelOut(ctx, bazelOutputFile))
+	}
+
+	jarName := android.RemoveOptionalPrebuiltPrefix(i.Name()) + ".jar"
+	outputFile := android.PathForModuleOut(ctx, "bazelCombined", jarName)
+	TransformJarsToJar(ctx, outputFile, "combine prebuilt jars", bazelJars,
+		android.OptionalPath{}, // manifest
+		false,                  // stripDirEntries
+		[]string{},             // filesToStrip
+		[]string{},             // dirsToStrip
+	)
+	i.combinedClasspathFile = outputFile
+
+	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+		HeaderJars:                     android.PathsIfNonNil(i.combinedClasspathFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(i.combinedClasspathFile),
+		ImplementationJars:             android.PathsIfNonNil(i.combinedClasspathFile),
+		//TODO(b/240308299) include AIDL information from Bazel
+	})
+
+	i.maybeInstall(ctx, jarName, outputFile)
+}
+
+func (i *Import) QueueBazelCall(ctx android.BaseModuleContext) {
+	bazelCtx := ctx.Config().BazelContext
+	bazelCtx.QueueBazelRequest(i.getBazelModuleLabel(ctx), cquery.GetOutputFiles, android.GetConfigKey(ctx))
+}
+
+func (i *Import) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
+	return true
 }
diff --git a/java/java_test.go b/java/java_test.go
index 32b0b0f..7f0cea7 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1287,6 +1287,41 @@
 	}
 }
 
+func TestAidlIncludeDirFromConvertedFileGroupWithPathPropInMixedBuilds(t *testing.T) {
+	bp := `
+	filegroup {
+		name: "foo_aidl",
+		srcs: ["aidl/foo/IFoo.aidl"],
+		path: "aidl/foo",
+		bazel_module: { label: "//:foo_aidl" },
+	}
+	java_library {
+		name: "foo",
+		srcs: [":foo_aidl"],
+	}
+`
+
+	outBaseDir := "out/bazel/output"
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.PrepareForTestWithFilegroup,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: outBaseDir,
+				LabelToOutputFiles: map[string][]string{
+					"//:foo_aidl": []string{"aidl/foo/IFoo.aidl"},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp)
+
+	aidlCommand := result.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+	expectedAidlFlag := "-I" + outBaseDir + "/execroot/__main__/aidl/foo"
+	if !strings.Contains(aidlCommand, expectedAidlFlag) {
+		t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+	}
+}
+
 func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_library {
@@ -1667,3 +1702,82 @@
 		})
 	}
 }
+
+func TestImportMixedBuild(t *testing.T) {
+	bp := `
+		java_import {
+			name: "baz",
+			jars: [
+				"test1.jar",
+				"test2.jar",
+			],
+			bazel_module: { label: "//foo/bar:baz" },
+		}
+	`
+
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: "outputbase",
+				LabelToOutputFiles: map[string][]string{
+					"//foo/bar:baz": []string{"test1.jar", "test2.jar"},
+				},
+			}
+		}),
+	).RunTestWithBp(t, bp)
+
+	bazMod := ctx.ModuleForTests("baz", "android_common").Module()
+	producer := bazMod.(android.OutputFileProducer)
+	expectedOutputFiles := []string{".intermediates/baz/android_common/bazelCombined/baz.jar"}
+
+	outputFiles, err := producer.OutputFiles("")
+	if err != nil {
+		t.Errorf("Unexpected error getting java_import outputfiles %s", err)
+	}
+	actualOutputFiles := android.NormalizePathsForTesting(outputFiles)
+	android.AssertDeepEquals(t, "Output files are produced", expectedOutputFiles, actualOutputFiles)
+
+	javaInfoProvider := ctx.ModuleProvider(bazMod, JavaInfoProvider)
+	javaInfo, ok := javaInfoProvider.(JavaInfo)
+	if !ok {
+		t.Error("could not get JavaInfo from java_import module")
+	}
+	android.AssertDeepEquals(t, "Header JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.HeaderJars))
+	android.AssertDeepEquals(t, "Implementation/Resources JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.ImplementationAndResourcesJars))
+	android.AssertDeepEquals(t, "Implementation JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.ImplementationJars))
+}
+
+func TestGenAidlIncludeFlagsForMixedBuilds(t *testing.T) {
+	bazelOutputBaseDir := filepath.Join("out", "bazel")
+	result := android.GroupFixturePreparers(
+		PrepareForIntegrationTestWithJava,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.BazelContext = android.MockBazelContext{
+				OutputBaseDir: bazelOutputBaseDir,
+			}
+		}),
+	).RunTest(t)
+
+	ctx := &android.TestPathContext{TestResult: result}
+
+	srcDirectory := filepath.Join("frameworks", "base")
+	srcDirectoryAlreadyIncluded := filepath.Join("frameworks", "base", "core", "java")
+	bazelSrcDirectory := android.PathForBazelOut(ctx, srcDirectory)
+	bazelSrcDirectoryAlreadyIncluded := android.PathForBazelOut(ctx, srcDirectoryAlreadyIncluded)
+	srcs := android.Paths{
+		android.PathForTestingWithRel(bazelSrcDirectory.String(), "bazelAidl.aidl"),
+		android.PathForTestingWithRel(bazelSrcDirectory.String(), "bazelAidl2.aidl"),
+		android.PathForTestingWithRel(bazelSrcDirectoryAlreadyIncluded.String(), "bazelAidlExclude.aidl"),
+		android.PathForTestingWithRel(bazelSrcDirectoryAlreadyIncluded.String(), "bazelAidl2Exclude.aidl"),
+	}
+	dirsAlreadyIncluded := android.Paths{
+		android.PathForTesting(srcDirectoryAlreadyIncluded),
+	}
+
+	expectedFlags := " -Iout/bazel/execroot/__main__/frameworks/base"
+	flags := genAidlIncludeFlags(ctx, srcs, dirsAlreadyIncluded)
+	if flags != expectedFlags {
+		t.Errorf("expected flags to be %q; was %q", expectedFlags, flags)
+	}
+}
diff --git a/java/lint.go b/java/lint.go
index c27ca98..931820d 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -61,6 +61,11 @@
 
 		// If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
 		Strict_updatability_linting *bool
+
+		// Treat the code in this module as test code for @VisibleForTesting enforcement.
+		// This will be true by default for test module types, false otherwise.
+		// If soong gets support for testonly, this flag should be replaced with that.
+		Test *bool
 	}
 }
 
@@ -74,7 +79,6 @@
 	classpath               android.Paths
 	classes                 android.Path
 	extraLintCheckJars      android.Paths
-	test                    bool
 	library                 bool
 	minSdkVersion           int
 	targetSdkVersion        int
@@ -210,7 +214,7 @@
 	return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
 }
 
-func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
+func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths {
 	projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
 	// Lint looks for a lint.xml file next to the project.xml file, give it one.
 	configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
@@ -229,7 +233,7 @@
 	if l.library {
 		cmd.Flag("--library")
 	}
-	if l.test {
+	if proptools.BoolDefault(l.properties.Lint.Test, false) {
 		cmd.Flag("--test")
 	}
 	if l.manifest != nil {
@@ -241,8 +245,7 @@
 
 	// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
 	// lint separately.
-	srcsList := android.PathForModuleOut(ctx, "lint-srcs.list")
-	cmd.FlagWithRspFileInputList("--srcs ", srcsList, l.srcs)
+	cmd.FlagWithInput("--srcs ", srcsList)
 
 	cmd.FlagWithInput("--generated_srcs ", srcJarList)
 
@@ -328,12 +331,18 @@
 
 	if l.minSdkVersion != l.compileSdkVersion {
 		l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
-		_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
-		if len(filtered) != 0 {
-			ctx.PropertyErrorf("lint.warning_checks",
-				"Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
+		// Skip lint warning checks for NewApi warnings for libcore where they come from source
+		// files that reference the API they are adding (b/208656169).
+		if ctx.ModuleDir() != "libcore" {
+			_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
+
+			if len(filtered) != 0 {
+				ctx.PropertyErrorf("lint.warning_checks",
+					"Can't treat %v checks as warnings if min_sdk_version is different from sdk_version.", filtered)
+			}
 		}
-		_, filtered = android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
+
+		_, filtered := android.FilterList(l.properties.Lint.Disabled_checks, updatabilityChecks)
 		if len(filtered) != 0 {
 			ctx.PropertyErrorf("lint.disabled_checks",
 				"Can't disable %v checks if min_sdk_version is different from sdk_version.", filtered)
@@ -381,7 +390,11 @@
 		rule.Temporary(manifest)
 	}
 
-	lintPaths := l.writeLintProjectXML(ctx, rule)
+	srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
+	srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
+	rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList)
+
+	lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
 
 	html := android.PathForModuleOut(ctx, "lint", "lint-report.html")
 	text := android.PathForModuleOut(ctx, "lint", "lint-report.txt")
@@ -441,6 +454,7 @@
 		FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
 		FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
 		Flag("--exitcode").
+		Flag("--apply-suggestions"). // applies suggested fixes to files in the sandbox
 		Flags(l.properties.Lint.Flags).
 		Implicit(annotationsZipPath).
 		Implicit(apiVersionsXMLPath)
@@ -466,6 +480,13 @@
 	// The HTML output contains a date, remove it to make the output deterministic.
 	rule.Command().Text(`sed -i.tmp -e 's|Check performed at .*\(</nav>\)|\1|'`).Output(html)
 
+	// The sources in the sandbox may have been modified by --apply-suggestions, zip them up and
+	// export them out of the sandbox.
+	rule.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", android.PathForModuleOut(ctx, "lint", "suggested-fixes.zip")).
+		FlagWithArg("-C ", cmd.PathForInput(android.PathForSource(ctx))).
+		FlagWithInput("-r ", srcsList)
+
 	rule.Build("lint", "lint")
 
 	l.outputs = lintOutputs{
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index e99cb05..01e7e6e 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -101,7 +101,6 @@
 --warning_check WrongViewCast                      # 1 occurences in 1 modules
 
 --warning_check CoarseFineLocation
---warning_check ExtraText
 --warning_check IntentFilterExportedReceiver
 --warning_check MissingInflatedId
 --warning_check NotificationPermission
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 1e27238..24f8253 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -62,7 +62,7 @@
 type platformBootclasspathProperties struct {
 	BootclasspathFragmentsDepsProperties
 
-	Hidden_api HiddenAPIFlagFileProperties
+	HiddenAPIFlagFileProperties
 }
 
 func platformBootclasspathFactory() android.SingletonModule {
@@ -372,7 +372,7 @@
 	temporaryInput := newHiddenAPIFlagInput()
 
 	// Create paths to the flag files specified in the properties.
-	temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
+	temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.HiddenAPIFlagFileProperties)
 
 	// Create the monolithic info, by starting with the flag files specified on this and then merging
 	// in information from all the fragment dependencies of this.
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 1c42495..655021f 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -280,7 +280,7 @@
 	return &platformCompatConfigSingleton{}
 }
 
-//============== merged_compat_config =================
+// ============== merged_compat_config =================
 type globalCompatConfigProperties struct {
 	// name of the file into which the metadata will be copied.
 	Filename *string
diff --git a/java/robolectric.go b/java/robolectric.go
index f719521..71ffdb1 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"
 )
 
 func init() {
@@ -344,7 +345,7 @@
 		&module.testProperties)
 
 	module.Module.dexpreopter.isTest = true
-	module.Module.linter.test = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
 
 	module.testProperties.Test_suites = []string{"robolectric-tests"}
 
diff --git a/java/rro.go b/java/rro.go
index 7952c2c..c12e748 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -51,6 +51,9 @@
 	// Name of the signing certificate lineage file.
 	Lineage *string
 
+	// For overriding the --rotation-min-sdk-version property of apksig
+	RotationMinSdkVersion *string
+
 	// optional theme name. If specified, the overlay package will be applied
 	// only when the ro.boot.vendor.overlay.theme system property is set to the same value.
 	Theme *string
@@ -142,14 +145,17 @@
 	r.aapt.buildActions(ctx, r, nil, nil, aaptLinkFlags...)
 
 	// Sign the built package
-	_, certificates := collectAppDeps(ctx, r, false, false)
+	_, _, certificates := collectAppDeps(ctx, r, false, false)
 	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 != "" {
 		lineageFile = android.PathForModuleSrc(ctx, lineage)
 	}
-	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile)
+
+	rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion)
+
+	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion)
 	r.certificate = certificates[0]
 
 	r.outputFile = signed
diff --git a/java/rro_test.go b/java/rro_test.go
index be0d7ba..00ba5ba 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -33,6 +33,7 @@
 			name: "foo",
 			certificate: "platform",
 			lineage: "lineage.bin",
+			rotationMinSdkVersion: "32",
 			product_specific: true,
 			static_libs: ["bar"],
 			resource_libs: ["baz"],
@@ -89,13 +90,14 @@
 		t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags)
 	}
 
-	// Check cert signing flag.
+	// Check cert signing flags.
 	signedApk := m.Output("signed/foo.apk")
-	lineageFlag := signedApk.Args["flags"]
-	expectedLineageFlag := "--lineage lineage.bin"
-	if expectedLineageFlag != lineageFlag {
-		t.Errorf("Incorrect signing lineage flags, expected: %q, got: %q", expectedLineageFlag, lineageFlag)
+	actualCertSigningFlags := signedApk.Args["flags"]
+	expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32"
+	if expectedCertSigningFlags != actualCertSigningFlags {
+		t.Errorf("Incorrect cert signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags)
 	}
+
 	signingFlag := signedApk.Args["certificates"]
 	expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
 	if expected != signingFlag {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index f7e5d9d..8f499b1 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -2129,11 +2129,12 @@
 
 // The type of a structure that contains a field of type sdkLibraryScopeProperties
 // for each apiscope in allApiScopes, e.g. something like:
-// struct {
-//   Public sdkLibraryScopeProperties
-//   System sdkLibraryScopeProperties
-//   ...
-// }
+//
+//	struct {
+//	  Public sdkLibraryScopeProperties
+//	  System sdkLibraryScopeProperties
+//	  ...
+//	}
 var allScopeStructType = createAllScopePropertiesStructType()
 
 // Dynamically create a structure type for each apiscope in allApiScopes.
@@ -2556,9 +2557,7 @@
 	return requiredFilesFromPrebuiltApexForImport(name)
 }
 
-//
 // java_sdk_library_xml
-//
 type sdkLibraryXml struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
@@ -2700,7 +2699,10 @@
 			`"current" is not an allowed value for this attribute`)
 		return ""
 	}
-	return formattedOptionalAttribute(attrName, value)
+	// "safeValue" is safe because it translates finalized codenames to a string
+	// with their SDK int.
+	safeValue := apiLevel.String()
+	return formattedOptionalAttribute(attrName, &safeValue)
 }
 
 // formats an attribute for the xml permissions file if the value is not null
diff --git a/java/sdk_library_external.go b/java/sdk_library_external.go
index 0acaa13..4f83981 100644
--- a/java/sdk_library_external.go
+++ b/java/sdk_library_external.go
@@ -49,9 +49,10 @@
 
 // Get partition group of java module that can be used at inter-partition dependency check.
 // We currently have three groups
-//   (system, system_ext) => system partition group
-//   (vendor, odm) => vendor partition group
-//   (product) => product partition group
+//
+//	(system, system_ext) => system partition group
+//	(vendor, odm) => vendor partition group
+//	(product) => product partition group
 func (j *Module) partitionGroup(ctx android.EarlyModuleContext) partitionGroup {
 	// system and system_ext partition can be treated as the same in terms of inter-partition dependency.
 	if j.Platform() || j.SystemExtSpecific() {
diff --git a/java/testing.go b/java/testing.go
index 4000334..511cc5d 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -54,6 +54,8 @@
 		"build/soong/java/lint_defaults.txt": nil,
 		// Needed for apps that do not provide their own.
 		"build/make/target/product/security": nil,
+		// Required to generate Java used-by API coverage
+		"build/soong/scripts/gen_java_usedby_apex.sh": nil,
 	}.AddToFixture(),
 )
 
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 2707f0c..aa48e63 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -14,13 +14,13 @@
 
 // Convert makefile containing device configuration to Starlark file
 // The conversion can handle the following constructs in a makefile:
-//   * comments
-//   * simple variable assignments
-//   * $(call init-product,<file>)
-//   * $(call inherit-product-if-exists
-//   * if directives
-// All other constructs are carried over to the output starlark file as comments.
+//   - comments
+//   - simple variable assignments
+//   - $(call init-product,<file>)
+//   - $(call inherit-product-if-exists
+//   - if directives
 //
+// All other constructs are carried over to the output starlark file as comments.
 package mk2rbc
 
 import (
diff --git a/mk2rbc/soong_variables.go b/mk2rbc/soong_variables.go
index de46925..a52ec4f 100644
--- a/mk2rbc/soong_variables.go
+++ b/mk2rbc/soong_variables.go
@@ -32,8 +32,8 @@
 
 // Scans the makefile Soong uses to generate soong.variables file,
 // collecting variable names and types from the lines that look like this:
-//    $(call add_json_XXX,  <...>,             $(VAR))
 //
+//	$(call add_json_XXX,  <...>,             $(VAR))
 func FindSoongVariables(mkFile string, includeFileScope mkparser.Scope, registrar variableRegistrar) error {
 	ctx := context{includeFileScope, registrar}
 	return ctx.doFind(mkFile)
diff --git a/multitree/Android.bp b/multitree/Android.bp
index 9b16d20..78c4962 100644
--- a/multitree/Android.bp
+++ b/multitree/Android.bp
@@ -10,6 +10,7 @@
         "soong-android",
     ],
     srcs: [
+        "api_imports.go",
         "api_surface.go",
         "export.go",
         "metadata.go",
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
new file mode 100644
index 0000000..2c4cf80
--- /dev/null
+++ b/multitree/api_imports.go
@@ -0,0 +1,88 @@
+// 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 multitree
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+var (
+	apiImportNameSuffix = ".apiimport"
+)
+
+func init() {
+	RegisterApiImportsModule(android.InitRegistrationContext)
+}
+
+func RegisterApiImportsModule(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("api_imports", apiImportsFactory)
+}
+
+type ApiImports struct {
+	android.ModuleBase
+	properties apiImportsProperties
+}
+
+type apiImportsProperties struct {
+	Shared_libs []string // List of C shared libraries from API surfaces
+	Header_libs []string // List of C header libraries from API surfaces
+}
+
+// 'api_imports' is a module which describes modules available from API surfaces.
+// This module is required to get the list of all imported API modules, because
+// it is discouraged to loop and fetch all modules from its type information. The
+// only module with name 'api_imports' will be used from the build.
+func apiImportsFactory() android.Module {
+	module := &ApiImports{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidModule(module)
+	return module
+}
+
+func (imports *ApiImports) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// ApiImport module does not generate any build actions
+}
+
+type ApiImportInfo struct {
+	SharedLibs, HeaderLibs map[string]string
+}
+
+var ApiImportsProvider = blueprint.NewMutatorProvider(ApiImportInfo{}, "deps")
+
+// Store module lists into ApiImportInfo and share it over mutator provider.
+func (imports *ApiImports) DepsMutator(ctx android.BottomUpMutatorContext) {
+	generateNameMapWithSuffix := func(names []string) map[string]string {
+		moduleNameMap := make(map[string]string)
+		for _, name := range names {
+			moduleNameMap[name] = name + apiImportNameSuffix
+		}
+
+		return moduleNameMap
+	}
+
+	sharedLibs := generateNameMapWithSuffix(imports.properties.Shared_libs)
+	headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
+
+	ctx.SetProvider(ApiImportsProvider, ApiImportInfo{
+		SharedLibs: sharedLibs,
+		HeaderLibs: headerLibs,
+	})
+}
+
+func GetApiImportSuffix() string {
+	return apiImportNameSuffix
+}
diff --git a/python/androidmk.go b/python/androidmk.go
index 233d867..7dc4713 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -69,7 +69,7 @@
 
 			entries.AddStrings("LOCAL_TEST_DATA", android.AndroidMkDataPaths(p.data)...)
 
-			entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(p.testProperties.Test_options.Unit_test))
+			p.testProperties.Test_options.SetAndroidMkEntries(entries)
 		})
 	base.subAndroidMk(entries, p.binaryDecorator.pythonInstaller)
 }
diff --git a/python/python.go b/python/python.go
index eb0d3ca..8364169 100644
--- a/python/python.go
+++ b/python/python.go
@@ -438,9 +438,9 @@
 }
 
 // DepsMutator mutates dependencies for this module:
-//  * handles proto dependencies,
-//  * if required, specifies launcher and adds launcher dependencies,
-//  * applies python version mutations to Python dependencies
+//   - handles proto dependencies,
+//   - if required, specifies launcher and adds launcher dependencies,
+//   - applies python version mutations to Python dependencies
 func (p *Module) DepsMutator(ctx android.BottomUpMutatorContext) {
 	android.ProtoDeps(ctx, &p.protoProperties)
 
diff --git a/python/test.go b/python/test.go
index 7413782..b9b3465 100644
--- a/python/test.go
+++ b/python/test.go
@@ -32,12 +32,6 @@
 	ctx.RegisterModuleType("python_test", PythonTestFactory)
 }
 
-// Test option struct.
-type TestOptions struct {
-	// If the test is a hostside(no device required) unittest that shall be run during presubmit check.
-	Unit_test *bool
-}
-
 type TestProperties struct {
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
@@ -55,7 +49,7 @@
 	Java_data []string
 
 	// Test options.
-	Test_options TestOptions
+	Test_options android.CommonTestOptions
 }
 
 type testDecorator struct {
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 2361e03..32c746e 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -105,10 +105,11 @@
 				entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String())
 			}
 			entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(test.Properties.Auto_gen_config, true))
-			entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(test.Properties.Test_options.Unit_test))
 			if test.Properties.Data_bins != nil {
 				entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...)
 			}
+
+			test.Properties.Test_options.SetAndroidMkEntries(entries)
 		})
 
 	cc.AndroidMkWriteTestData(test.data, ret)
diff --git a/rust/config/global.go b/rust/config/global.go
index 9acbfb3..e676837 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.62.0.p1"
+	RustDefaultVersion = "1.63.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
diff --git a/rust/rust.go b/rust/rust.go
index 4d9fe4c..1517e62 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -1373,6 +1373,11 @@
 	var commonDepVariations []blueprint.Variation
 	var snapshotInfo *cc.SnapshotInfo
 
+	apiImportInfo := cc.GetApiImports(mod, actx)
+	for idx, lib := range deps.SharedLibs {
+		deps.SharedLibs[idx] = cc.GetReplaceModuleName(lib, apiImportInfo.SharedLibs)
+	}
+
 	if ctx.Os() == android.Android {
 		deps.SharedLibs, _ = cc.RewriteLibs(mod, &snapshotInfo, actx, ctx.Config(), deps.SharedLibs)
 	}
@@ -1393,7 +1398,7 @@
 	rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation})
 	for _, lib := range deps.Rlibs {
 		depTag := rlibDepTag
-		lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
+		lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
 
 		actx.AddVariationDependencies(rlibDepVariations, depTag, lib)
 	}
@@ -1431,7 +1436,7 @@
 		if mod.compiler.stdLinkage(ctx) == RlibLinkage {
 			for _, lib := range deps.Stdlibs {
 				depTag := rlibDepTag
-				lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
+				lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
 
 				actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
 					depTag, lib)
@@ -1455,7 +1460,7 @@
 
 	for _, lib := range deps.WholeStaticLibs {
 		depTag := cc.StaticDepTag(true)
-		lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
+		lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
 
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
@@ -1464,7 +1469,7 @@
 
 	for _, lib := range deps.StaticLibs {
 		depTag := cc.StaticDepTag(false)
-		lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
+		lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
 
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
@@ -1476,11 +1481,11 @@
 	crtVariations := cc.GetCrtVariations(ctx, mod)
 	for _, crt := range deps.CrtBegin {
 		actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag,
-			cc.RewriteSnapshotLib(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
+			cc.GetReplaceModuleName(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
 	}
 	for _, crt := range deps.CrtEnd {
 		actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag,
-			cc.RewriteSnapshotLib(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
+			cc.GetReplaceModuleName(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
 	}
 
 	if mod.sourceProvider != nil {
@@ -1503,7 +1508,7 @@
 
 // addRlibDependency will add an rlib dependency, rewriting to the snapshot library if available.
 func addRlibDependency(actx android.BottomUpMutatorContext, lib string, mod *Module, snapshotInfo *cc.SnapshotInfo, variations []blueprint.Variation) {
-	lib = cc.RewriteSnapshotLib(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
+	lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
 	actx.AddVariationDependencies(variations, rlibDepTag, lib)
 }
 
diff --git a/rust/test.go b/rust/test.go
index 6e53935..0cc3bca 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -24,12 +24,6 @@
 	"android/soong/tradefed"
 )
 
-// Test option struct.
-type TestOptions struct {
-	// If the test is a hostside(no device required) unittest that shall be run during presubmit check.
-	Unit_test *bool
-}
-
 type TestProperties struct {
 	// Disables the creation of a test-specific directory when used with
 	// relative_install_path. Useful if several tests need to be in the same
@@ -67,7 +61,7 @@
 	Test_harness *bool
 
 	// Test options.
-	Test_options TestOptions
+	Test_options android.CommonTestOptions
 
 	// Add RootTargetPreparer to auto generated test config. This guarantees the test to run
 	// with root permission.
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
index 82ba749..bb4b9fd 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -19,12 +19,12 @@
 // To use, download the logs.zip from one or more branches, and extract them
 // into subdirectories of the current directory. So for example, I have:
 //
-//   ./aosp-master/aosp_arm/std_full.log
-//   ./aosp-master/aosp_arm64/std_full.log
-//   ./aosp-master/...
-//   ./internal-master/aosp_arm/std_full.log
-//   ./internal-master/aosp_arm64/std_full.log
-//   ./internal-master/...
+//	./aosp-master/aosp_arm/std_full.log
+//	./aosp-master/aosp_arm64/std_full.log
+//	./aosp-master/...
+//	./internal-master/aosp_arm/std_full.log
+//	./internal-master/aosp_arm64/std_full.log
+//	./internal-master/...
 //
 // Then I use `go run path/to/build_broken_logs.go *`
 package main
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 2da29ee..58079aa 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -70,6 +70,8 @@
   parser.add_argument('--test-only', dest='test_only', action='store_true',
                       help=('adds testOnly="true" attribute to application. Assign true value if application elem '
                             'already has a testOnly attribute.'))
+  parser.add_argument('--override-placeholder-version', dest='new_version',
+                      help='Overrides the versionCode if it\'s set to the placeholder value of 0')
   parser.add_argument('input', help='input AndroidManifest.xml file')
   parser.add_argument('output', help='output AndroidManifest.xml file')
   return parser.parse_args()
@@ -362,6 +364,19 @@
       if max_attr and max_attr.value == 'current':
         max_attr.value = max_sdk_version
 
+def override_placeholder_version(doc, new_version):
+  """Replace the versionCode attribute value if it\'s currently
+  set to the placeholder version of 0.
+
+  Args:
+    doc: The XML document.  May be modified by this function.
+    new_version: The new version to set if versionCode is equal to 0.
+  """
+  manifest = parse_manifest(doc)
+  version = manifest.getAttribute("android:versionCode")
+  if (version == '0'):
+    manifest.setAttribute("android:versionCode", new_version)
+
 def main():
   """Program entry point."""
   try:
@@ -401,6 +416,9 @@
     if args.extract_native_libs is not None:
       add_extract_native_libs(doc, args.extract_native_libs)
 
+    if args.new_version:
+      override_placeholder_version(doc, args.new_version)
+
     with open(args.output, 'w') as f:
       write_xml(f, doc)
 
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index dad104a..0a62b10 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -643,5 +643,39 @@
     output = self.run_test(manifest_input, '9000')
     self.assert_xml_equal(output, expected)
 
+class OverrideDefaultVersionTest(unittest.TestCase):
+  """Unit tests for override_default_version function."""
+
+  def assert_xml_equal(self, output, expected):
+    self.assertEqual(ET.canonicalize(output), ET.canonicalize(expected))
+
+  def run_test(self, input_manifest, version):
+    doc = minidom.parseString(input_manifest)
+    manifest_fixer.override_placeholder_version(doc, version)
+    output = io.StringIO()
+    manifest_fixer.write_xml(output, doc)
+    return output.getvalue()
+
+  manifest_tmpl = (
+      '<?xml version="1.0" encoding="utf-8"?>\n'
+      '<manifest xmlns:android="http://schemas.android.com/apk/res/android" '
+      'android:versionCode="%s">\n'
+      '</manifest>\n')
+
+  def test_doesnt_override_existing_version(self):
+    """Tests that an existing version is not overridden"""
+    manifest_input = self.manifest_tmpl % '12345'
+    expected = manifest_input
+    output = self.run_test(manifest_input, '67890')
+    self.assert_xml_equal(output, expected)
+
+  def test_overrides_default_version(self):
+    """Tests that a default version is overridden"""
+    manifest_input = self.manifest_tmpl % '0'
+    expected = self.manifest_tmpl % '67890'
+    output = self.run_test(manifest_input, '67890')
+    self.assert_xml_equal(output, expected)
+
+
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 13ddbe7..c93055a 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -675,8 +675,8 @@
 		prepareForSdkTestWithJava,
 		java.PrepareForTestWithJavaDefaultModules,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
-		java.FixtureWithLastReleaseApis("mysdklibrary"),
-		java.FixtureConfigureApexBootJars("myapex:mybootlib"),
+		java.FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"),
+		java.FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"),
 		prepareForSdkTestWithApex,
 
 		// Add a platform_bootclasspath that depends on the fragment.
@@ -691,6 +691,7 @@
 			"my-removed.txt":                   nil,
 			"my-unsupported-packages.txt":      nil,
 			"my-unsupported.txt":               nil,
+			"my-new-max-target-q.txt":          nil,
 		}.AddToFixture(),
 		android.FixtureWithRootAndroidBp(`
 			sdk {
@@ -708,7 +709,7 @@
 			bootclasspath_fragment {
 				name: "mybootclasspathfragment",
 				apex_available: ["myapex"],
-				contents: ["mybootlib"],
+				contents: ["mybootlib", "mynewlibrary"],
 				api: {
 					stub_libs: ["mysdklibrary"],
 				},
@@ -737,7 +738,9 @@
 					unsupported_packages: [
 							"my-unsupported-packages.txt",
 					],
-					split_packages: ["*"],
+					split_packages: ["sdklibrary"],
+					package_prefixes: ["sdklibrary.all.mine"],
+					single_packages: ["sdklibrary.mine"],
 				},
 			}
 
@@ -759,6 +762,24 @@
 				public: {enabled: true},
 				permitted_packages: ["mysdklibrary"],
 			}
+
+			java_sdk_library {
+				name: "mynewlibrary",
+				apex_available: ["myapex"],
+				srcs: ["Test.java"],
+				min_sdk_version: "10",
+				compile_dex: true,
+				public: {enabled: true},
+				permitted_packages: ["mysdklibrary"],
+				hidden_api: {
+					max_target_q: [
+							"my-new-max-target-q.txt",
+					],
+					split_packages: ["sdklibrary", "newlibrary"],
+					package_prefixes: ["newlibrary.all.mine"],
+					single_packages: ["newlibrary.mine"],
+				},
+			}
 		`),
 	).RunTest(t)
 
@@ -774,7 +795,10 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["myapex"],
-    contents: ["mybootlib"],
+    contents: [
+        "mybootlib",
+        "mynewlibrary",
+    ],
     api: {
         stub_libs: ["mysdklibrary"],
     },
@@ -782,7 +806,10 @@
         unsupported: ["hiddenapi/my-unsupported.txt"],
         removed: ["hiddenapi/my-removed.txt"],
         max_target_r_low_priority: ["hiddenapi/my-max-target-r-low-priority.txt"],
-        max_target_q: ["hiddenapi/my-max-target-q.txt"],
+        max_target_q: [
+            "hiddenapi/my-max-target-q.txt",
+            "hiddenapi/my-new-max-target-q.txt",
+        ],
         max_target_p: ["hiddenapi/my-max-target-p.txt"],
         max_target_o_low_priority: ["hiddenapi/my-max-target-o-low-priority.txt"],
         blocked: ["hiddenapi/my-blocked.txt"],
@@ -806,6 +833,23 @@
 }
 
 java_sdk_library_import {
+    name: "mynewlibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: true,
+    compile_dex: true,
+    permitted_packages: ["mysdklibrary"],
+    public: {
+        jars: ["sdk_library/public/mynewlibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mynewlibrary_stub_sources"],
+        current_api: "sdk_library/public/mynewlibrary.txt",
+        removed_api: "sdk_library/public/mynewlibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+
+java_sdk_library_import {
     name: "mysdklibrary",
     prefer: false,
     visibility: ["//visibility:public"],
@@ -827,6 +871,7 @@
 my-removed.txt -> hiddenapi/my-removed.txt
 my-max-target-r-low-priority.txt -> hiddenapi/my-max-target-r-low-priority.txt
 my-max-target-q.txt -> hiddenapi/my-max-target-q.txt
+my-new-max-target-q.txt -> hiddenapi/my-new-max-target-q.txt
 my-max-target-p.txt -> hiddenapi/my-max-target-p.txt
 my-max-target-o-low-priority.txt -> hiddenapi/my-max-target-o-low-priority.txt
 my-blocked.txt -> hiddenapi/my-blocked.txt
@@ -838,6 +883,9 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
+.intermediates/mynewlibrary.stubs/android_common/javac/mynewlibrary.stubs.jar -> sdk_library/public/mynewlibrary-stubs.jar
+.intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_api.txt -> sdk_library/public/mynewlibrary.txt
+.intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_removed.txt -> sdk_library/public/mynewlibrary-removed.txt
 .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
diff --git a/sdk/build_release.go b/sdk/build_release.go
index 0494a28..ac57a32 100644
--- a/sdk/build_release.go
+++ b/sdk/build_release.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"math"
 	"reflect"
 	"strings"
 )
@@ -29,7 +30,10 @@
 	// The name of the release, e.g. S, Tiramisu, etc.
 	name string
 
-	// The index of this structure within the buildReleases list.
+	// The index of this structure within the dessertBuildReleases list.
+	//
+	// The buildReleaseCurrent does not appear in the dessertBuildReleases list as it has an ordinal value
+	// that is larger than the size of the dessertBuildReleases.
 	ordinal int
 }
 
@@ -56,7 +60,7 @@
 // addRange adds all the build releases from start (inclusive) to end (inclusive).
 func (s *buildReleaseSet) addRange(start *buildRelease, end *buildRelease) {
 	for i := start.ordinal; i <= end.ordinal; i += 1 {
-		s.addItem(buildReleases[i])
+		s.addItem(dessertBuildReleases[i])
 	}
 }
 
@@ -69,11 +73,17 @@
 // String returns a string representation of the set, sorted from earliest to latest release.
 func (s *buildReleaseSet) String() string {
 	list := []string{}
-	for _, release := range buildReleases {
+	addRelease := func(release *buildRelease) {
 		if _, ok := s.contents[release]; ok {
 			list = append(list, release.name)
 		}
 	}
+	// Add the names of the build releases in this set in the order in which they were created.
+	for _, release := range dessertBuildReleases {
+		addRelease(release)
+	}
+	// Always add "current" to the list of names last if it is present in the set.
+	addRelease(buildReleaseCurrent)
 	return fmt.Sprintf("[%s]", strings.Join(list, ","))
 }
 
@@ -81,30 +91,46 @@
 	// nameToBuildRelease contains a map from name to build release.
 	nameToBuildRelease = map[string]*buildRelease{}
 
-	// buildReleases lists all the available build releases.
-	buildReleases = []*buildRelease{}
+	// dessertBuildReleases lists all the available dessert build releases, i.e. excluding current.
+	dessertBuildReleases = []*buildRelease{}
 
 	// allBuildReleaseSet is the set of all build releases.
 	allBuildReleaseSet = &buildReleaseSet{contents: map[*buildRelease]struct{}{}}
 
-	// Add the build releases from oldest to newest.
+	// Add the dessert build releases from oldest to newest.
 	buildReleaseS = initBuildRelease("S")
 	buildReleaseT = initBuildRelease("Tiramisu")
+
+	// Add the current build release which is always treated as being more recent than any other
+	// build release, including those added in tests.
+	buildReleaseCurrent = initBuildRelease("current")
 )
 
 // initBuildRelease creates a new build release with the specified name.
 func initBuildRelease(name string) *buildRelease {
-	ordinal := len(nameToBuildRelease)
+	ordinal := len(dessertBuildReleases)
+	if name == "current" {
+		// The current build release is more recent than all other build releases, including those
+		// created in tests so use the max int value. It cannot just rely on being created after all
+		// the other build releases as some are created in tests which run after the current build
+		// release has been created.
+		ordinal = math.MaxInt
+	}
 	release := &buildRelease{name: name, ordinal: ordinal}
 	nameToBuildRelease[name] = release
-	buildReleases = append(buildReleases, release)
 	allBuildReleaseSet.addItem(release)
+	if name != "current" {
+		// As the current build release has an ordinal value that does not correspond to its position
+		// in the dessertBuildReleases list do not add it to the list.
+		dessertBuildReleases = append(dessertBuildReleases, release)
+	}
 	return release
 }
 
-// latestBuildRelease returns the latest build release, i.e. the last one added.
-func latestBuildRelease() *buildRelease {
-	return buildReleases[len(buildReleases)-1]
+// latestDessertBuildRelease returns the latest dessert release build name, i.e. the last dessert
+// release added to the list, which does not include current.
+func latestDessertBuildRelease() *buildRelease {
+	return dessertBuildReleases[len(dessertBuildReleases)-1]
 }
 
 // nameToRelease maps from build release name to the corresponding build release (if it exists) or
@@ -134,8 +160,10 @@
 		if err != nil {
 			return nil, err
 		}
-		end := latestBuildRelease()
+		end := latestDessertBuildRelease()
 		set.addRange(start, end)
+		// An open-ended range always includes the current release.
+		set.addItem(buildReleaseCurrent)
 	} else if strings.Contains(specification, "-") {
 		limits := strings.SplitN(specification, "-", 2)
 		start, err := nameToRelease(limits[0])
@@ -369,7 +397,9 @@
 // structure which are not supported by the specified target build release.
 //
 // A property is pruned if its field has a tag of the form:
-//     `supported_build_releases:"<build-release-set>"`
+//
+//	`supported_build_releases:"<build-release-set>"`
+//
 // and the resulting build release set does not contain the target build release. Properties that
 // have no such tag are assumed to be supported by all releases.
 func newPropertyPrunerByBuildRelease(propertiesStruct interface{}, targetBuildRelease *buildRelease) *propertyPruner {
diff --git a/sdk/build_release_test.go b/sdk/build_release_test.go
index 6f1ef9e..13730cb 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,T.*,F1,F2\]`, []error{err})
+		android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,F1,F2,current\]`, []error{err})
 	})
 }
 
@@ -55,7 +55,7 @@
 	t.Run("open range", func(t *testing.T) {
 		set, err := parseBuildReleaseSet("F1+")
 		android.AssertDeepEquals(t, "errors", nil, err)
-		android.AssertStringEquals(t, "set", "[F1,F2]", set.String())
+		android.AssertStringEquals(t, "set", "[F1,F2,current]", set.String())
 	})
 	t.Run("closed range", func(t *testing.T) {
 		set, err := parseBuildReleaseSet("S-F1")
diff --git a/sdk/member_trait.go b/sdk/member_trait.go
index 4229ca8..0843306 100644
--- a/sdk/member_trait.go
+++ b/sdk/member_trait.go
@@ -68,7 +68,6 @@
 // A list of sdkMemberTraitListProperty instances is created, one per member trait that provides:
 // * a reference to the member trait.
 // * a getter for the corresponding field in the properties struct.
-//
 func createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits {
 
 	var listProperties []*sdkMemberTraitListProperty
diff --git a/sdk/member_type.go b/sdk/member_type.go
index 10669fe..98f5982 100644
--- a/sdk/member_type.go
+++ b/sdk/member_type.go
@@ -80,7 +80,6 @@
 // * a reference to the member type.
 // * a getter for the corresponding field in the properties struct.
 // * a dependency tag that identifies the member type of a resolved dependency.
-//
 func createDynamicSdkMemberTypes(sdkMemberTypes []android.SdkMemberType) *dynamicSdkMemberTypes {
 
 	var listProperties []*sdkMemberTypeListProperty
diff --git a/sdk/testing.go b/sdk/testing.go
index bed11b2..f4e2b03 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -262,8 +262,7 @@
 
 	// If the generated snapshot builders not for the current release then it cannot be loaded by
 	// the current release.
-	currentBuildRelease := latestBuildRelease()
-	if snapshotBuildInfo.targetBuildRelease != currentBuildRelease {
+	if snapshotBuildInfo.targetBuildRelease != buildReleaseCurrent {
 		return
 	}
 
diff --git a/sdk/update.go b/sdk/update.go
index c555ddc..5c9376b 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -387,12 +387,11 @@
 	// Always add -current to the end
 	snapshotFileSuffix := "-current"
 
-	currentBuildRelease := latestBuildRelease()
-	targetBuildReleaseEnv := config.GetenvWithDefault("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", currentBuildRelease.name)
+	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 = currentBuildRelease
+		targetBuildRelease = buildReleaseCurrent
 	}
 
 	builder := &snapshotBuilder{
@@ -472,7 +471,7 @@
 	contents := bp.content.String()
 	// If the snapshot is being generated for the current build release then check the syntax to make
 	// sure that it is compatible.
-	if targetBuildRelease == currentBuildRelease {
+	if targetBuildRelease == buildReleaseCurrent {
 		syntaxCheckSnapshotBpFile(ctx, contents)
 	}
 
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 4de0144..9627329 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -103,12 +103,6 @@
 	Recovery_available *bool
 }
 
-// Test option struct.
-type TestOptions struct {
-	// If the test is a hostside(no device required) unittest that shall be run during presubmit check.
-	Unit_test *bool
-}
-
 type TestProperties struct {
 	// list of compatibility suites (for example "cts", "vts") that the module should be
 	// installed into.
@@ -153,7 +147,7 @@
 	Per_testcase_directory *bool
 
 	// Test options.
-	Test_options TestOptions
+	Test_options android.CommonTestOptions
 }
 
 type ShBinary struct {
@@ -464,10 +458,9 @@
 				if s.testProperties.Data_bins != nil {
 					entries.AddStrings("LOCAL_TEST_DATA_BINS", s.testProperties.Data_bins...)
 				}
-				if Bool(s.testProperties.Test_options.Unit_test) {
-					entries.SetBool("LOCAL_IS_UNIT_TEST", true)
-				}
 				entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(s.testProperties.Per_testcase_directory))
+
+				s.testProperties.Test_options.SetAndroidMkEntries(entries)
 			},
 		},
 	}}
diff --git a/shared/env.go b/shared/env.go
index 152729b..b7d3baf 100644
--- a/shared/env.go
+++ b/shared/env.go
@@ -32,10 +32,11 @@
 //
 // e.g. OUT_DIR = "out"
 // is converted to:
-// {
-//     "Key": "OUT_DIR",
-//     "Value": "out",
-// },
+//
+//	{
+//	    "Key": "OUT_DIR",
+//	    "Value": "out",
+//	},
 func EnvFileContents(envDeps map[string]string) ([]byte, error) {
 	contents := make(envFileData, 0, len(envDeps))
 	for key, value := range envDeps {
diff --git a/snapshot/recovery_snapshot.go b/snapshot/recovery_snapshot.go
index f1e31ca..ac002be 100644
--- a/snapshot/recovery_snapshot.go
+++ b/snapshot/recovery_snapshot.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go
index 294f8b6..206ecc9 100644
--- a/snapshot/snapshot.go
+++ b/snapshot/snapshot.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go
index 4a14f2e..8e5dfe4 100644
--- a/snapshot/snapshot_base.go
+++ b/snapshot/snapshot_base.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/snapshot/util.go b/snapshot/util.go
index f447052..806ac90 100644
--- a/snapshot/util.go
+++ b/snapshot/util.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/snapshot/vendor_snapshot.go b/snapshot/vendor_snapshot.go
index 9bd26c2..8f7b8c2 100644
--- a/snapshot/vendor_snapshot.go
+++ b/snapshot/vendor_snapshot.go
@@ -4,7 +4,7 @@
 // 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
+//	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,
diff --git a/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
index 4b2f795..ac3c177 100755
--- a/tests/apex_comparison_tests.sh
+++ b/tests/apex_comparison_tests.sh
@@ -33,6 +33,10 @@
 SOONG_OUTPUT_DIR="$OUTPUT_DIR/soong"
 BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel"
 
+function call_bazel() {
+  tools/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
+}
+
 function cleanup {
   # call bazel clean because some bazel outputs don't have w bits.
   call_bazel clean
@@ -54,9 +58,6 @@
 ######################
 build/soong/soong_ui.bash --make-mode BP2BUILD_VERBOSE=1 --skip-soong-tests bp2build
 
-function call_bazel() {
-  tools/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
-}
 BAZEL_OUT="$(call_bazel info output_path)"
 
 call_bazel build --config=bp2build --config=ci --config=android_arm \
diff --git a/tests/lib.sh b/tests/lib.sh
index 69ad201..6210e77 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -111,7 +111,7 @@
 
 # shellcheck disable=SC2120
 function run_soong {
-  build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
+  USE_RBE=false build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
 }
 
 function create_mock_bazel {
diff --git a/third_party/zip/reader_test.go b/third_party/zip/reader_test.go
index 11c6d6e..5f97f5c 100644
--- a/third_party/zip/reader_test.go
+++ b/third_party/zip/reader_test.go
@@ -615,7 +615,6 @@
 //
 // It's here in hex for the same reason as rZipBytes above: to avoid
 // problems with on-disk virus scanners or other zip processors.
-//
 func biggestZipBytes() []byte {
 	s := `
 0000000 50 4b 03 04 14 00 08 00 08 00 00 00 00 00 00 00
diff --git a/ui/build/build.go b/ui/build/build.go
index 5b80b4d..c61baa1 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -110,6 +110,24 @@
 	RunAllWithBazel = RunProductConfig | RunSoong | RunKati | RunKatiNinja | RunBazel
 )
 
+// checkBazelMode fails the build if there are conflicting arguments for which bazel
+// build mode to use.
+func checkBazelMode(ctx Context, config Config) {
+	// TODO(cparsons): Remove USE_BAZEL_ANALYSIS handling.
+	if config.Environment().IsEnvTrue("USE_BAZEL_ANALYSIS") {
+		if config.bazelProdMode || config.bazelDevMode {
+			ctx.Fatalf("USE_BAZEL_ANALYSIS is deprecated.\n" +
+				"Unset USE_BAZEL_ANALYSIS when using --bazel-mode or --bazel-mode-dev.")
+		} else {
+			config.bazelDevMode = true
+		}
+	}
+	if config.bazelProdMode && config.bazelDevMode {
+		ctx.Fatalf("Conflicting bazel mode.\n" +
+			"Do not specify both --bazel-mode and --bazel-mode-dev")
+	}
+}
+
 // checkProblematicFiles fails the build if existing Android.mk or CleanSpec.mk files are found at the root of the tree.
 func checkProblematicFiles(ctx Context) {
 	files := []string{"Android.mk", "CleanSpec.mk"}
@@ -201,13 +219,28 @@
 	buildLock := BecomeSingletonOrFail(ctx, config)
 	defer buildLock.Unlock()
 
+	logArgsOtherThan := func(specialTargets ...string) {
+		var ignored []string
+		for _, a := range config.Arguments() {
+			if !inList(a, specialTargets) {
+				ignored = append(ignored, a)
+			}
+		}
+		if len(ignored) > 0 {
+			ctx.Printf("ignoring arguments %q", ignored)
+		}
+	}
+
 	if inList("clean", config.Arguments()) || inList("clobber", config.Arguments()) {
+		logArgsOtherThan("clean", "clobber")
 		clean(ctx, config)
 		return
 	}
 
 	defer waitForDist(ctx)
 
+	checkBazelMode(ctx, config)
+
 	// checkProblematicFiles aborts the build if Android.mk or CleanSpec.mk are found at the root of the tree.
 	checkProblematicFiles(ctx)
 
@@ -279,6 +312,7 @@
 
 	if inList("installclean", config.Arguments()) ||
 		inList("install-clean", config.Arguments()) {
+		logArgsOtherThan("installclean", "install-clean")
 		installClean(ctx, config)
 		ctx.Println("Deleted images and staging directories.")
 		return
@@ -286,6 +320,7 @@
 
 	if inList("dataclean", config.Arguments()) ||
 		inList("data-clean", config.Arguments()) {
+		logArgsOtherThan("dataclean", "data-clean")
 		dataClean(ctx, config)
 		ctx.Println("Deleted data files.")
 		return
diff --git a/ui/build/config.go b/ui/build/config.go
index cbf1986..590aeb9 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -99,7 +99,10 @@
 
 	pathReplaced bool
 
-	useBazel bool
+	// TODO(b/243077098): Remove useBazel.
+	useBazel      bool
+	bazelProdMode bool
+	bazelDevMode  bool
 
 	// During Bazel execution, Bazel cannot write outside OUT_DIR.
 	// So if DIST_DIR is set to an external dir (outside of OUT_DIR), we need to rig it temporarily and then migrate files at the end of the build.
@@ -130,18 +133,6 @@
 	BUILD_MODULES
 )
 
-type bazelBuildMode int
-
-// Bazel-related build modes.
-const (
-	// Don't use bazel at all.
-	noBazel bazelBuildMode = iota
-
-	// Generate synthetic build files and incorporate these files into a build which
-	// partially uses Bazel. Build metadata may come from Android.bp or BUILD files.
-	mixedBuild
-)
-
 // checkTopDir validates that the current directory is at the root directory of the source tree.
 func checkTopDir(ctx Context) {
 	if _, err := os.Stat(srcDirFileCheck); err != nil {
@@ -496,7 +487,7 @@
 		UseGoma:         proto.Bool(config.UseGoma()),
 		UseRbe:          proto.Bool(config.UseRBE()),
 		BazelAsNinja:    proto.Bool(config.UseBazel()),
-		BazelMixedBuild: proto.Bool(config.bazelBuildMode() == mixedBuild),
+		BazelMixedBuild: proto.Bool(config.BazelBuildEnabled()),
 	}
 	c.Targets = append(c.Targets, config.arguments...)
 
@@ -747,6 +738,10 @@
 			c.skipSoongTests = true
 		} else if arg == "--mk-metrics" {
 			c.reportMkMetrics = true
+		} else if arg == "--bazel-mode" {
+			c.bazelProdMode = true
+		} else if arg == "--bazel-mode-dev" {
+			c.bazelDevMode = true
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -1134,16 +1129,13 @@
 	return false
 }
 
+// TODO(b/243077098): Remove UseBazel.
 func (c *configImpl) UseBazel() bool {
 	return c.useBazel
 }
 
-func (c *configImpl) bazelBuildMode() bazelBuildMode {
-	if c.Environment().IsEnvTrue("USE_BAZEL_ANALYSIS") {
-		return mixedBuild
-	} else {
-		return noBazel
-	}
+func (c *configImpl) BazelBuildEnabled() bool {
+	return c.bazelProdMode || c.bazelDevMode
 }
 
 func (c *configImpl) StartRBE() bool {
@@ -1326,6 +1318,10 @@
 	return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiPackageSuffix+".ninja")
 }
 
+func (c *configImpl) SoongVarsFile() string {
+	return filepath.Join(c.SoongOutDir(), "soong.variables")
+}
+
 func (c *configImpl) SoongNinjaFile() string {
 	return filepath.Join(c.SoongOutDir(), "build.ninja")
 }
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index e293275..63716b0 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -28,6 +28,7 @@
 	"android/soong/ui/logger"
 	smpb "android/soong/ui/metrics/metrics_proto"
 	"android/soong/ui/status"
+	"google.golang.org/protobuf/encoding/prototext"
 
 	"google.golang.org/protobuf/proto"
 )
@@ -1005,6 +1006,8 @@
 		environ             Environment
 		arguments           []string
 		useBazel            bool
+		bazelDevMode        bool
+		bazelProdMode       bool
 		expectedBuildConfig *smpb.BuildConfig
 	}{
 		{
@@ -1064,7 +1067,7 @@
 			},
 		},
 		{
-			name:    "bazel mixed build",
+			name:    "bazel mixed build from env",
 			environ: Environment{"USE_BAZEL_ANALYSIS=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
 				ForceUseGoma:    proto.Bool(false),
@@ -1075,6 +1078,30 @@
 			},
 		},
 		{
+			name:         "bazel mixed build from dev mode",
+			environ:      Environment{},
+			bazelDevMode: true,
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:    proto.Bool(false),
+				UseGoma:         proto.Bool(false),
+				UseRbe:          proto.Bool(false),
+				BazelAsNinja:    proto.Bool(false),
+				BazelMixedBuild: proto.Bool(true),
+			},
+		},
+		{
+			name:          "bazel mixed build from prod mode",
+			environ:       Environment{},
+			bazelProdMode: true,
+			expectedBuildConfig: &smpb.BuildConfig{
+				ForceUseGoma:    proto.Bool(false),
+				UseGoma:         proto.Bool(false),
+				UseRbe:          proto.Bool(false),
+				BazelAsNinja:    proto.Bool(false),
+				BazelMixedBuild: proto.Bool(true),
+			},
+		},
+		{
 			name:      "specified targets",
 			environ:   Environment{},
 			useBazel:  true,
@@ -1094,9 +1121,9 @@
 				"FORCE_USE_GOMA=1",
 				"USE_GOMA=1",
 				"USE_RBE=1",
-				"USE_BAZEL_ANALYSIS=1",
 			},
-			useBazel: true,
+			useBazel:     true,
+			bazelDevMode: true,
 			expectedBuildConfig: &smpb.BuildConfig{
 				ForceUseGoma:    proto.Bool(true),
 				UseGoma:         proto.Bool(true),
@@ -1107,17 +1134,23 @@
 		},
 	}
 
+	ctx := testContext()
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			c := &configImpl{
-				environ:   &tc.environ,
-				useBazel:  tc.useBazel,
-				arguments: tc.arguments,
+				environ:       &tc.environ,
+				useBazel:      tc.useBazel,
+				bazelDevMode:  tc.bazelDevMode,
+				bazelProdMode: tc.bazelProdMode,
+				arguments:     tc.arguments,
 			}
 			config := Config{c}
+			checkBazelMode(ctx, config)
 			actualBuildConfig := buildConfig(config)
 			if expected := tc.expectedBuildConfig; !proto.Equal(expected, actualBuildConfig) {
-				t.Errorf("Expected build config != actual build config: %#v != %#v", *expected, *actualBuildConfig)
+				t.Errorf("Build config mismatch.\n"+
+					"Expected build config: %#v\n"+
+					"Actual build config: %#v", prototext.Format(expected), prototext.Format(actualBuildConfig))
 			}
 		})
 	}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index f56964c..adc56ac 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -141,7 +141,6 @@
 	"PLATFORM_VERSION",
 	"TARGET_PRODUCT",
 	"TARGET_BUILD_VARIANT",
-	"TARGET_BUILD_TYPE",
 	"TARGET_BUILD_APPS",
 	"TARGET_BUILD_UNBUNDLED",
 	"TARGET_ARCH",
@@ -150,18 +149,11 @@
 	"TARGET_2ND_ARCH",
 	"TARGET_2ND_ARCH_VARIANT",
 	"TARGET_2ND_CPU_VARIANT",
-	"HOST_ARCH",
-	"HOST_2ND_ARCH",
 	"HOST_OS",
 	"HOST_OS_EXTRA",
 	"HOST_CROSS_OS",
-	"HOST_CROSS_ARCH",
-	"HOST_CROSS_2ND_ARCH",
-	"HOST_BUILD_TYPE",
 	"BUILD_ID",
 	"OUT_DIR",
-	"AUX_OS_VARIANT_LIST",
-	"PRODUCT_SOONG_NAMESPACES",
 	"SOONG_SDK_SNAPSHOT_PREFER",
 	"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE",
 	"SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR",
@@ -236,6 +228,13 @@
 
 		// Not used, but useful to be in the soong.log
 		"BOARD_VNDK_VERSION",
+		"TARGET_BUILD_TYPE",
+		"HOST_ARCH",
+		"HOST_2ND_ARCH",
+		"HOST_CROSS_ARCH",
+		"HOST_CROSS_2ND_ARCH",
+		"HOST_BUILD_TYPE",
+		"PRODUCT_SOONG_NAMESPACES",
 
 		"DEFAULT_WARNING_BUILD_MODULE_TYPES",
 		"DEFAULT_ERROR_BUILD_MODULE_TYPES",
diff --git a/ui/build/soong.go b/ui/build/soong.go
index cfcf990..ff6d68f 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -22,6 +22,7 @@
 	"os"
 	"path/filepath"
 	"strconv"
+	"strings"
 
 	"android/soong/ui/metrics"
 	soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
@@ -169,9 +170,8 @@
 
 	commonArgs = append(commonArgs, "-l", filepath.Join(config.FileListDir(), "Android.bp.list"))
 	invocationEnv := make(map[string]string)
-	debugMode := os.Getenv("SOONG_DELVE") != ""
-
-	if debugMode {
+	if os.Getenv("SOONG_DELVE") != "" {
+		//debug mode
 		commonArgs = append(commonArgs, "--delve_listen", os.Getenv("SOONG_DELVE"))
 		commonArgs = append(commonArgs, "--delve_path", shared.ResolveDelveBinary())
 		// GODEBUG=asyncpreemptoff=1 disables the preemption of goroutines. This
@@ -186,7 +186,7 @@
 		invocationEnv["GODEBUG"] = "asyncpreemptoff=1"
 	}
 
-	allArgs := make([]string, 0, 0)
+	var allArgs []string
 	allArgs = append(allArgs, specificArgs...)
 	allArgs = append(allArgs,
 		"--globListDir", name,
@@ -253,6 +253,12 @@
 	if config.EmptyNinjaFile() {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--empty-ninja-file")
 	}
+	if config.bazelProdMode {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode")
+	}
+	if config.bazelDevMode {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-dev")
+	}
 
 	mainSoongBuildInvocation := primaryBuilderInvocation(
 		config,
@@ -262,7 +268,7 @@
 		fmt.Sprintf("analyzing Android.bp files and generating ninja file at %s", config.SoongNinjaFile()),
 	)
 
-	if config.bazelBuildMode() == mixedBuild {
+	if config.BazelBuildEnabled() {
 		// Mixed builds call Bazel from soong_build and they therefore need the
 		// Bazel workspace to be available. Make that so by adding a dependency on
 		// the bp2build marker file to the action that invokes soong_build .
@@ -312,14 +318,6 @@
 		fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
 	)
 
-	globFiles := []string{
-		config.NamedGlobFile(soongBuildTag),
-		config.NamedGlobFile(bp2buildTag),
-		config.NamedGlobFile(jsonModuleGraphTag),
-		config.NamedGlobFile(queryviewTag),
-		config.NamedGlobFile(soongDocsTag),
-	}
-
 	// The glob .ninja files are subninja'd. However, they are generated during
 	// the build itself so we write an empty file if the file does not exist yet
 	// so that the subninja doesn't fail on clean builds
@@ -342,7 +340,7 @@
 		runGoTests:  !config.skipSoongTests,
 		// If we want to debug soong_build, we need to compile it for debugging
 		debugCompilation: os.Getenv("SOONG_DELVE") != "",
-		subninjas:        globFiles,
+		subninjas:        bootstrapGlobFileList(config),
 		primaryBuilderInvocations: []bootstrap.PrimaryBuilderInvocation{
 			mainSoongBuildInvocation,
 			bp2buildInvocation,
@@ -380,9 +378,6 @@
 	// unused variables were changed?
 	envFile := filepath.Join(config.SoongOutDir(), availableEnvFile)
 
-	buildMode := config.bazelBuildMode()
-	integratedBp2Build := buildMode == mixedBuild
-
 	// This is done unconditionally, but does not take a measurable amount of time
 	bootstrapBlueprint(ctx, config)
 
@@ -412,7 +407,7 @@
 
 		checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongBuildTag))
 
-		if integratedBp2Build || config.Bp2Build() {
+		if config.BazelBuildEnabled() || config.Bp2Build() {
 			checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(bp2buildTag))
 		}
 
@@ -453,6 +448,11 @@
 			"-f", filepath.Join(config.SoongOutDir(), ninjaFile),
 		}
 
+		if extra, ok := config.Environment().Get("SOONG_UI_NINJA_ARGS"); ok {
+			ctx.Printf(`CAUTION: arguments in $SOONG_UI_NINJA_ARGS=%q, e.g. "-n", can make soong_build FAIL or INCORRECT`, extra)
+			ninjaArgs = append(ninjaArgs, strings.Fields(extra)...)
+		}
+
 		ninjaArgs = append(ninjaArgs, targets...)
 		cmd := Command(ctx, config, "soong "+name,
 			config.PrebuiltBuildTool("ninja"), ninjaArgs...)
@@ -504,6 +504,7 @@
 	}
 
 	distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
+	distFile(ctx, config, config.SoongVarsFile(), "soong")
 
 	if !config.SkipKati() {
 		distGzipFile(ctx, config, config.SoongAndroidMk(), "soong")
diff --git a/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel b/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel
new file mode 100644
index 0000000..356b188
--- /dev/null
+++ b/ui/metrics/bp2build_progress_metrics_proto/BUILD.bazel
@@ -0,0 +1,27 @@
+# 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.
+
+load("//build/bazel/rules/python:py_proto.bzl", "py_proto_library")
+
+proto_library(
+    name = "bp2build_proto",
+    srcs = ["bp2build.proto"],
+    strip_import_prefix = "",
+)
+
+py_proto_library(
+    name = "bp2build_py_proto",
+    deps = [":bp2build_proto"],
+    visibility = ["//build/bazel/scripts/bp2build-progress:__pkg__"],
+)
diff --git a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
new file mode 100644
index 0000000..4aee88b
--- /dev/null
+++ b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package bp2build_proto;
+
+
+// Conversion progress report for root_modules .
+message Bp2buildConversionProgress {
+
+  // Soong module identifying information.
+  message Module {
+    // Name of the Soong module.
+    string name = 1;
+
+    // Directory that the Soong module is in.
+    string directory = 2;
+
+    // Module type of this module.
+    string type = 3;
+
+    // All unconverted transitive dependencies.
+    repeated string unconverted_deps = 4;
+
+    // Total number of transitive dependencies.
+    int32 num_deps = 5;
+  }
+
+  // Modules that the transitive dependencies were identified for.
+  repeated string root_modules = 1;
+
+  // Names of all dependencies of the root_modules.
+  int32 num_deps = 2;
+
+  // Module with all its unconverted transitive dependencies.
+  repeated Module unconverted = 3;
+}
diff --git a/ui/signal/signal.go b/ui/signal/signal.go
index 4929a7b..552545d 100644
--- a/ui/signal/signal.go
+++ b/ui/signal/signal.go
@@ -31,13 +31,12 @@
 // same time we do. Most of the time this means we just need to ignore the signal and we'll
 // just see errors from all of our subprocesses. But in case that fails, when we get a signal:
 //
-//   1. Wait two seconds to exit normally.
-//   2. Call cancel() which is normally the cancellation of a Context. This will send a SIGKILL
-//      to any subprocesses attached to that context.
-//   3. Wait two seconds to exit normally.
-//   4. Call cleanup() to close the log/trace buffers, then panic.
-//   5. If another two seconds passes (if cleanup got stuck, etc), then panic.
-//
+//  1. Wait two seconds to exit normally.
+//  2. Call cancel() which is normally the cancellation of a Context. This will send a SIGKILL
+//     to any subprocesses attached to that context.
+//  3. Wait two seconds to exit normally.
+//  4. Call cleanup() to close the log/trace buffers, then panic.
+//  5. If another two seconds passes (if cleanup got stuck, etc), then panic.
 func SetupSignals(log logger.Logger, cancel, cleanup func()) {
 	signals := make(chan os.Signal, 5)
 	signal.Notify(signals, os.Interrupt, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM)
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index 4d99621..fc0e21a 100644
--- a/ui/status/ninja.go
+++ b/ui/status/ninja.go
@@ -35,8 +35,7 @@
 func NewNinjaReader(ctx logger.Logger, status ToolStatus, fifo string) *NinjaReader {
 	os.Remove(fifo)
 
-	err := syscall.Mkfifo(fifo, 0666)
-	if err != nil {
+	if err := syscall.Mkfifo(fifo, 0666); err != nil {
 		ctx.Fatalf("Failed to mkfifo(%q): %v", fifo, err)
 	}
 
diff --git a/zip/zip.go b/zip/zip.go
index ae379f5..955fe68 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -201,6 +201,16 @@
 	return fmt.Sprintf("path %q is outside relative root %q", x.Path, x.RelativeRoot)
 }
 
+type ConflictingFileError struct {
+	Dest string
+	Prev string
+	Src  string
+}
+
+func (x ConflictingFileError) Error() string {
+	return fmt.Sprintf("destination %q has two files %q and %q", x.Dest, x.Prev, x.Src)
+}
+
 type ZipWriter struct {
 	time         time.Time
 	createdFiles map[string]string
@@ -605,13 +615,24 @@
 		if prev, exists := z.createdDirs[dest]; exists {
 			return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
 		}
+
+		return nil
+	}
+
+	checkDuplicateFiles := func(dest, src string) (bool, error) {
 		if prev, exists := z.createdFiles[dest]; exists {
-			return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+			if prev != src {
+				return true, ConflictingFileError{
+					Dest: dest,
+					Prev: prev,
+					Src:  src,
+				}
+			}
+			return true, nil
 		}
 
 		z.createdFiles[dest] = src
-
-		return nil
+		return false, nil
 	}
 
 	if s.IsDir() {
@@ -625,6 +646,14 @@
 			return err
 		}
 
+		duplicate, err := checkDuplicateFiles(dest, src)
+		if err != nil {
+			return err
+		}
+		if duplicate {
+			return nil
+		}
+
 		return z.writeSymlink(dest, src)
 	} else if s.Mode().IsRegular() {
 		r, err := z.fs.Open(src)
@@ -667,6 +696,14 @@
 			return err
 		}
 
+		duplicate, err := checkDuplicateFiles(dest, src)
+		if err != nil {
+			return err
+		}
+		if duplicate {
+			return nil
+		}
+
 		return z.writeFileContents(header, r)
 	} else {
 		return fmt.Errorf("%s is not a file, directory, or symlink", src)
@@ -678,7 +715,14 @@
 		return fmt.Errorf("destination %q is both a directory %q and a file %q", dest, prev, src)
 	}
 	if prev, exists := z.createdFiles[dest]; exists {
-		return fmt.Errorf("destination %q has two files %q and %q", dest, prev, src)
+		if prev != src {
+			return ConflictingFileError{
+				Dest: dest,
+				Prev: prev,
+				Src:  src,
+			}
+		}
+		return nil
 	}
 
 	if err := z.writeDirectory(filepath.Dir(dest), src, true); err != nil {
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 79cc0b4..c4832dc 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -46,6 +46,7 @@
 	"dangling -> missing": nil,
 	"a/a/d -> b":          nil,
 	"c":                   fileC,
+	"d/a/a":               nil,
 	"l_nl":                []byte("a/a/a\na/a/b\nc\n\\[\n"),
 	"l_sp":                []byte("a/a/a a/a/b c \\["),
 	"l2":                  []byte("missing\n"),
@@ -400,6 +401,17 @@
 				fh("a/a/b", fileB, zip.Deflate),
 			},
 		},
+		{
+			name: "duplicate sources",
+			args: fileArgsBuilder().
+				File("a/a/a").
+				File("a/a/a"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("a/a/a", fileA, zip.Deflate),
+			},
+		},
 
 		// errors
 		{
@@ -427,6 +439,15 @@
 				File("a/a/a"),
 			err: IncorrectRelativeRootError{},
 		},
+		{
+			name: "error conflicting file",
+			args: fileArgsBuilder().
+				SourcePrefixToStrip("a").
+				File("a/a/a").
+				SourcePrefixToStrip("d").
+				File("d/a/a"),
+			err: ConflictingFileError{},
+		},
 	}
 
 	for _, test := range testCases {
@@ -454,13 +475,17 @@
 				t.Fatalf("want error %v, got %v", test.err, err)
 			} else if test.err != nil {
 				if os.IsNotExist(test.err) {
-					if !os.IsNotExist(test.err) {
+					if !os.IsNotExist(err) {
 						t.Fatalf("want error %v, got %v", test.err, err)
 					}
 				} else if _, wantRelativeRootErr := test.err.(IncorrectRelativeRootError); wantRelativeRootErr {
 					if _, gotRelativeRootErr := err.(IncorrectRelativeRootError); !gotRelativeRootErr {
 						t.Fatalf("want error %v, got %v", test.err, err)
 					}
+				} else if _, wantConflictingFileError := test.err.(ConflictingFileError); wantConflictingFileError {
+					if _, gotConflictingFileError := err.(ConflictingFileError); !gotConflictingFileError {
+						t.Fatalf("want error %v, got %v", test.err, err)
+					}
 				} else {
 					t.Fatalf("want error %v, got %v", test.err, err)
 				}