Merge tag 'android-security-13.0.0_r18' into staging/lineage-20.0_android-security-13.0.0_r18

Android Security 13.0.0 Release 18 (11698590)

* tag 'android-security-13.0.0_r18':
  java_sdk_library_import: Copy all prebuilt properties to child modules
  Expose avb_hash_algorithm as a property.

Change-Id: I2013d84c682b3c6e6e719267c894385d8bf64b11
diff --git a/android/arch.go b/android/arch.go
index cbf77c7..3587b46 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -655,7 +655,8 @@
 	prefer32 := os == Windows
 
 	// Determine the multilib selection for this module.
-	multilib, extraMultilib := decodeMultilib(base, os)
+	force_first_on_device := mctx.Config().ForceMultilibFirstOnDevice()
+	multilib, extraMultilib := decodeMultilib(base, os, force_first_on_device)
 
 	// Convert the multilib selection into a list of Targets.
 	targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
@@ -730,7 +731,7 @@
 // multilib from the factory's call to InitAndroidArchModule if none was set.  For modules that
 // called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
 // the actual multilib in extraMultilib.
-func decodeMultilib(base *ModuleBase, os OsType) (multilib, extraMultilib string) {
+func decodeMultilib(base *ModuleBase, os OsType, force_first_on_device bool) (multilib, extraMultilib string) {
 	// First check the "android.compile_multilib" or "host.compile_multilib" properties.
 	switch os.Class {
 	case Device:
@@ -749,6 +750,13 @@
 		multilib = base.commonProperties.Default_multilib
 	}
 
+	// If a device is configured with multiple targets, this option
+	// force all device targets that prefer32 to be compiled only as
+	// the first target.
+	if force_first_on_device && os.Class == Device && (multilib == "prefer32" || multilib == "first_prefer32") {
+		multilib = "first"
+	}
+
 	if base.commonProperties.UseTargetVariants {
 		// Darwin has the concept of "universal binaries" which is implemented in Soong by
 		// building both x86_64 and arm64 variants, and having select module types know how to
diff --git a/android/config.go b/android/config.go
index ba95c5a..9663121 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1093,6 +1093,10 @@
 	return append([]string(nil), c.productVariables.NamespacesToExport...)
 }
 
+func (c *config) IncludeTags() []string {
+	return c.productVariables.IncludeTags
+}
+
 func (c *config) HostStaticBinaries() bool {
 	return Bool(c.productVariables.HostStaticBinaries)
 }
@@ -1239,6 +1243,10 @@
 	return c.config.productVariables.DeviceKernelHeaders
 }
 
+func (c *deviceConfig) TargetSpecificHeaderPath() string {
+	return String(c.config.productVariables.TargetSpecificHeaderPath)
+}
+
 // JavaCoverageEnabledForPath returns whether Java code coverage is enabled for
 // path. Coverage is enabled by default when the product variable
 // JavaCoveragePaths is empty. If JavaCoveragePaths is not empty, coverage is
@@ -1701,6 +1709,10 @@
 	return c.config.productVariables.GenerateAidlNdkPlatformBackend
 }
 
+func (c *config) ForceMultilibFirstOnDevice() bool {
+	return c.productVariables.ForceMultilibFirstOnDevice
+}
+
 // The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
 // Such lists are used in the build system for things like bootclasspath jars or system server jars.
 // The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
diff --git a/android/makevars.go b/android/makevars.go
index a74185a..557ea8b 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -466,7 +466,7 @@
 			fmt.Fprintf(buf, " %s", dep.String())
 		}
 		fmt.Fprintln(buf)
-		fmt.Fprintln(buf, "\t@echo \"Install $@\"")
+		fmt.Fprintln(buf, "\t@echo \"Install: $@\"")
 		fmt.Fprintf(buf, "\trm -f $@ && cp -f %s $< $@\n", preserveSymlinksFlag)
 		if install.executable {
 			fmt.Fprintf(buf, "\tchmod +x $@\n")
@@ -510,7 +510,7 @@
 			fromStr = symlink.absFrom
 		}
 
-		fmt.Fprintln(buf, "\t@echo \"Symlink $@\"")
+		fmt.Fprintln(buf, "\t@echo \"Symlink: $@\"")
 		fmt.Fprintf(buf, "\trm -f $@ && ln -sfn %s $@", fromStr)
 		fmt.Fprintln(buf)
 		fmt.Fprintln(buf)
diff --git a/android/namespace.go b/android/namespace.go
index fc7bc29..85f276a 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -136,6 +136,9 @@
 			return fmt.Errorf("a namespace must be the first module in the file")
 		}
 	}
+	if (namespace.exportToKati) {
+		r.rootNamespace.visibleNamespaces = append(r.rootNamespace.visibleNamespaces, namespace)
+	}
 	r.sortedNamespaces.add(namespace)
 
 	r.namespacesByDir.Store(namespace.Path, namespace)
diff --git a/android/neverallow.go b/android/neverallow.go
index aa47bca..38d9722 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -153,7 +153,9 @@
 	javaDeviceForHostProjectsAllowedList := []string{
 		"development/build",
 		"external/guava",
+		"external/kotlinx.coroutines",
 		"external/robolectric-shadows",
+		"external/robolectric",
 		"frameworks/layoutlib",
 	}
 
diff --git a/android/paths.go b/android/paths.go
index e7829b9..fd04830 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1080,6 +1080,31 @@
 	return ret, nil
 }
 
+// pathForSourceRelaxed creates a SourcePath from pathComponents, but does not check that it exists.
+// It differs from pathForSource in that the path is allowed to exist outside of the PathContext.
+func pathForSourceRelaxed(ctx PathContext, pathComponents ...string) (SourcePath, error) {
+	p := filepath.Join(pathComponents...)
+	ret := SourcePath{basePath{p, ""}, "."}
+
+	abs, err := filepath.Abs(ret.String())
+	if err != nil {
+		return ret, err
+	}
+	buildroot, err := filepath.Abs(ctx.Config().soongOutDir)
+	if err != nil {
+		return ret, err
+	}
+	if strings.HasPrefix(abs, buildroot) {
+		return ret, fmt.Errorf("source path %s is in output", abs)
+	}
+
+	if pathtools.IsGlob(ret.String()) {
+		return ret, fmt.Errorf("path may not contain a glob: %s", ret.String())
+	}
+
+	return ret, nil
+}
+
 // existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
 // path does not exist.
 func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err error) {
@@ -1134,6 +1159,31 @@
 	return path
 }
 
+// PathForSourceRelaxed joins the provided path components.  Unlike PathForSource,
+// the result is allowed to exist outside of the source dir.
+// On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
+func PathForSourceRelaxed(ctx PathContext, pathComponents ...string) SourcePath {
+	path, err := pathForSourceRelaxed(ctx, pathComponents...)
+	if err != nil {
+		reportPathError(ctx, err)
+	}
+
+	if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
+		exists, err := existsWithDependencies(ctx, path)
+		if err != nil {
+			reportPathError(ctx, err)
+		}
+		if !exists {
+			modCtx.AddMissingDependencies([]string{path.String()})
+		}
+	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
+		ReportPathErrorf(ctx, "%s: %s", path, err.Error())
+	} else if !exists {
+		ReportPathErrorf(ctx, "source path %s does not exist", path)
+	}
+	return path
+}
+
 // ExistentPathForSource returns an OptionalPath with the SourcePath, rooted from SrcDir, *not*
 // rooted from the module's local source directory, if the path exists, or an empty OptionalPath if
 // it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state
diff --git a/android/register.go b/android/register.go
index c505833..a29cfea 100644
--- a/android/register.go
+++ b/android/register.go
@@ -160,6 +160,7 @@
 func NewContext(config Config) *Context {
 	ctx := &Context{blueprint.NewContext(), config}
 	ctx.SetSrcDir(absSrcDir)
+	ctx.AddIncludeTags(config.IncludeTags()...)
 	return ctx
 }
 
diff --git a/android/sdk.go b/android/sdk.go
index 3a56240..1ce692f 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -661,6 +661,10 @@
 	// an Android.bp file.
 	RequiresBpProperty() bool
 
+	// SupportedBuildReleases returns the string representation of a set of target build releases that
+	// support this member type.
+	SupportedBuildReleases() string
+
 	// UsableWithSdkAndSdkSnapshot returns true if the member type supports the sdk/sdk_snapshot,
 	// false otherwise.
 	UsableWithSdkAndSdkSnapshot() bool
@@ -760,6 +764,11 @@
 	// property to be specifiable in an Android.bp file.
 	BpPropertyNotRequired bool
 
+	// The name of the first targeted build release.
+	//
+	// If not specified then it is assumed to be available on all targeted build releases.
+	SupportedBuildReleaseSpecification string
+
 	SupportsSdk     bool
 	HostOsDependent bool
 
@@ -780,6 +789,10 @@
 	return !b.BpPropertyNotRequired
 }
 
+func (b *SdkMemberTypeBase) SupportedBuildReleases() string {
+	return b.SupportedBuildReleaseSpecification
+}
+
 func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool {
 	return b.SupportsSdk
 }
