Merge "Remove unnecessary lunch output"
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/allowlists/allowlists.go b/android/allowlists/allowlists.go
index a5799a5..a932a91 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -154,6 +154,7 @@
 		"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/startop/apps/test":                  Bp2BuildDefaultTrue,
@@ -183,9 +184,9 @@
 		"packages/modules/adb/pairing_connection":          Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb/proto":                       Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb/tls":                         Bp2BuildDefaultTrueRecursively,
-		"packages/providers/MediaProvider/tools/dialogs":   Bp2BuildDefaultTrue,
+		"packages/providers/MediaProvider/tools/dialogs":   Bp2BuildDefaultFalse, // TODO(b/242834374)
 		"packages/screensavers/Basic":                      Bp2BuildDefaultTrue,
-		"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultTrue,
+		"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
 
 		"prebuilts/clang/host/linux-x86":           Bp2BuildDefaultTrueRecursively,
 		"prebuilts/runtime/mainline/platform/sdk":  Bp2BuildDefaultTrueRecursively,
@@ -262,6 +263,7 @@
 		// build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive.
 		"build/make/tools":/* recursive = */ false,
 		"build/pesto":/* recursive = */ true,
+		"build/soong/ui/metrics/bp2build_progress_metrics_proto":/* recursive = */ true,
 
 		// 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
@@ -305,6 +307,7 @@
 		"libandroid_runtime_vm_headers",
 		"libaudioclient_aidl_conversion_util",
 		"libaudioutils_fixedfft",
+		"libbinder_aidl",
 		"libbinder_headers",
 		"libbinder_headers_platform_shared",
 		"libbluetooth-types-header",
@@ -326,6 +329,8 @@
 		"libpdx_headers",
 		"libprocpartition",
 		"libruy_static",
+		"libandroidio",
+		"libandroidio_srcs",
 		"libserviceutils",
 		"libstagefright_enc_common",
 		"libstagefright_foundation_headers",
@@ -390,6 +395,13 @@
 		//system/libhidl
 		// needed by cc_hidl_library
 		"libhidlbase",
+
+		//frameworks/native
+		"framework_native_aidl_binder",
+		"framework_native_aidl_gui",
+
+		//frameworks/native/libs/input
+		"inputconstants_aidl",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -485,8 +497,6 @@
 		"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++
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 b5bd2f0..a0895ed 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -524,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.
 //
@@ -1215,11 +1218,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) {
@@ -1231,11 +1236,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()
@@ -2010,9 +2016,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
@@ -2165,17 +2172,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/bazel.go b/android/bazel.go
index 183a2f3..aff6116 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -35,6 +35,12 @@
 	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
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 0ed973a..a5fa043 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -767,9 +767,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
 	}
 
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..da4a915 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,
diff --git a/android/config.go b/android/config.go
index 3e7dc47..15707a5 100644
--- a/android/config.go
+++ b/android/config.go
@@ -689,7 +689,7 @@
 }
 
 func (c *config) MinSupportedSdkVersion() ApiLevel {
-	return uncheckedFinalApiLevel(19)
+	return uncheckedFinalApiLevel(21)
 }
 
 func (c *config) FinalApiLevels() []ApiLevel {
@@ -798,6 +798,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.
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/defaults.go b/android/defaults.go
index 54f44bc..03b2efb 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
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..7d39238 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"path/filepath"
 	"strings"
 
 	"android/soong/bazel"
@@ -41,6 +42,11 @@
 	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 +72,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 +121,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 +189,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 +208,27 @@
 
 	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)
+	}
+}
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..f718935 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
@@ -866,10 +868,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 450dba9..bf62080 100644
--- a/android/module.go
+++ b/android/module.go
@@ -936,6 +936,20 @@
 	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
+}
+
+// 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))
+}
+
 // 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
@@ -1095,7 +1109,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)
 
@@ -1336,30 +1350,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.
diff --git a/android/module_test.go b/android/module_test.go
index 77ef146..835ab4c 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -911,3 +911,45 @@
 		})
 	}
 }
+
+func TestProcessCommonTestOptions(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{},
+		},
+	}
+	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/paths.go b/android/paths.go
index f8e7018..74d9f13 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
diff --git a/android/register.go b/android/register.go
index 4ff8fff..5832b1b 100644
--- a/android/register.go
+++ b/android/register.go
@@ -258,20 +258,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..b25f248 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 {
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/testing.go b/android/testing.go
index 85bdca4..b4429ca 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -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..2d7b0bf 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"`
 
@@ -701,20 +702,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 +728,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 e9b0815..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.
@@ -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/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/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 aba97c6..963e27b 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -960,6 +960,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 {
@@ -1085,15 +1225,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/bp2build/Android.bp b/bp2build/Android.bp
index 1fabfaa..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",
@@ -68,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/build_conversion_test.go b/bp2build/build_conversion_test.go
index c5644ed..1ac7518 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -231,6 +231,52 @@
 func TestGenerateBazelTargetModules(t *testing.T) {
 	testCases := []Bp2buildTestCase{
 		{
+			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",
@@ -244,7 +290,7 @@
 			},
 		},
 		{
-			Description: "string props",
+			Description: "string list props",
 			Blueprint: `custom {
   name: "foo",
     string_list_prop: ["a", "b"],
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 95869dd..1f69b5a 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -543,3 +543,41 @@
 		},
 	})
 }
+
+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"]`,
+			},
+			},
+		},
+	})
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 6c56d41..f6d5067 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -2514,3 +2514,29 @@
 			})...),
 	})
 }