@@ -933,6 +946,10 @@
 
 	// RequiresTrait returns true if this member is expected to provide the specified trait.
 	RequiresTrait(trait SdkMemberTrait) bool
+
+	// IsTargetBuildBeforeTiramisu return true if the target build release for which this snapshot is
+	// being generated is before Tiramisu, i.e. S.
+	IsTargetBuildBeforeTiramisu() bool
 }
 
 // ExportedComponentsInfo contains information about the components that this module exports to an
diff --git a/android/variable.go b/android/variable.go
index 373891a..e56fd77 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -73,6 +73,13 @@
 			Header_libs         []string `android:"arch_variant"`
 		} `android:"arch_variant"`
 
+		Malloc_not_svelte_libc32 struct {
+			Cflags              []string `android:"arch_variant"`
+			Shared_libs         []string `android:"arch_variant"`
+			Whole_static_libs   []string `android:"arch_variant"`
+			Exclude_static_libs []string `android:"arch_variant"`
+		} `android:"arch_variant"`
+
 		Malloc_zero_contents struct {
 			Cflags []string `android:"arch_variant"`
 		} `android:"arch_variant"`
@@ -134,6 +141,7 @@
 		Eng struct {
 			Cflags   []string
 			Cppflags []string
+			Init_rc  []string
 			Lto      struct {
 				Never *bool
 			}
@@ -259,6 +267,7 @@
 	Always_use_prebuilt_sdks     *bool    `json:",omitempty"`
 	Skip_boot_jars_check         *bool    `json:",omitempty"`
 	Malloc_not_svelte            *bool    `json:",omitempty"`
+	Malloc_not_svelte_libc32     *bool    `json:",omitempty"`
 	Malloc_zero_contents         *bool    `json:",omitempty"`
 	Malloc_pattern_fill_contents *bool    `json:",omitempty"`
 	Safestack                    *bool    `json:",omitempty"`
@@ -330,6 +339,8 @@
 
 	DeviceKernelHeaders []string `json:",omitempty"`
 
+	TargetSpecificHeaderPath *string `json:",omitempty"`
+
 	ExtraVndkVersions []string `json:",omitempty"`
 
 	NamespacesToExport []string `json:",omitempty"`
@@ -443,6 +454,10 @@
 	SepolicyFreezeTestExtraPrebuiltDirs []string `json:",omitempty"`
 
 	GenerateAidlNdkPlatformBackend bool `json:",omitempty"`
+
+	ForceMultilibFirstOnDevice bool `json:",omitempty"`
+
+	IncludeTags []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -487,6 +502,7 @@
 		AAPTPrebuiltDPI:     []string{"xhdpi", "xxhdpi"},
 
 		Malloc_not_svelte:            boolPtr(true),
+		Malloc_not_svelte_libc32:     boolPtr(true),
 		Malloc_zero_contents:         boolPtr(true),
 		Malloc_pattern_fill_contents: boolPtr(false),
 		Safestack:                    boolPtr(false),
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 954f8d0..ef347d8 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -758,6 +758,13 @@
 	return includeVariableNow(bpVariable{"cflags", bpparser.ListType}, ctx)
 }
 
+func exportCflags(ctx variableAssignmentContext) error {
+	// The Soong replacement for EXPORT_CFLAGS doesn't need the same extra escaped quotes that were present in Make
+	ctx.mkvalue = ctx.mkvalue.Clone()
+	ctx.mkvalue.ReplaceLiteral(`\"`, `"`)
+	return includeVariableNow(bpVariable{"export_cflags", bpparser.ListType}, ctx)
+}
+
 func proguardEnabled(ctx variableAssignmentContext) error {
 	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
 	if err != nil {
diff --git a/apex/apex.go b/apex/apex.go
index 951157f..f12c517 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2776,61 +2776,13 @@
 	// Module separator
 	//
 	m["com.android.btservices"] = []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",
+		// empty
 	}
 	//
 	// 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",
+		// empty
 	}
 	//
 	// Module separator
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b3036b1..36d5306 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7264,6 +7264,28 @@
 	android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String())
 }
 
+func TestApexSetApksModuleAssignment(t *testing.T) {
+	ctx := testApex(t, `
+		apex_set {
+			name: "myapex",
+			set: ":myapex_apks_file",
+		}
+
+		filegroup {
+			name: "myapex_apks_file",
+			srcs: ["myapex.apks"],
+		}
+	`)
+
+	m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+
+	// Check that the extractor produces the correct apks file from the input module
+	extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.apks"
+	extractedApex := m.Output(extractorOutput)
+
+	android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings())
+}
+
 func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) {
 	t.Helper()
 
@@ -8254,6 +8276,30 @@
 	}
 }
 
+func TestApexSet_NativeBridge(t *testing.T) {
+	ctx := testApex(t, `
+		apex_set {
+			name: "myapex",
+			set: "myapex.apks",
+			filename: "foo_v2.apex",
+			overrides: ["foo"],
+		}
+	`,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.Targets[android.Android] = []android.Target{
+				{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "", Abi: []string{"x86_64"}}},
+				{Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled},
+			}
+		}),
+	)
+
+	m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+
+	// Check extract_apks tool parameters. No native bridge arch expected
+	extractedApex := m.Output("extracted/myapex.apks")
+	android.AssertStringEquals(t, "abis", "X86_64", extractedApex.Args["abis"])
+}
+
 func TestNoStaticLinkingToStubsLib(t *testing.T) {
 	testApexError(t, `.*required by "mylib" is a native library providing stub.*`, `
 		apex {
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 187e0df..e9261c0 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -24,6 +24,7 @@
 	"android/soong/android"
 	"android/soong/java"
 	"android/soong/provenance"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -817,6 +818,8 @@
 	}
 	apexSet := android.SingleSourcePathFromSupplier(ctx, srcsSupplier, "set")
 	p.extractedApex = android.PathForModuleOut(ctx, "extracted", apexSet.Base())
+	// Filter out NativeBridge archs (b/260115309)
+	abis := java.SupportedAbis(ctx, true)
 	ctx.Build(pctx,
 		android.BuildParams{
 			Rule:        extractMatchingApex,
@@ -824,7 +827,7 @@
 			Inputs:      android.Paths{apexSet},
 			Output:      p.extractedApex,
 			Args: map[string]string{
-				"abis":              strings.Join(java.SupportedAbis(ctx), ","),
+				"abis":              strings.Join(abis, ","),
 				"allow-prereleased": strconv.FormatBool(proptools.Bool(p.properties.Prerelease)),
 				"sdk-version":       ctx.Config().PlatformSdkVersion().String(),
 			},
@@ -839,17 +842,17 @@
 
 type ApexExtractorProperties struct {
 	// the .apks file path that contains prebuilt apex files to be extracted.
-	Set *string
+	Set *string `android:"path"`
 
 	Sanitized struct {
 		None struct {
-			Set *string
+			Set *string `android:"path"`
 		}
 		Address struct {
-			Set *string
+			Set *string `android:"path"`
 		}
 		Hwaddress struct {
-			Set *string
+			Set *string `android:"path"`
 		}
 	}
 
diff --git a/cc/cc.go b/cc/cc.go
index 456b736..d17369c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2223,6 +2223,22 @@
 	variantNdkLibs := []string{}
 	variantLateNdkLibs := []string{}
 	if ctx.Os() == android.Android {
+		rewriteHeaderLibs := func(list []string) (newHeaderLibs []string) {
+			newHeaderLibs = []string{}
+			for _, entry := range list {
+				// Replace device_kernel_headers with generated_kernel_headers
+				// for inline kernel building
+				if entry == "device_kernel_headers" || entry == "qti_kernel_headers" {
+					newHeaderLibs = append(newHeaderLibs, "generated_kernel_headers")
+					continue
+				}
+				newHeaderLibs = append(newHeaderLibs, entry)
+			}
+			return newHeaderLibs
+		}
+
+		deps.HeaderLibs = rewriteHeaderLibs(deps.HeaderLibs)
+
 		deps.SharedLibs, variantNdkLibs = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.SharedLibs)
 		deps.LateSharedLibs, variantLateNdkLibs = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.LateSharedLibs)
 		deps.ReexportSharedLibHeaders, _ = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.ReexportSharedLibHeaders)
diff --git a/cc/compiler.go b/cc/compiler.go
index eb5458f..36e5094 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -333,6 +333,16 @@
 	tc := ctx.toolchain()
 	modulePath := android.PathForModuleSrc(ctx).String()
 
+	additionalIncludeDirs := ctx.DeviceConfig().TargetSpecificHeaderPath()
+	if len(additionalIncludeDirs) > 0 {
+		// devices can have multiple paths in TARGET_SPECIFIC_HEADER_PATH
+		// add -I in front of all of them
+		if (strings.Contains(additionalIncludeDirs, " ")) {
+			additionalIncludeDirs = strings.ReplaceAll(additionalIncludeDirs, " ", " -I")
+		}
+		flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-I" + additionalIncludeDirs)
+	}
+
 	compiler.srcsBeforeGen = android.PathsForModuleSrcExcludes(ctx, compiler.Properties.Srcs, compiler.Properties.Exclude_srcs)
 	compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...)
 
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index db69ce7..626f990 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -58,6 +58,8 @@
 	"android.hardware.power-V1-ndk_platform",
 	"android.hardware.power-V2-ndk",
 	"android.hardware.power-V2-ndk_platform",
+	"android.hardware.power-V3-ndk",
+	"android.hardware.power-V3-ndk_platform",
 	"android.hardware.power-ndk_platform",
 	"android.hardware.power.stats-V1-ndk",
 	"android.hardware.power.stats-V1-ndk_platform",
diff --git a/cc/library.go b/cc/library.go
index f9bef6c..c689389 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -199,6 +199,9 @@
 	// using -isystem for this module and any module that links against this module.
 	Export_system_include_dirs []string `android:"arch_variant,variant_prepend"`
 
+	// list of plain cc flags to be used for any module that links against this module.
+	Export_cflags []string  `android:"arch_variant"`
+
 	Target struct {
 		Vendor, Product struct {
 			// list of exported include directories, like
@@ -519,6 +522,10 @@
 	f.systemDirs = append(f.systemDirs, android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)...)
 }
 
+func (f *flagExporter) exportExtraFlags(ctx ModuleContext) {
+	f.flags = append(f.flags, f.Properties.Export_cflags...)
+}
+
 // exportIncludesAsSystem registers the include directories and system include directories to be
 // exported transitively both as system include directories to modules depending on this module.
 func (f *flagExporter) exportIncludesAsSystem(ctx ModuleContext) {
@@ -1729,6 +1736,7 @@
 
 	// Export include paths and flags to be propagated up the tree.
 	library.exportIncludes(ctx)
+	library.exportExtraFlags(ctx)
 	library.reexportDirs(deps.ReexportedDirs...)
 	library.reexportSystemDirs(deps.ReexportedSystemDirs...)
 	library.reexportFlags(deps.ReexportedFlags...)
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 1cf64de..c5ec9f7 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -29,6 +29,7 @@
 
 	"google.golang.org/protobuf/proto"
 
+	"android/soong/cmd/extract_apks/bundle_proto"
 	android_bundle_proto "android/soong/cmd/extract_apks/bundle_proto"
 	"android/soong/third_party/zip"
 )
@@ -131,21 +132,21 @@
 	*android_bundle_proto.ApkDescription
 }
 
-func (m apkDescriptionMatcher) matches(config TargetConfig) bool {
-	return m.ApkDescription == nil || (apkTargetingMatcher{m.Targeting}).matches(config)
+func (m apkDescriptionMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
+	return m.ApkDescription == nil || (apkTargetingMatcher{m.Targeting}).matches(config, allAbisMustMatch)
 }
 
 type apkTargetingMatcher struct {
 	*android_bundle_proto.ApkTargeting
 }
 
-func (m apkTargetingMatcher) matches(config TargetConfig) bool {
+func (m apkTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
 	return m.ApkTargeting == nil ||
 		(abiTargetingMatcher{m.AbiTargeting}.matches(config) &&
 			languageTargetingMatcher{m.LanguageTargeting}.matches(config) &&
 			screenDensityTargetingMatcher{m.ScreenDensityTargeting}.matches(config) &&
 			sdkVersionTargetingMatcher{m.SdkVersionTargeting}.matches(config) &&
-			multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config))
+			multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config, allAbisMustMatch))
 }
 
 type languageTargetingMatcher struct {
@@ -197,38 +198,97 @@
 	*android_bundle_proto.MultiAbiTargeting
 }
 
-func (t multiAbiTargetingMatcher) matches(config TargetConfig) bool {
+type multiAbiValue []*bundle_proto.Abi
+
+func (m multiAbiValue) compare(other multiAbiValue) int {
+	min := func(a, b int) int {
+		if a < b {
+			return a
+		}
+		return b
+	}
+
+	sortAbis := func(abiSlice multiAbiValue) func(i, j int) bool {
+		return func(i, j int) bool {
+			// sort priorities greatest to least
+			return multiAbiPriorities[abiSlice[i].Alias] > multiAbiPriorities[abiSlice[j].Alias]
+		}
+	}
+
+	sortedM := append(multiAbiValue{}, m...)
+	sort.Slice(sortedM, sortAbis(sortedM))
+	sortedOther := append(multiAbiValue{}, other...)
+	sort.Slice(sortedOther, sortAbis(sortedOther))
+
+	for i := 0; i < min(len(sortedM), len(sortedOther)); i++ {
+		if multiAbiPriorities[sortedM[i].Alias] > multiAbiPriorities[sortedOther[i].Alias] {
+			return 1
+		}
+		if multiAbiPriorities[sortedM[i].Alias] < multiAbiPriorities[sortedOther[i].Alias] {
+			return -1
+		}
+	}
+
+	return len(sortedM) - len(sortedOther)
+}
+
+// this logic should match the logic in bundletool at
+// https://github.com/google/bundletool/blob/ae0fc0162fd80d92ef8f4ef4527c066f0106942f/src/main/java/com/android/tools/build/bundletool/device/MultiAbiMatcher.java#L43
+// (note link is the commit at time of writing; but logic should always match the latest)
+func (t multiAbiTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
 	if t.MultiAbiTargeting == nil {
 		return true
 	}
 	if _, ok := config.abis[android_bundle_proto.Abi_UNSPECIFIED_CPU_ARCHITECTURE]; ok {
 		return true
 	}
-	// Find the one with the highest priority.
-	highestPriority := 0
-	for _, v := range t.GetValue() {
-		for _, a := range v.GetAbi() {
-			if _, ok := config.abis[a.Alias]; ok {
-				if highestPriority < multiAbiPriorities[a.Alias] {
-					highestPriority = multiAbiPriorities[a.Alias]
-				}
+
+	multiAbiIsValid := func(m multiAbiValue) bool {
+		numValid := 0
+		for _, abi := range m {
+			if _, ok := config.abis[abi.Alias]; ok {
+				numValid += 1
 			}
 		}
+		if numValid == 0 {
+			return false
+		} else if numValid > 0 && !allAbisMustMatch {
+			return true
+		} else {
+			return numValid == len(m)
+		}
 	}
-	if highestPriority == 0 {
+
+	// ensure that the current value is valid for our config
+	valueSetContainsViableAbi := false
+	multiAbiSet := t.GetValue()
+	for _, multiAbi := range multiAbiSet {
+		if multiAbiIsValid(multiAbi.GetAbi()) {
+			valueSetContainsViableAbi = true
+			break
+		}
+	}
+
+	if !valueSetContainsViableAbi {
 		return false
 	}
+
 	// See if there are any matching alternatives with a higher priority.
-	for _, v := range t.GetAlternatives() {
-		for _, a := range v.GetAbi() {
-			if _, ok := config.abis[a.Alias]; ok {
-				if highestPriority < multiAbiPriorities[a.Alias] {
-					// There's a better one. Skip this one.
-					return false
-				}
+	for _, altMultiAbi := range t.GetAlternatives() {
+		if !multiAbiIsValid(altMultiAbi.GetAbi()) {
+			continue
+		}
+
+		for _, multiAbi := range multiAbiSet {
+			valueAbis := multiAbiValue(multiAbi.GetAbi())
+			altAbis := multiAbiValue(altMultiAbi.GetAbi())
+			if valueAbis.compare(altAbis) < 0 {
+				// An alternative has a higher priority, don't use this one
+				return false
 			}
 		}
 	}
+
 	return true
 }
 
@@ -304,13 +364,13 @@
 	*android_bundle_proto.VariantTargeting
 }
 
-func (m variantTargetingMatcher) matches(config TargetConfig) bool {
+func (m variantTargetingMatcher) matches(config TargetConfig, allAbisMustMatch bool) bool {
 	if m.VariantTargeting == nil {
 		return true
 	}
 	return sdkVersionTargetingMatcher{m.SdkVersionTargeting}.matches(config) &&
 		abiTargetingMatcher{m.AbiTargeting}.matches(config) &&
-		multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config) &&
+		multiAbiTargetingMatcher{m.MultiAbiTargeting}.matches(config, allAbisMustMatch) &&
 		screenDensityTargetingMatcher{m.ScreenDensityTargeting}.matches(config) &&
 		textureCompressionFormatTargetingMatcher{m.TextureCompressionFormatTargeting}.matches(config)
 }
@@ -322,30 +382,42 @@
 
 // Return all entries matching target configuration
 func selectApks(toc Toc, targetConfig TargetConfig) SelectionResult {
-	var result SelectionResult
-	for _, variant := range (*toc).GetVariant() {
-		if !(variantTargetingMatcher{variant.GetTargeting()}.matches(targetConfig)) {
-			continue
-		}
-		for _, as := range variant.GetApkSet() {
-			if !(moduleMetadataMatcher{as.ModuleMetadata}.matches(targetConfig)) {
+	checkMatching := func(allAbisMustMatch bool) SelectionResult {
+		var result SelectionResult
+		for _, variant := range (*toc).GetVariant() {
+			if !(variantTargetingMatcher{variant.GetTargeting()}.matches(targetConfig, allAbisMustMatch)) {
 				continue
 			}
-			for _, apkdesc := range as.GetApkDescription() {
-				if (apkDescriptionMatcher{apkdesc}).matches(targetConfig) {
-					result.entries = append(result.entries, apkdesc.GetPath())
-					// TODO(asmundak): As it turns out, moduleName which we get from
-					// the ModuleMetadata matches the module names of the generated
-					// entry paths just by coincidence, only for the split APKs. We
-					// need to discuss this with bundletool folks.
-					result.moduleName = as.GetModuleMetadata().GetName()
+			for _, as := range variant.GetApkSet() {
+				if !(moduleMetadataMatcher{as.ModuleMetadata}.matches(targetConfig)) {
+					continue
+				}
+				for _, apkdesc := range as.GetApkDescription() {
+					if (apkDescriptionMatcher{apkdesc}).matches(targetConfig, allAbisMustMatch) {
+						result.entries = append(result.entries, apkdesc.GetPath())
+						// TODO(asmundak): As it turns out, moduleName which we get from
+						// the ModuleMetadata matches the module names of the generated
+						// entry paths just by coincidence, only for the split APKs. We
+						// need to discuss this with bundletool folks.
+						result.moduleName = as.GetModuleMetadata().GetName()
+					}
+				}
+				// we allow only a single module, so bail out here if we found one
+				if result.moduleName != "" {
+					return result
 				}
 			}
-			// we allow only a single module, so bail out here if we found one
-			if result.moduleName != "" {
-				return result
-			}
 		}
+		return result
+	}
+	result := checkMatching(true)
+	if result.moduleName == "" {
+		// if there are no matches where all of the ABIs are available in the
+		// TargetConfig, then search again with a looser requirement of at
+		// least one matching ABI
+		// NOTE(b/260130686): this logic diverges from the logic in bundletool
+		// https://github.com/google/bundletool/blob/ae0fc0162fd80d92ef8f4ef4527c066f0106942f/src/main/java/com/android/tools/build/bundletool/device/MultiAbiMatcher.java#L43
+		result = checkMatching(false)
 	}
 	return result
 }
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index f5e4046..9f52877 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -420,6 +420,374 @@
 	}
 }
 
+func TestSelectApks_ApexSet_Variants(t *testing.T) {
+	testCases := []testDesc{
+		{
+			protoText: `
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: X86}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: X86}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-armeabi_v7a.apex"
+		}
+	}
+	variant_number: 0
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: X86}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: X86}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-arm64_v8a.apex"
+		}
+	}
+	variant_number: 1
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: X86}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: X86}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-armeabi_v7a.arm64_v8a.apex"
+		}
+	}
+	variant_number: 2
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {abi {alias: X86}}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {abi {alias: X86}}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+				}
+			}
+			path: "standalones/standalone-x86.apex"
+		}
+	}
+	variant_number: 3
+}
+variant {
+	targeting {
+		sdk_version_targeting {value {min {value: 29}}}
+		multi_abi_targeting {
+			value {
+				abi {alias: X86}
+				abi {alias: X86_64}
+			}
+			alternatives {abi {alias: ARMEABI_V7A}}
+			alternatives {
+				abi {alias: ARMEABI_V7A}
+				abi {alias: ARM64_V8A}
+			}
+			alternatives {abi {alias: ARM64_V8A}}
+			alternatives {abi {alias: X86}}
+		}
+	}
+	apk_set {
+		module_metadata {
+			name: "base"
+			delivery_type: INSTALL_TIME
+		}
+		apk_description {
+			targeting {
+				multi_abi_targeting {
+					value {
+						abi {alias: X86}
+						abi {alias: X86_64}
+					}
+					alternatives {abi {alias: ARMEABI_V7A}}
+					alternatives {
+						abi {alias: ARMEABI_V7A}
+						abi {alias: ARM64_V8A}
+					}
+					alternatives {abi {alias: ARM64_V8A}}
+					alternatives {abi {alias: X86}}
+				}
+			}
+			path: "standalones/standalone-x86.x86_64.apex"
+		}
+  }
+  variant_number: 4
+}
+`,
+			configs: []testConfigDesc{
+				{
+					name: "multi-variant multi-target ARM",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARM64_V8A:   0,
+							bp.Abi_ARMEABI_V7A: 1,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-armeabi_v7a.arm64_v8a.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target arm",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARMEABI_V7A: 0,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-armeabi_v7a.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target arm64",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARM64_V8A: 0,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-arm64_v8a.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant multi-target x86",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_X86:    0,
+							bp.Abi_X86_64: 1,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-x86.x86_64.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target x86",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_X86: 0,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-x86.apex",
+						},
+					},
+				},
+				{
+					name: "multi-variant single-target x86_64",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_X86_64: 0,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-x86.x86_64.apex",
+						}},
+				},
+				{
+					name: "multi-variant multi-target cross-target",
+					targetConfig: TargetConfig{
+						sdkVersion: 33,
+						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+						},
+						abis: map[bp.Abi_AbiAlias]int{
+							bp.Abi_ARM64_V8A: 0,
+							bp.Abi_X86_64:    1,
+						},
+					},
+					expected: SelectionResult{
+						"base",
+						[]string{
+							"standalones/standalone-arm64_v8a.apex",
+						},
+					},
+				},
+			},
+		},
+	}
+	for _, testCase := range testCases {
+		var toc bp.BuildApksResult
+		if err := prototext.Unmarshal([]byte(testCase.protoText), &toc); err != nil {
+			t.Fatal(err)
+		}
+		for _, config := range testCase.configs {
+			t.Run(config.name, func(t *testing.T) {
+				actual := selectApks(&toc, config.targetConfig)
+				if !reflect.DeepEqual(config.expected, actual) {
+					t.Errorf("expected %v, got %v", config.expected, actual)
+				}
+			})
+		}
+	}
+}
+
 type testZip2ZipWriter struct {
 	entries map[string]string
 }
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index f8844fc..ba0648d 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -150,6 +150,7 @@
 var defaultMinSdkVersion string
 var useVersion string
 var staticDeps bool
+var writeCmd bool
 var jetifier bool
 
 func InList(s string, list []string) bool {
@@ -206,6 +207,10 @@
 	return p.Packaging == "jar"
 }
 
+func (p Pom) IsApk() bool {
+	return p.Packaging == "apk"
+}
+
 func (p Pom) IsHostModule() bool {
 	return hostModuleNames.IsHostModule(p.GroupId, p.ArtifactId)
 }
@@ -243,6 +248,8 @@
 func (p Pom) ImportModuleType() string {
 	if p.IsAar() {
 		return "android_library_import"
+	} else if p.IsApk() {
+		return "android_app_import"
 	} else if p.IsHostOnly() {
 		return "java_import_host"
 	} else {
@@ -253,6 +260,8 @@
 func (p Pom) BazelImportTargetType() string {
 	if p.IsAar() {
 		return "aar_import"
+	} else if p.IsApk() {
+		return "apk_import"
 	} else {
 		return "java_import"
 	}
@@ -261,6 +270,8 @@
 func (p Pom) ImportProperty() string {
 	if p.IsAar() {
 		return "aars"
+	} else if p.IsApk() {
+		return "apk"
 	} else {
 		return "jars"
 	}
@@ -269,6 +280,8 @@
 func (p Pom) BazelImportProperty() string {
 	if p.IsAar() {
 		return "aar"
+	} else if p.IsApk() {
+		return "apk"
 	} else {
 		return "jars"
 	}
@@ -492,8 +505,12 @@
 var bpTemplate = template.Must(template.New("bp").Parse(`
 {{.ImportModuleType}} {
     name: "{{.BpName}}",
+    {{- if .IsApk}}
+    {{.ImportProperty}}: "{{.ArtifactFile}}",
+    {{- else}}
     {{.ImportProperty}}: ["{{.ArtifactFile}}"],
     sdk_version: "{{.SdkVersion}}",
+    {{- end}}
     {{- if .Jetifier}}
     jetifier: true,
     {{- end}}
@@ -534,8 +551,14 @@
     ],
     {{- end}}
     {{- else if not .IsHostOnly}}