+
+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": `["."]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index bb59c63..5846f83 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -390,3 +390,24 @@
 		},
 	})
 }
+
+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 6a47862..de57e5a 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -624,3 +624,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 ddb7bf9..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 (
@@ -1559,3 +1559,25 @@
 		})
 	}
 }
+
+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_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
index 74ad005..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,
diff --git a/bp2build/cc_prebuilt_library_static_test.go b/bp2build/cc_prebuilt_library_static_test.go
index 7498e50..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,
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/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index b598b85..de09a17 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -56,3 +56,68 @@
 		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/testing.go b/bp2build/testing.go
index 3ee5096..0f321de 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -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}
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/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 61a55ee..ba93439 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -52,6 +52,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
 
@@ -710,6 +711,7 @@
 	implementationDeps               bazel.LabelListAttribute
 	dynamicDeps                      bazel.LabelListAttribute
 	implementationDynamicDeps        bazel.LabelListAttribute
+	runtimeDeps                      bazel.LabelListAttribute
 	wholeArchiveDeps                 bazel.LabelListAttribute
 	implementationWholeArchiveDeps   bazel.LabelListAttribute
 	systemDynamicDeps                bazel.LabelListAttribute
@@ -825,6 +827,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) {
diff --git a/cc/builder.go b/cc/builder.go
index ab2b80a..f3faca8 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -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,15 @@
 			"-allow-unreferenced-elf-symbol-changes")
 	}
 
+	// TODO(b/241496591): Remove -advice-only after b/239792343 and b/239790286 are reolved.
+	if previousVersionDiff {
+		extraFlags = append(extraFlags, "-advice-only")
+	}
+
 	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.
diff --git a/cc/cc.go b/cc/cc.go
index c71fb34..336771a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -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()
 }
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 792a8e0..f025700 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -4145,7 +4145,7 @@
 		"${config.ArmArmv7ANeonCflags}",
 		"${config.ArmGenericCflags}",
 		"-target",
-		"armv7a-linux-androideabi20",
+		"armv7a-linux-androideabi21",
 	}
 
 	expectedIncludes := []string{
@@ -4176,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}"}
@@ -4269,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)
@@ -4306,7 +4305,7 @@
 			cc_library {
 				name: "%s",
 				export_include_dirs: ["%s"],
-				sdk_version: "20",
+				sdk_version: "minimum",
 				stl: "none",
 			}
 		`, lib, lib)
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 dfc718e..8a8c107 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -152,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.
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 546982b..621b58c 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -319,6 +319,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 +336,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),
 	}
 
@@ -613,6 +615,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 +776,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 +1050,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,9 +1623,39 @@
 	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 version string
+		var prevVersion string
+
 		if ctx.useVndk() {
 			// For modules linking against vndk, follow its vndk version
 			version = ctx.Module().(*Module).VndkVersion()
@@ -1628,6 +1667,7 @@
 			} else {
 				version = "current"
 			}
+			prevVersion = prevDumpRefVersion(ctx)
 		}
 
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
@@ -1646,13 +1686,24 @@
 
 		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
 
+		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)
 		}
 	}
 }
@@ -2501,6 +2552,7 @@
 		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
 		System_dynamic_deps:               linkerAttrs.systemDynamicDeps,
 		sdkAttributes:                     bp2BuildParseSdkAttributes(module),
+		Runtime_deps:                      linkerAttrs.runtimeDeps,
 	}
 
 	var attrs interface{}
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 14d1b96..fa6c279 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -68,6 +68,9 @@
 		apiLibraryDecorator.baseLinker.Properties.System_shared_libs = []string{}
 	}
 
+	apiLibraryDecorator.baseLinker.Properties.No_libcrt = BoolPtr(true)
+	apiLibraryDecorator.baseLinker.Properties.Nocrt = BoolPtr(true)
+
 	module.Init()
 
 	return module
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/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_ui/main.go b/cmd/soong_ui/main.go
index 3d18849..cb85634 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -268,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")
@@ -318,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")
@@ -401,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")
@@ -453,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 == "" {
@@ -509,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 {
@@ -518,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/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/genrule/genrule.go b/genrule/genrule.go
index b796877..6686c87 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -976,9 +976,7 @@
 var Bool = proptools.Bool
 var String = proptools.String
 
-//
 // Defaults
-//
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
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 3c8fcd3..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) {
@@ -661,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)
@@ -690,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)
@@ -1055,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(
@@ -1108,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(
diff --git a/java/app_builder.go b/java/app_builder.go
index 4348644..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, " "),
@@ -267,6 +271,18 @@
 	})
 }
 
+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 {
 	return filepath.Join("lib", target.Arch.Abi[0])
 }
diff --git a/java/app_import.go b/java/app_import.go
index 9d199d6..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
@@ -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 0f973ba..23635b9 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -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)
diff --git a/java/base.go b/java/base.go
index 94daf37..fe92b47 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 "":
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/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/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..901419c 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
@@ -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/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 481c625..210b883 100644
--- a/java/java.go
+++ b/java/java.go
@@ -629,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)
@@ -852,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 {
@@ -1262,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)
@@ -1278,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
diff --git a/java/java_test.go b/java/java_test.go
index 9e5cf0c..bfd97eb 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 {
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/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 9c8c53b..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
@@ -149,7 +152,10 @@
 	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/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/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/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/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..f7a2d7b 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -201,7 +201,20 @@
 	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
 	}
@@ -279,6 +292,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 +300,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/soong.go b/ui/build/soong.go
index 29c3b65..519506e 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"
@@ -445,6 +446,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...)
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/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)
 				}