+    {{- if not .IsApk}}
     min_sdk_version: "{{.DefaultMinSdkVersion}}",
     {{- end}}
+    {{- end}}
+    {{- if .IsApk}}
+    presigned: true
+    {{- end}}
+
 }
 `))
 
@@ -810,6 +833,9 @@
   -use-version <version>
      If the maven directory contains multiple versions of artifacts and their pom files,
      -use-version can be used to only write Android.bp files for a specific version of those artifacts.
+  -write-cmd
+     Whether to write the command line arguments used to generate the build file as a comment at
+     the top of the build file itself.
   -jetifier
      Sets jetifier: true for all modules.
   <dir>
@@ -824,6 +850,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")
@@ -836,9 +863,11 @@
 	flag.StringVar(&defaultMinSdkVersion, "default-min-sdk-version", "24", "Default min_sdk_version to use, if one is not available from AndroidManifest.xml. Default: 24")
 	flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
 	flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
+	flag.BoolVar(&writeCmd, "write-cmd", true, "Write command line arguments as a comment")
 	flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
 	flag.StringVar(&regen, "regen", "", "Rewrite specified file")
 	flag.BoolVar(&pom2build, "pom2build", false, "If true, will generate a Bazel BUILD file *instead* of a .bp file")
+	flag.StringVar(&prepend, "prepend", "", "Path to a file containing text to insert at the beginning of the generated build file")
 	flag.Parse()
 
 	if regen != "" {
@@ -962,8 +991,22 @@
 	if pom2build {
 		commentString = "#"
 	}
-	fmt.Fprintln(buf, commentString, "Automatically generated with:")
-	fmt.Fprintln(buf, commentString, "pom2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
+
+	fmt.Fprintln(buf, commentString, "This is a generated file. Do not modify directly.")
+
+	if writeCmd {
+		fmt.Fprintln(buf, commentString, "Automatically generated with:")
+		fmt.Fprintln(buf, commentString, "pom2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
+	}
+
+	if prepend != "" {
+		contents, err := ioutil.ReadFile(prepend)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, "Error reading", prepend, err)
+			os.Exit(1)
+		}
+		fmt.Fprintln(buf, string(contents))
+	}
 
 	depsTemplate := bpDepsTemplate
 	template := bpTemplate
@@ -974,7 +1017,7 @@
 
 	for _, pom := range poms {
 		var err error
-		if staticDeps {
+		if staticDeps && !pom.IsApk() {
 			err = depsTemplate.Execute(buf, pom)
 		} else {
 			err = template.Execute(buf, pom)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 4b3161b..f1884a7 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -117,6 +117,7 @@
 	ctx.Register()
 	ctx.SetNameInterface(newNameResolver(configuration))
 	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
+	ctx.AddIncludeTags(configuration.IncludeTags()...)
 	return ctx
 }
 
diff --git a/java/aar.go b/java/aar.go
index 00ff7e7..4e31e68 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -233,7 +233,7 @@
 
 	if !hasVersionName {
 		var versionName string
-		if ctx.ModuleName() == "framework-res" {
+		if ctx.ModuleName() == "framework-res" || ctx.ModuleName() == "org.lineageos.platform-res" {
 			// Some builds set AppsDefaultVersionName() to include the build number ("O-123456").  aapt2 copies the
 			// version name of framework-res into app manifests as compileSdkVersionCodename, which confuses things
 			// if it contains the build number.  Use the PlatformVersionName instead.
@@ -258,6 +258,9 @@
 	if sdkDep.frameworkResModule != "" {
 		ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule)
 	}
+	if sdkDep.lineageResModule != "" {
+		ctx.AddVariationDependencies(nil, lineageResTag, sdkDep.lineageResModule)
+	}
 }
 
 var extractAssetsRule = pctx.AndroidStaticRule("extractAssets",
@@ -440,7 +443,7 @@
 			if exportPackage != nil {
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
-		case frameworkResTag:
+		case frameworkResTag, lineageResTag:
 			if exportPackage != nil {
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
@@ -741,6 +744,9 @@
 		if sdkDep.useModule && sdkDep.frameworkResModule != "" {
 			ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule)
 		}
+		if sdkDep.useModule && sdkDep.lineageResModule != "" {
+			ctx.AddVariationDependencies(nil, lineageResTag, sdkDep.lineageResModule)
+		}
 	}
 
 	ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 7772b70..fb6e984 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -126,7 +126,7 @@
 		targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params.SdkContext)
 		args = append(args, "--targetSdkVersion ", targetSdkVersion)
 
-		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
+		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" && ctx.ModuleName() != "org.lineageos.platform-res" {
 			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
 			deps = append(deps, ApiFingerprintPath(ctx))
 		}
@@ -136,7 +136,7 @@
 			ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
 		}
 
-		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
+		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" && ctx.ModuleName() != "org.lineageos.platform-res" {
 			minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
 			deps = append(deps, ApiFingerprintPath(ctx))
 		}
diff --git a/java/androidmk.go b/java/androidmk.go
index 7322637..49ca176 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -347,7 +347,7 @@
 				entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary)
 				entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip)
 
-				if app.Name() == "framework-res" {
+				if app.Name() == "framework-res" || app.Name() == "org.lineageos.platform-res" {
 					entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)")
 					// Make base_rules.mk not put framework-res in a subdirectory called
 					// framework_res.
@@ -475,7 +475,7 @@
 			entries.SetPath("LOCAL_SOONG_AAR", a.aarFile)
 		}
 
-		if a.Name() == "framework-res" {
+		if a.Name() == "framework-res" || a.Name() == "org.lineageos.platform-res" {
 			entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)")
 			// Make base_rules.mk not put framework-res in a subdirectory called
 			// framework_res.
diff --git a/java/app.go b/java/app.go
index 41419ba..b46f2b1 100755
--- a/java/app.go
+++ b/java/app.go
@@ -449,6 +449,9 @@
 	if ctx.ModuleName() == "framework-res" {
 		// framework-res.apk is installed as system/framework/framework-res.apk
 		installDir = "framework"
+	} else if ctx.ModuleName() == "org.lineageos.platform-res" {
+		// org.lineageos.platform-res.apk is installed as system/framework/org.lineageos.platform-res.apk
+		installDir = "framework"
 	} else if a.Privileged() {
 		installDir = filepath.Join("priv-app", a.installApkName)
 	} else {
@@ -471,7 +474,7 @@
 	a.dexpreopter.manifestFile = a.mergedManifestFile
 	a.dexpreopter.preventInstall = a.appProperties.PreventInstall
 
-	if ctx.ModuleName() != "framework-res" {
+	if ctx.ModuleName() != "framework-res" && ctx.ModuleName() != "org.lineageos.platform-res" {
 		a.Module.compile(ctx, a.aaptSrcJar)
 	}
 
@@ -578,6 +581,9 @@
 	if ctx.ModuleName() == "framework-res" {
 		// framework-res.apk is installed as system/framework/framework-res.apk
 		a.installDir = android.PathForModuleInstall(ctx, "framework")
+	} else if ctx.ModuleName() == "org.lineageos.platform-res" {
+		// org.lineageos.platform-res.apk is installed as system/framework/org.lineageos.platform-res.apk
+		a.installDir = android.PathForModuleInstall(ctx, "framework")
 	} else if a.Privileged() {
 		a.installDir = android.PathForModuleInstall(ctx, "priv-app", a.installApkName)
 	} else if ctx.InstallInTestcases() {
diff --git a/java/app_set.go b/java/app_set.go
index 694b167..defb4cb 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -96,7 +96,7 @@
 	"x86_64": "X86_64",
 }
 
-func SupportedAbis(ctx android.ModuleContext) []string {
+func SupportedAbis(ctx android.ModuleContext, excludeNativeBridgeAbis bool) []string {
 	abiName := func(targetIdx int, deviceArch string) string {
 		if abi, found := TargetCpuAbi[deviceArch]; found {
 			return abi
@@ -107,6 +107,9 @@
 
 	var result []string
 	for i, target := range ctx.Config().Targets[android.Android] {
+		if target.NativeBridge == android.NativeBridgeEnabled && excludeNativeBridgeAbis {
+			continue
+		}
 		result = append(result, abiName(i, target.Arch.ArchType.String()))
 	}
 	return result
@@ -133,7 +136,7 @@
 			ImplicitOutputs: android.WritablePaths{as.packedOutput, as.apkcertsFile},
 			Inputs:          android.Paths{as.prebuilt.SingleSourcePath(ctx)},
 			Args: map[string]string{
-				"abis":              strings.Join(SupportedAbis(ctx), ","),
+				"abis":              strings.Join(SupportedAbis(ctx, false), ","),
 				"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
 				"screen-densities":  screenDensities,
 				"sdk-version":       ctx.Config().PlatformSdkVersion().String(),
diff --git a/java/app_test.go b/java/app_test.go
index 8e331d4..239bd52 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -77,8 +77,11 @@
 			expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String())
 
 			frameworkRes := result.ModuleForTests("framework-res", "android_common")
+			lineageRes := result.ModuleForTests("org.lineageos.platform-res", "android_common")
 			expectedLinkImplicits = append(expectedLinkImplicits,
 				frameworkRes.Output("package-res.apk").Output.String())
+			expectedLinkImplicits = append(expectedLinkImplicits,
+				lineageRes.Output("package-res.apk").Output.String())
 
 			// Test the mapping from input files to compiled output file names
 			compile := foo.Output(compiledResourceFiles[0])
diff --git a/java/base.go b/java/base.go
index 7aa2814..f4a91f5 100644
--- a/java/base.go
+++ b/java/base.go
@@ -749,9 +749,7 @@
 		// Kotlin files
 		ctx.AddVariationDependencies(nil, kotlinStdlibTag,
 			"kotlin-stdlib", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8")
-		if len(j.properties.Plugins) > 0 {
-			ctx.AddVariationDependencies(nil, kotlinAnnotationsTag, "kotlin-annotations")
-		}
+		ctx.AddVariationDependencies(nil, kotlinAnnotationsTag, "kotlin-annotations")
 	}
 
 	// Framework libraries need special handling in static coverage builds: they should not have
@@ -1107,8 +1105,6 @@
 		flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
 		flags.classpath = append(flags.classpath, deps.kotlinAnnotations...)
 
-		flags.dexClasspath = append(flags.dexClasspath, deps.kotlinAnnotations...)
-
 		flags.kotlincClasspath = append(flags.kotlincClasspath, flags.bootClasspath...)
 		flags.kotlincClasspath = append(flags.kotlincClasspath, flags.classpath...)
 
@@ -1140,9 +1136,12 @@
 		// Jar kotlin classes into the final jar after javac
 		if BoolDefault(j.properties.Static_kotlin_stdlib, true) {
 			kotlinJars = append(kotlinJars, deps.kotlinStdlib...)
+			kotlinJars = append(kotlinJars, deps.kotlinAnnotations...)
 			kotlinHeaderJars = append(kotlinHeaderJars, deps.kotlinStdlib...)
+			kotlinHeaderJars = append(kotlinHeaderJars, deps.kotlinAnnotations...)
 		} else {
 			flags.dexClasspath = append(flags.dexClasspath, deps.kotlinStdlib...)
+			flags.dexClasspath = append(flags.dexClasspath, deps.kotlinAnnotations...)
 		}
 	}
 
diff --git a/java/java.go b/java/java.go
index c8fb93c..876979c 100644
--- a/java/java.go
+++ b/java/java.go
@@ -118,6 +118,16 @@
 		copyEverythingToSnapshot,
 	}
 
+	snapshotRequiresImplementationJar = func(ctx android.SdkMemberContext) bool {
+		// In the S build the build will break if updatable-media does not provide a full implementation
+		// jar. That issue was fixed in Tiramisu by b/229932396.
+		if ctx.IsTargetBuildBeforeTiramisu() && ctx.Name() == "updatable-media" {
+			return true
+		}
+
+		return false
+	}
+
 	// Supports adding java boot libraries to module_exports and sdk.
 	//
 	// The build has some implicit dependencies (via the boot jars configuration) on a number of
@@ -135,13 +145,21 @@
 			SupportsSdk:  true,
 		},
 		func(ctx android.SdkMemberContext, j *Library) android.Path {
+			if snapshotRequiresImplementationJar(ctx) {
+				return exportImplementationClassesJar(ctx, j)
+			}
+
 			// Java boot libs are only provided in the SDK to provide access to their dex implementation
 			// jar for use by dexpreopting and boot jars package check. They do not need to provide an
 			// actual implementation jar but the java_import will need a file that exists so just copy an
 			// empty file. Any attempt to use that file as a jar will cause a build error.
 			return ctx.SnapshotBuilder().EmptyFile()
 		},
-		func(osPrefix, name string) string {
+		func(ctx android.SdkMemberContext, osPrefix, name string) string {
+			if snapshotRequiresImplementationJar(ctx) {
+				return sdkSnapshotFilePathForJar(ctx, osPrefix, name)
+			}
+
 			// Create a special name for the implementation jar to try and provide some useful information
 			// to a developer that attempts to compile against this.
 			// TODO(b/175714559): Provide a proper error message in Soong not ninja.
@@ -164,6 +182,9 @@
 		android.SdkMemberTypeBase{
 			PropertyName: "java_systemserver_libs",
 			SupportsSdk:  true,
+
+			// This was only added in Tiramisu.
+			SupportedBuildReleaseSpecification: "Tiramisu+",
 		},
 		func(ctx android.SdkMemberContext, j *Library) android.Path {
 			// Java systemserver libs are only provided in the SDK to provide access to their dex
@@ -172,7 +193,7 @@
 			// file. Any attempt to use that file as a jar will cause a build error.
 			return ctx.SnapshotBuilder().EmptyFile()
 		},
-		func(osPrefix, name string) string {
+		func(_ android.SdkMemberContext, osPrefix, name string) string {
 			// Create a special name for the implementation jar to try and provide some useful information
 			// to a developer that attempts to compile against this.
 			// TODO(b/175714559): Provide a proper error message in Soong not ninja.
@@ -340,6 +361,7 @@
 	bootClasspathTag        = dependencyTag{name: "bootclasspath", runtimeLinked: true}
 	systemModulesTag        = dependencyTag{name: "system modules", runtimeLinked: true}
 	frameworkResTag         = dependencyTag{name: "framework-res"}
+	lineageResTag           = dependencyTag{name: "org.lineageos.platform-res"}
 	kotlinStdlibTag         = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true}
 	kotlinAnnotationsTag    = dependencyTag{name: "kotlin-annotations", runtimeLinked: true}
 	kotlinPluginTag         = dependencyTag{name: "kotlin-plugin", toolchain: true}
@@ -379,6 +401,7 @@
 	java9Classpath []string
 
 	frameworkResModule string
+	lineageResModule   string
 
 	jars android.Paths
 	aidl android.OptionalPath
@@ -418,6 +441,10 @@
 	if sdkDep.systemModules != "" {
 		ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
 	}
+
+	if ctx.ModuleName() == "org.lineageos.platform-res" {
+		ctx.AddVariationDependencies(nil, frameworkResTag, "framework-res")
+	}
 }
 
 type deps struct {
@@ -505,6 +532,20 @@
 	}
 }
 
+func (v javaVersion) StringForKotlinc() string {
+	// $ ./external/kotlinc/bin/kotlinc -jvm-target foo
+	// error: unknown JVM target version: foo
+	// Supported versions: 1.6, 1.8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+	switch v {
+	case JAVA_VERSION_7:
+		return "1.6"
+	case JAVA_VERSION_9:
+		return "9"
+	default:
+		return v.String()
+	}
+}
+
 // Returns true if javac targeting this version uses system modules instead of a bootclasspath.
 func (v javaVersion) usesJavaModules() bool {
 	return v >= 9
@@ -646,7 +687,7 @@
 )
 
 // path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
-func sdkSnapshotFilePathForJar(osPrefix, name string) string {
+func sdkSnapshotFilePathForJar(_ android.SdkMemberContext, osPrefix, name string) string {
 	return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
 }
 
@@ -663,7 +704,7 @@
 
 	// Function to compute the snapshot relative path to which the named library's
 	// jar should be copied.
-	snapshotPathGetter func(osPrefix, name string) string
+	snapshotPathGetter func(ctx android.SdkMemberContext, osPrefix, name string) string
 
 	// True if only the jar should be copied to the snapshot, false if the jar plus any additional
 	// files like aidl files should also be copied.
@@ -721,7 +762,7 @@
 	exportedJar := p.JarToExport
 	if exportedJar != nil {
 		// Delegate the creation of the snapshot relative path to the member type.
-		snapshotRelativeJavaLibPath := memberType.snapshotPathGetter(p.OsPrefix(), ctx.Name())
+		snapshotRelativeJavaLibPath := memberType.snapshotPathGetter(ctx, p.OsPrefix(), ctx.Name())
 
 		// Copy the exported jar to the snapshot.
 		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
@@ -1187,7 +1228,7 @@
 
 	exportedJar := p.JarToExport
 	if exportedJar != nil {
-		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(ctx, p.OsPrefix(), ctx.Name())
 		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
 
 		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
diff --git a/java/kotlin.go b/java/kotlin.go
index 903c624..9bff5ea 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -119,9 +119,8 @@
 			"srcJarDir":         android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(),
 			"kotlinBuildFile":   android.PathForModuleOut(ctx, "kotlinc-build.xml").String(),
 			"emptyDir":          android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
-			// http://b/69160377 kotlinc only supports -jvm-target 1.6 and 1.8
-			"kotlinJvmTarget": "1.8",
-			"name":            kotlinName,
+			"kotlinJvmTarget":   flags.javaVersion.StringForKotlinc(),
+			"name":              kotlinName,
 		},
 	})
 }
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 435d782..491ce29 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -42,6 +42,11 @@
 		}
 		`)
 
+	kotlinStdlib := ctx.ModuleForTests("kotlin-stdlib", "android_common").
+		Output("turbine-combined/kotlin-stdlib.jar").Output
+	kotlinAnnotations := ctx.ModuleForTests("kotlin-annotations", "android_common").
+		Output("turbine-combined/kotlin-annotations.jar").Output
+
 	fooKotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
 	fooJavac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
 	fooJar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
@@ -69,6 +74,16 @@
 			fooJar.Inputs.Strings(), fooKotlincClasses.String())
 	}
 
+	if !inList(kotlinStdlib.String(), fooJar.Inputs.Strings()) {
+		t.Errorf("foo jar inputs %v does not contain %v",
+			fooJar.Inputs.Strings(), kotlinStdlib.String())
+	}
+
+	if !inList(kotlinAnnotations.String(), fooJar.Inputs.Strings()) {
+		t.Errorf("foo jar inputs %v does not contain %v",
+			fooJar.Inputs.Strings(), kotlinAnnotations.String())
+	}
+
 	if !inList(fooKotlincHeaderClasses.String(), fooHeaderJar.Inputs.Strings()) {
 		t.Errorf("foo header jar inputs %v does not contain %q",
 			fooHeaderJar.Inputs.Strings(), fooKotlincHeaderClasses.String())
diff --git a/java/robolectric.go b/java/robolectric.go
index f719521..80be046 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -23,6 +23,8 @@
 	"android/soong/android"
 	"android/soong/java/config"
 	"android/soong/tradefed"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -63,6 +65,10 @@
 	// The version number of a robolectric prebuilt to use from prebuilts/misc/common/robolectric
 	// instead of the one built from source in external/robolectric-shadows.
 	Robolectric_prebuilt_version *string
+
+	// Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectri
+	// to use.  /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows
+	Upstream *bool
 }
 
 type robolectricTest struct {
@@ -106,7 +112,11 @@
 	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
 		ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
 	} else {
-		ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
+		if proptools.Bool(r.robolectricProperties.Upstream) {
+			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream")
+		} else {
+			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib)
+		}
 	}
 
 	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
diff --git a/java/sdk.go b/java/sdk.go
index 0dddd40..d0664ec 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -152,6 +152,7 @@
 			systemModules:      fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind),
 			java9Classpath:     []string{module},
 			frameworkResModule: "framework-res",
+			lineageResModule:   "org.lineageos.platform-res",
 			aidl:               android.OptionalPathForPath(aidl),
 		}
 	}
@@ -164,6 +165,7 @@
 			bootclasspath:      corePlatformBootclasspathLibraries(ctx),
 			classpath:          config.FrameworkLibraries,
 			frameworkResModule: "framework-res",
+			lineageResModule:   "org.lineageos.platform-res",
 		}
 	case android.SdkNone:
 		systemModules := sdkContext.SystemModules()
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index fa61ea6..79d2ee9 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -28,6 +28,9 @@
 		SdkMemberTypeBase: android.SdkMemberTypeBase{
 			PropertyName: "systemserverclasspath_fragments",
 			SupportsSdk:  true,
+
+			// This was only added in Tiramisu.
+			SupportedBuildReleaseSpecification: "Tiramisu+",
 		},
 	})
 }
diff --git a/java/testing.go b/java/testing.go
index 511cc5d..cfe1455 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -370,6 +370,11 @@
 		android_app {
 			name: "framework-res",
 			sdk_version: "core_platform",
+		}
+
+		android_app {
+			name: "org.lineageos.platform-res",
+			sdk_version: "core_platform",
 		}`
 
 	systemModules := []string{
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 802e1da..7468579 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -8,6 +8,7 @@
 	RustAllowedPaths = []string{
 		"device/google/cuttlefish",
 		"external/adhd",
+		"external/boringssl",
 		"external/crosvm",
 		"external/libchromeos-rs",
 		"external/minijail",
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index a02c195..604cf9c 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -251,3 +251,24 @@
 # Packages used for Android in Chrome OS
 org\.chromium\.arc
 org\.chromium\.arc\..*
+
+# Lineage adds
+lineageos\.platform
+org\.lineageos\.platform\.internal
+
+# NV adds
+com\.nvidia
+com\.nvidia\..*
+
+# QC adds
+com.qualcomm.qti
+com.quicinc.tcmiface
+com.qualcomm.wfd
+com.qualcomm.wfd.service
+org.codeaurora.ims
+org.codeaurora.internal
+qcom.fmradio
+
+###################################################
+# IFAA Manager used for Alipay and/or WeChat payment
+org\.ifaa\.android\.manager.*
diff --git a/sdk/build_release.go b/sdk/build_release.go
index 4c2277e..0494a28 100644
--- a/sdk/build_release.go
+++ b/sdk/build_release.go
@@ -24,18 +24,22 @@
 
 // buildRelease represents the version of a build system used to create a specific release.
 //
-// The name of the release, is the same as the code for the dessert release, e.g. S, T, etc.
+// The name of the release, is the same as the code for the dessert release, e.g. S, Tiramisu, etc.
 type buildRelease struct {
-	// The name of the release, e.g. S, T, etc.
+	// The name of the release, e.g. S, Tiramisu, etc.
 	name string
 
 	// The index of this structure within the buildReleases list.
 	ordinal int
 }
 
+func (br *buildRelease) EarlierThan(other *buildRelease) bool {
+	return br.ordinal < other.ordinal
+}
+
 // String returns the name of the build release.
-func (s *buildRelease) String() string {
-	return s.name
+func (br *buildRelease) String() string {
+	return br.name
 }
 
 // buildReleaseSet represents a set of buildRelease objects.
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index a99fa1f..2cadd60 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -15,6 +15,7 @@
 package sdk
 
 import (
+	"fmt"
 	"testing"
 
 	"android/soong/android"
@@ -339,8 +340,8 @@
 		android.FixtureAddFile("aidl", nil),
 		android.FixtureAddFile("resource.txt", nil),
 	).RunTestWithBp(t, `
-		module_exports {
-			name: "myexports",
+		sdk {
+			name: "mysdk",
 			java_boot_libs: ["myjavalib"],
 		}
 
@@ -360,7 +361,7 @@
 		}
 	`)
 
-	CheckSnapshot(t, result, "myexports", "",
+	CheckSnapshot(t, result, "mysdk", "",
 		checkUnversionedAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
@@ -377,7 +378,7 @@
 // This is auto-generated. DO NOT EDIT.
 
 java_import {
-    name: "myexports_myjavalib@current",
+    name: "mysdk_myjavalib@current",
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
@@ -385,19 +386,73 @@
     permitted_packages: ["pkg.myjavalib"],
 }
 
-module_exports_snapshot {
-    name: "myexports@current",
+sdk_snapshot {
+    name: "mysdk@current",
     visibility: ["//visibility:public"],
-    java_boot_libs: ["myexports_myjavalib@current"],
+    java_boot_libs: ["mysdk_myjavalib@current"],
 }
 
 `),
 		checkAllCopyRules(`
-.intermediates/myexports/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
 `),
 	)
 }
 
+func TestSnapshotWithJavaBootLibrary_UpdatableMedia(t *testing.T) {
+	runTest := func(t *testing.T, targetBuildRelease, expectedJarPath, expectedCopyRule string) {
+		result := android.GroupFixturePreparers(
+			prepareForSdkTestWithJava,
+			android.FixtureMergeEnv(map[string]string{
+				"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
+			}),
+		).RunTestWithBp(t, `
+		sdk {
+			name: "mysdk",
+			java_boot_libs: ["updatable-media"],
+		}
+
+		java_library {
+			name: "updatable-media",
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+			compile_dex: true,
+			permitted_packages: ["pkg.media"],
+			apex_available: ["com.android.media"],
+		}
+	`)
+
+		CheckSnapshot(t, result, "mysdk", "",
+			checkUnversionedAndroidBpContents(fmt.Sprintf(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "updatable-media",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["com.android.media"],
+    jars: ["%s"],
+    permitted_packages: ["pkg.media"],
+}
+`, expectedJarPath)),
+			checkAllCopyRules(expectedCopyRule),
+		)
+	}
+
+	t.Run("updatable-media in S", func(t *testing.T) {
+		runTest(t, "S", "java/updatable-media.jar", `
+.intermediates/updatable-media/android_common/package-check/updatable-media.jar -> java/updatable-media.jar
+`)
+	})
+
+	t.Run("updatable-media in T", func(t *testing.T) {
+		runTest(t, "Tiramisu", "java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar", `
+.intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/updatable-media.jar
+`)
+	})
+}
+
 func TestSnapshotWithJavaSystemserverLibrary(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForSdkTestWithJava,
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 16e3e7f..819083d 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -22,13 +22,16 @@
 	"android/soong/java"
 )
 
-func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) {
+func testSnapshotWithSystemServerClasspathFragment(t *testing.T, targetBuildRelease string, expectedUnversionedSdkSnapshot string, expectedVersionedSdkSnapshot string) {
 	result := android.GroupFixturePreparers(
 		prepareForSdkTestWithJava,
 		java.PrepareForTestWithJavaDefaultModules,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("mysdklibrary"),
 		dexpreopt.FixtureSetApexSystemServerJars("myapex:mylib", "myapex:mysdklibrary"),
+		android.FixtureModifyEnv(func(env map[string]string) {
+			env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = targetBuildRelease
+		}),
 		prepareForSdkTestWithApex,
 
 		android.FixtureWithRootAndroidBp(`
@@ -83,7 +86,58 @@
 	).RunTest(t)
 
 	CheckSnapshot(t, result, "mysdk", "",
-		checkUnversionedAndroidBpContents(`
+		checkUnversionedAndroidBpContents(expectedUnversionedSdkSnapshot),
+		checkVersionedAndroidBpContents(expectedVersionedSdkSnapshot),
+	)
+}
+
+func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) {
+	t.Run("target-s", func(t *testing.T) {
+		testSnapshotWithSystemServerClasspathFragment(t, "S", `
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+`, `
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "mysdk_mysdklibrary@current",
+    sdk_member_name: "mysdklibrary",
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: false,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    visibility: ["//visibility:public"],
+    java_sdk_libs: ["mysdk_mysdklibrary@current"],
+}
+`)
+	})
+
+	t.Run("target-t", func(t *testing.T) {
+		testSnapshotWithSystemServerClasspathFragment(t, "Tiramisu", `
 // This is auto-generated. DO NOT EDIT.
 
 java_sdk_library_import {
@@ -120,8 +174,7 @@
         "mysdklibrary",
     ],
 }
-`),
-		checkVersionedAndroidBpContents(`
+`, `
 // This is auto-generated. DO NOT EDIT.
 
 java_sdk_library_import {
@@ -166,6 +219,6 @@
     java_systemserver_libs: ["mysdk_mylib@current"],
     systemserverclasspath_fragments: ["mysdk_mysystemserverclasspathfragment@current"],
 }
-`),
-	)
+`)
+	})
 }
diff --git a/sdk/update.go b/sdk/update.go
index 5db604b..0178874 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -242,7 +242,7 @@
 // Finally, the member type slices are concatenated together to form a single slice. The order in
 // which they are concatenated is the order in which the member types were registered in the
 // android.SdkMemberTypesRegistry.
-func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
+func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, targetBuildRelease *buildRelease, memberVariantDeps []sdkMemberVariantDep) []*sdkMember {
 	byType := make(map[android.SdkMemberType][]*sdkMember)
 	byName := make(map[string]*sdkMember)
 
@@ -265,13 +265,39 @@
 
 	var members []*sdkMember
 	for _, memberListProperty := range s.memberTypeListProperties() {
-		membersOfType := byType[memberListProperty.memberType]
+		memberType := memberListProperty.memberType
+
+		if !isMemberTypeSupportedByTargetBuildRelease(memberType, targetBuildRelease) {
+			continue
+		}
+
+		membersOfType := byType[memberType]
 		members = append(members, membersOfType...)
 	}
 
 	return members
 }
 
+// isMemberTypeSupportedByTargetBuildRelease returns true if the member type is supported by the
+// target build release.
+func isMemberTypeSupportedByTargetBuildRelease(memberType android.SdkMemberType, targetBuildRelease *buildRelease) bool {
+	supportedByTargetBuildRelease := true
+	supportedBuildReleases := memberType.SupportedBuildReleases()
+	if supportedBuildReleases == "" {
+		supportedBuildReleases = "S+"
+	}
+
+	set, err := parseBuildReleaseSet(supportedBuildReleases)
+	if err != nil {
+		panic(fmt.Errorf("member type %s has invalid supported build releases %q: %s",
+			memberType.SdkPropertyName(), supportedBuildReleases, err))
+	}
+	if !set.contains(targetBuildRelease) {
+		supportedByTargetBuildRelease = false
+	}
+	return supportedByTargetBuildRelease
+}
+
 func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
 	for _, v := range variants {
 		if v == newVariant {
@@ -416,7 +442,7 @@
 
 	// Group the variants for each member module together and then group the members of each member
 	// type together.
-	members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
+	members := s.groupMemberVariantsByMemberThenType(ctx, targetBuildRelease, memberVariantDeps)
 
 	// Create the prebuilt modules for each of the member modules.
 	traits := s.gatherTraits()
@@ -795,6 +821,9 @@
 		if memberListProperty.getter == nil {
 			continue
 		}
+		if !isMemberTypeSupportedByTargetBuildRelease(memberListProperty.memberType, builder.targetBuildRelease) {
+			continue
+		}
 		names := memberListProperty.getter(dynamicMemberTypeListProperties)
 		if len(names) > 0 {
 			propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
@@ -1902,6 +1931,12 @@
 	return m.requiredTraits.Contains(trait)
 }
 
+func (m *memberContext) IsTargetBuildBeforeTiramisu() bool {
+	return m.builder.targetBuildRelease.EarlierThan(buildReleaseT)
+}
+
+var _ android.SdkMemberContext = (*memberContext)(nil)
+
 func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
 
 	memberType := member.memberType
diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go
index f526838..8a957e1 100644
--- a/third_party/zip/writer.go
+++ b/third_party/zip/writer.go
@@ -162,9 +162,17 @@
 		if records > uint16max {
 			records = uint16max
 		}
+		// Only store uint32max for the size and the offset if they don't fit.
+		// Robolectric currently doesn't support zip64 and fails to find the
+		// offset to the central directory when the number of files in the zip
+		// is larger than 2^16.
+		if size > uint32max {
+			size = uint32max
+		}
+		if offset > uint32max {
+			offset = uint32max
+		}
 		// END ANDROID CHANGE
-		size = uint32max
-		offset = uint32max
 	}
 
 	// write end record
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 1c80cff..df1470a 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -154,11 +154,13 @@
 		hostCommonOut("obj/PACKAGING"),
 		productOut("*.img"),
 		productOut("*.zip"),
+		productOut("*.zip.sha256sum"),
 		productOut("android-info.txt"),
 		productOut("misc_info.txt"),
 		productOut("apex"),
 		productOut("kernel"),
 		productOut("kernel-*"),
+		productOut("recovery_kernel"),
 		productOut("data"),
 		productOut("skin"),
 		productOut("obj/NOTICE_FILES"),
@@ -187,7 +189,8 @@
 		productOut("odm_dlkm"),
 		productOut("sysloader"),
 		productOut("testcases"),
-		productOut("symbols"))
+		productOut("symbols"),
+		productOut("install"))
 }
 
 // Since products and build variants (unfortunately) shared the same
diff --git a/ui/build/config.go b/ui/build/config.go
index e271bfc..a676321 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -98,6 +98,8 @@
 	emptyNinjaFile bool
 
 	metricsUploader string
+
+	includeTags []string
 }
 
 const srcDirFileCheck = "build/soong/root.bp"
@@ -1038,6 +1040,14 @@
 	return c.parallel
 }
 
+func (c *configImpl) GetIncludeTags() []string {
+	return c.includeTags
+}
+
+func (c *configImpl) SetIncludeTags(i []string) {
+	c.includeTags = i
+}
+
 func (c *configImpl) HighmemParallel() int {
 	if i, ok := c.environ.GetInt("NINJA_HIGHMEM_NUM_JOBS"); ok {
 		return i
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 285f156..7fb747c 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -139,6 +139,8 @@
 var BannerVars = []string{
 	"PLATFORM_VERSION_CODENAME",
 	"PLATFORM_VERSION",
+	"LINEAGE_VERSION",
+	"PRODUCT_INCLUDE_TAGS",
 	"TARGET_PRODUCT",
 	"TARGET_BUILD_VARIANT",
 	"TARGET_BUILD_TYPE",
@@ -166,6 +168,12 @@
 	"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE",
 	"SOONG_SDK_SNAPSHOT_USE_SOURCE_CONFIG_VAR",
 	"SOONG_SDK_SNAPSHOT_VERSION",
+        "PRODUCT_IS_ATV",
+        "PRODUCT_IS_AUTO",
+	"WITH_SU",
+	"WITH_GMS",
+	"GMS_MAKEFILE",
+	"MAINLINE_MODULES_MAKEFILE",
 }
 
 func Banner(make_vars map[string]string) string {
@@ -295,4 +303,5 @@
 	config.SetBuildBrokenDupRules(makeVars["BUILD_BROKEN_DUP_RULES"] == "true")
 	config.SetBuildBrokenUsesNetwork(makeVars["BUILD_BROKEN_USES_NETWORK"] == "true")
 	config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(makeVars["BUILD_BROKEN_NINJA_USES_ENV_VARS"]))
+	config.SetIncludeTags(strings.Fields(makeVars["PRODUCT_INCLUDE_TAGS"]))
 }
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index 5b2046e..6b18079 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -235,6 +235,13 @@
 		sandboxArgs = append(sandboxArgs, "-N")
 	}
 
+	if ccacheExec := os.Getenv("CCACHE_EXEC"); ccacheExec != "" {
+		bytes, err := exec.Command(ccacheExec, "-k", "cache_dir").Output()
+		if err == nil {
+			sandboxArgs = append(sandboxArgs, "-B", strings.TrimSpace(string(bytes)))
+		}
+	}
+
 	// Stop nsjail from parsing arguments
 	sandboxArgs = append(sandboxArgs, "--")
 
diff --git a/ui/build/soong.go b/ui/build/soong.go
index c7f22f9..a0ab1cc 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -332,6 +332,7 @@
 	blueprintArgs.EmptyNinjaFile = false
 
 	blueprintCtx := blueprint.NewContext()
+	blueprintCtx.AddIncludeTags(config.GetIncludeTags()...)
 	blueprintCtx.SetIgnoreUnknownModuleTypes(true)
 	blueprintConfig := BlueprintConfig{
 		soongOutDir: config.SoongOutDir(),