Merge "Do not attempt to generate prebuilt_kernel_modules if they are not src" into main
diff --git a/android/apex.go b/android/apex.go
index 9277ff3..1bfcf04 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -224,11 +224,8 @@
 	// run.
 	DirectlyInAnyApex() bool
 
-	// NotInPlatform tells whether or not this module is included in an APEX and therefore
-	// shouldn't be exposed to the platform (i.e. outside of the APEX) directly. A module is
-	// considered to be included in an APEX either when there actually is an APEX that
-	// explicitly has the module as its dependency or the module is not available to the
-	// platform, which indicates that the module belongs to at least one or more other APEXes.
+	// NotInPlatform returns true if the module is not available to the platform due to
+	// apex_available being set and not containing "//apex_available:platform".
 	NotInPlatform() bool
 
 	// Tests if this module could have APEX variants. Even when a module type implements
@@ -291,14 +288,6 @@
 	// See ApexModule.DirectlyInAnyApex()
 	DirectlyInAnyApex bool `blueprint:"mutated"`
 
-	// AnyVariantDirectlyInAnyApex is true in the primary variant of a module if _any_ variant
-	// of the module is directly in any apex. This includes host, arch, asan, etc. variants. It
-	// is unused in any variant that is not the primary variant. Ideally this wouldn't be used,
-	// as it incorrectly mixes arch variants if only one arch is in an apex, but a few places
-	// depend on it, for example when an ASAN variant is created before the apexMutator. Call
-	// this after apex.apexMutator is run.
-	AnyVariantDirectlyInAnyApex bool `blueprint:"mutated"`
-
 	// See ApexModule.NotAvailableForPlatform()
 	NotAvailableForPlatform bool `blueprint:"mutated"`
 
@@ -428,7 +417,7 @@
 
 // Implements ApexModule
 func (m *ApexModuleBase) NotInPlatform() bool {
-	return m.ApexProperties.AnyVariantDirectlyInAnyApex || !m.AvailableFor(AvailableToPlatform)
+	return !m.AvailableFor(AvailableToPlatform)
 }
 
 // Implements ApexModule
@@ -802,22 +791,6 @@
 		}
 		return false
 	})
-
-	if base.ApexProperties.DirectlyInAnyApex {
-		// Variants of a module are always visited sequentially in order, so it is safe to
-		// write to another variant of this module. For a BottomUpMutator the
-		// PrimaryModule() is visited first and FinalModule() is visited last.
-		mctx.FinalModule().(ApexModule).apexModuleBase().ApexProperties.AnyVariantDirectlyInAnyApex = true
-	}
-
-	// If this is the FinalModule (last visited module) copy
-	// AnyVariantDirectlyInAnyApex to all the other variants
-	if mctx.IsFinalModule(am) {
-		mctx.VisitAllModuleVariants(func(variant Module) {
-			variant.(ApexModule).apexModuleBase().ApexProperties.AnyVariantDirectlyInAnyApex =
-				base.ApexProperties.AnyVariantDirectlyInAnyApex
-		})
-	}
 }
 
 // ApexMembership tells how a module became part of an APEX.
diff --git a/android/module_context.go b/android/module_context.go
index 2014907..ae7b54f 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -831,6 +831,11 @@
 }
 
 func (m *moduleContext) SetOutputFiles(outputFiles Paths, tag string) {
+	for _, outputFile := range outputFiles {
+		if outputFile == nil {
+			panic("outputfiles cannot be nil")
+		}
+	}
 	if tag == "" {
 		if len(m.outputFiles.DefaultOutputFiles) > 0 {
 			m.ModuleErrorf("Module %s default OutputFiles cannot be overwritten", m.ModuleName())
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 5e4af0b..b90ef3b 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -508,11 +508,10 @@
 }
 
 func (p *prebuiltModule) GenerateAndroidBuildActions(ctx ModuleContext) {
-	var src Path
 	if len(p.properties.Srcs) >= 1 {
-		src = p.prebuilt.SingleSourcePath(ctx)
+		src := p.prebuilt.SingleSourcePath(ctx)
+		ctx.SetOutputFiles(Paths{src}, "")
 	}
-	ctx.SetOutputFiles(Paths{src}, "")
 }
 
 func (p *prebuiltModule) Prebuilt() *Prebuilt {
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 403c184..a157386 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -611,6 +611,7 @@
 		nsjailCmd.WriteString(" -m none:/tmp:tmpfs:size=1073741824") // 1GB, should be enough
 		nsjailCmd.WriteString(" -D nsjail_build_sandbox")
 		nsjailCmd.WriteString(" --disable_rlimits")
+		nsjailCmd.WriteString(" --skip_setsid") // ABFS relies on process-groups to track file operations
 		nsjailCmd.WriteString(" -q")
 		nsjailCmd.WriteString(" -- ")
 		nsjailCmd.WriteString("/bin/bash -c ")
diff --git a/android/variable.go b/android/variable.go
index 2d43c6d..88cf5a5 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -610,6 +610,7 @@
 	CopyImagesForTargetFilesZip    bool   `json:",omitempty"`
 
 	// Boot image stuff
+	BuildingRamdiskImage            bool   `json:",omitempty"`
 	ProductBuildBootImage           bool   `json:",omitempty"`
 	ProductBuildInitBootImage       bool   `json:",omitempty"`
 	BoardUsesRecoveryAsBoot         bool   `json:",omitempty"`
@@ -618,6 +619,7 @@
 	BoardBootimagePartitionSize     string `json:",omitempty"`
 	BoardInitBootimagePartitionSize string `json:",omitempty"`
 	BoardBootHeaderVersion          string `json:",omitempty"`
+	TargetKernelPath                string `json:",omitempty"`
 
 	// Avb (android verified boot) stuff
 	BoardAvbEnable          bool                                `json:",omitempty"`
diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go
index 76227a9..0eb8ef4 100644
--- a/apex/aconfig_test.go
+++ b/apex/aconfig_test.go
@@ -60,6 +60,7 @@
 					apex_available: [
 						"myapex",
 					],
+					compile_dex: true,
 				}
 				aconfig_declarations {
 					name: "my_aconfig_declarations_foo",
@@ -339,6 +340,7 @@
 					apex_available: [
 						"myapex",
 					],
+					compile_dex: true,
 				}
 				aconfig_declarations {
 					name: "my_aconfig_declarations_foo",
@@ -761,6 +763,7 @@
 					apex_available: [
 						"myapex",
 					],
+					compile_dex: true,
 				}
 				java_library {
 					name: "my_java_library_foo",
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d0494d6..5b5fe5f 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -495,6 +495,7 @@
 				"//apex_available:platform",
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		dex_import {
@@ -664,6 +665,7 @@
 			sdk_version: "none",
 			system_modules: "none",
 			apex_available: [ "myapex" ],
+			compile_dex: true,
 		}
 
 		android_app {
@@ -2035,6 +2037,7 @@
 			apex_available: [ "myapex" ],
 			sdk_version: "current",
 			min_sdk_version: "S", // should be okay
+			compile_dex: true,
 		}
 	`,
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -2584,6 +2587,7 @@
 				"myapex",
 			],
 			min_sdk_version: "30",
+			compile_dex: true,
 		}
 	`)
 
@@ -2611,6 +2615,7 @@
 			// Compile against core API surface
 			sdk_version: "core_current",
 			min_sdk_version: "30",
+			compile_dex: true,
 		}
 	`)
 
@@ -2658,6 +2663,7 @@
 			],
 			apex_available: ["myapex"],
 			min_sdk_version: "29",
+			compile_dex: true,
 		}
 
 		java_library {
@@ -2737,6 +2743,7 @@
 					srcs: ["foo/bar/MyClass.java"],
 					sdk_version: "test_current",
 					apex_available: ["myapex"],
+					compile_dex: true,
 				}
 			`,
 		},
@@ -2761,6 +2768,7 @@
 					sdk_version: "current",
 					apex_available: ["myapex"],
 					min_sdk_version: "29",
+					compile_dex: true,
 				}
 			`,
 		},
@@ -2784,6 +2792,7 @@
 					srcs: ["foo/bar/MyClass.java"],
 					sdk_version: "test_current",
 					apex_available: ["myapex"],
+					compile_dex: true,
 				}
 			`,
 		},
@@ -2807,6 +2816,7 @@
 					srcs: ["foo/bar/MyClass.java"],
 					sdk_version: "core_platform",
 					apex_available: ["myapex"],
+					compile_dex: true,
 				}
 			`,
 			preparer: java.FixtureUseLegacyCorePlatformApi("myjar-uses-legacy"),
@@ -2835,6 +2845,7 @@
 					sdk_version: "current",
 					apex_available: ["myapex"],
 					static_libs: ["transitive-jar"],
+					compile_dex: true,
 				}
 				java_library {
 					name: "transitive-jar",
@@ -5913,6 +5924,7 @@
 			system_modules: "none",
 			enabled: false,
 			apex_available: ["myapex"],
+			compile_dex: true,
 		}
 	`)
 }
@@ -7525,6 +7537,7 @@
 			apex_available: ["myapex"],
 			sdk_version: "none",
 			system_modules: "none",
+			compile_dex: true,
 		}
 
 		java_library {
@@ -7534,6 +7547,7 @@
 			apex_available: ["myapex"],
 			sdk_version: "none",
 			system_modules: "none",
+			compile_dex: true,
 		}
 
 		prebuilt_apis {
@@ -7643,6 +7657,7 @@
 			apex_available: ["myapex"],
 			sdk_version: "none",
 			system_modules: "none",
+			compile_dex: true,
 		}
 `),
 			"source/a.java":          nil,
@@ -7664,6 +7679,7 @@
 			public: {
 				enabled: true,
 			},
+			compile_dex: true,
 		}
 `),
 			"prebuilt/a.jar": nil,
@@ -7680,6 +7696,7 @@
 			public: {
 				jars: ["a.jar"],
 			},
+			compile_dex: true,
 		}
 `),
 		}), withFiles(filesForSdkLibrary),
@@ -7758,6 +7775,7 @@
 			sdk_version: "none",
 			system_modules: "none",
 			apex_available: [ "myapex" ],
+			compile_dex: true,
 		}
 
 		// Make sure that a preferred prebuilt does not affect the apex contents.
@@ -7997,6 +8015,7 @@
 				"//apex_available:platform",
 			],
 			min_sdk_version: "33",
+			compile_dex: true,
 		}
 
 		java_library {
@@ -8605,6 +8624,7 @@
 					apex_available: ["myapex"],
 					sdk_version: "none",
 					system_modules: "none",
+					compile_dex: true,
 				}
 				java_library {
 					name: "nonbcp_lib2",
@@ -8613,6 +8633,7 @@
 					permitted_packages: ["a.b"],
 					sdk_version: "none",
 					system_modules: "none",
+					compile_dex: true,
 				}
 				apex {
 					name: "myapex",
@@ -8638,6 +8659,7 @@
 					permitted_packages: ["foo.bar"],
 					sdk_version: "none",
 					system_modules: "none",
+					compile_dex: true,
 				}
 				java_library {
 					name: "bcp_lib2",
@@ -8646,6 +8668,7 @@
 					permitted_packages: ["foo.bar", "bar.baz"],
 					sdk_version: "none",
 					system_modules: "none",
+					compile_dex: true,
 				}
 				apex {
 					name: "myapex",
@@ -8676,6 +8699,7 @@
 					sdk_version: "none",
 					min_sdk_version: "29",
 					system_modules: "none",
+					compile_dex: true,
 				}
 				java_library {
 					name: "bcp_lib_unrestricted",
@@ -8685,6 +8709,7 @@
 					sdk_version: "none",
 					min_sdk_version: "29",
 					system_modules: "none",
+					compile_dex: true,
 				}
 				apex {
 					name: "myapex",
@@ -9834,6 +9859,7 @@
 			},
 			sdk_version: "current",
 			min_sdk_version: "29",
+			compile_dex: true,
 		}
 		`
 	fs := android.MockFS{
@@ -10268,6 +10294,7 @@
 			apex_available: [
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		java_library {
@@ -10279,6 +10306,7 @@
 			apex_available: [
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		aconfig_declarations {
@@ -10365,6 +10393,7 @@
 			apex_available: [
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		cc_library {
@@ -10691,6 +10720,7 @@
 			apex_available: [
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		java_library {
@@ -10702,6 +10732,7 @@
 			apex_available: [
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		aconfig_declarations {
@@ -10776,6 +10807,7 @@
 			apex_available: [
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		java_library {
@@ -10787,6 +10819,7 @@
 			apex_available: [
 				"myapex",
 			],
+			compile_dex: true,
 		}
 
 		aconfig_declarations {
@@ -11469,6 +11502,7 @@
 			apex_available: ["com.android.apex30"],
 			min_sdk_version: "30",
 			sdk_version: "current",
+			compile_dex: true,
 		}
 
 		override_apex {
@@ -11760,6 +11794,7 @@
 				"com.android.foo30",
 			],
 			sdk_version: "core_current",
+			compile_dex: true,
 		}
 
 		java_library {
diff --git a/apex/container_test.go b/apex/container_test.go
index d1dfb9c..395793f 100644
--- a/apex/container_test.go
+++ b/apex/container_test.go
@@ -15,10 +15,11 @@
 package apex
 
 import (
-	"android/soong/android"
-	"android/soong/java"
 	"fmt"
 	"testing"
+
+	"android/soong/android"
+	"android/soong/java"
 )
 
 var checkContainerMatch = func(t *testing.T, name string, container string, expected bool, actual bool) {
@@ -329,6 +330,7 @@
 			],
 			min_sdk_version: "30",
 			sdk_version: "current",
+			compile_dex: true,
 		}
 	`)
 
diff --git a/cc/binary.go b/cc/binary.go
index 2ac9a45..4b77bea 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -505,7 +505,7 @@
 	// The original path becomes a symlink to the corresponding file in the
 	// runtime APEX.
 	translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
-	if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !ctx.Host() && ctx.directlyInAnyApex() &&
+	if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !ctx.Host() && !ctx.isSdkVariant() &&
 		!translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() &&
 		!ctx.inVendorRamdisk() {
 
diff --git a/cc/cc.go b/cc/cc.go
index 76d01a5..bd91964 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -548,7 +548,6 @@
 	apexSdkVersion() android.ApiLevel
 	bootstrap() bool
 	nativeCoverage() bool
-	directlyInAnyApex() bool
 	isPreventInstall() bool
 	isCfiAssemblySupportEnabled() bool
 	getSharedFlags() *SharedFlags
@@ -1692,10 +1691,6 @@
 	return ctx.mod.nativeCoverage()
 }
 
-func (ctx *moduleContextImpl) directlyInAnyApex() bool {
-	return ctx.mod.DirectlyInAnyApex()
-}
-
 func (ctx *moduleContextImpl) isPreventInstall() bool {
 	return ctx.mod.Properties.PreventInstall
 }
diff --git a/cc/image.go b/cc/image.go
index ee40483..9766af3 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -179,9 +179,6 @@
 	// SnapshotVersion returns the snapshot version for this module.
 	SnapshotVersion(mctx android.ImageInterfaceContext) string
 
-	// SdkVersion returns the SDK version for this module.
-	SdkVersion() string
-
 	// ExtraVariants returns the list of extra variants this module requires.
 	ExtraVariants() []string
 
@@ -370,7 +367,7 @@
 		if m.HasProductVariant() {
 			productVariantNeeded = true
 		}
-	} else if vendorSpecific && m.SdkVersion() == "" {
+	} else if vendorSpecific {
 		// This will be available in /vendor (or /odm) only
 		vendorVariantNeeded = true
 	} else {
@@ -380,7 +377,7 @@
 		coreVariantNeeded = true
 	}
 
-	if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
+	if coreVariantNeeded && productSpecific {
 		// The module has "product_specific: true" that does not create core variant.
 		coreVariantNeeded = false
 		productVariantNeeded = true
diff --git a/cc/library.go b/cc/library.go
index 4ce506e..23ee9b1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -656,7 +656,7 @@
 	// However, having this distinction helps guard accidental
 	// promotion or demotion of API and also helps the API review process b/191371676
 	var flag string
-	if ctx.Module().(android.ApexModule).NotInPlatform() {
+	if ctx.notInPlatform() {
 		flag = "--apex"
 	} else {
 		flag = "--systemapi"
@@ -740,6 +740,7 @@
 	hasLLNDKStubs() bool
 	hasLLNDKHeaders() bool
 	hasVendorPublicLibrary() bool
+	isLLNDKMovedToApex() bool
 }
 
 var _ libraryInterface = (*libraryDecorator)(nil)
@@ -1750,21 +1751,17 @@
 
 func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if library.shared() {
-		if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() {
+		translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
+		if library.hasStubsVariants() && !ctx.Host() && !ctx.isSdkVariant() &&
+			InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() &&
+			!translatedArch && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() {
 			// Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory.
 			// The original path becomes a symlink to the corresponding file in the
 			// runtime APEX.
-			translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
-			if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() &&
-				!translatedArch && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() {
-				if ctx.Device() {
-					library.installSymlinkToRuntimeApex(ctx, file)
-				}
-				library.baseInstaller.subDir = "bootstrap"
+			if ctx.Device() {
+				library.installSymlinkToRuntimeApex(ctx, file)
 			}
-		} else if ctx.directlyInAnyApex() && ctx.IsLlndk() && !isBionic(ctx.baseModuleName()) {
-			// Skip installing LLNDK (non-bionic) libraries moved to APEX.
-			ctx.Module().HideFromMake()
+			library.baseInstaller.subDir = "bootstrap"
 		}
 
 		library.baseInstaller.install(ctx, file)
@@ -1848,6 +1845,11 @@
 	return Bool(library.Properties.Llndk.Llndk_headers)
 }
 
+// isLLNDKMovedToApex returns true if this cc_library module sets the llndk.moved_to_apex property.
+func (library *libraryDecorator) isLLNDKMovedToApex() bool {
+	return Bool(library.Properties.Llndk.Moved_to_apex)
+}
+
 // hasVendorPublicLibrary returns true if this cc_library module has a variant that will build
 // vendor public library stubs.
 func (library *libraryDecorator) hasVendorPublicLibrary() bool {
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index c7950f9..162dd54 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -57,17 +57,18 @@
 	// if true, make this module available to provide headers to other modules that set
 	// llndk.symbol_file.
 	Llndk_headers *bool
+
+	// moved_to_apex marks this module has having been distributed through an apex module.
+	Moved_to_apex *bool
 }
 
 func makeLlndkVars(ctx android.MakeVarsContext) {
-	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
-	// they been moved to an apex.
+	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to generate the linker config.
 	movedToApexLlndkLibraries := make(map[string]bool)
 	ctx.VisitAllModules(func(module android.Module) {
 		if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
-			// Skip bionic libs, they are handled in different manner
-			name := library.implementationModuleName(module.(*Module).BaseModuleName())
-			if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) {
+			if library.isLLNDKMovedToApex() {
+				name := library.implementationModuleName(module.(*Module).BaseModuleName())
 				movedToApexLlndkLibraries[name] = true
 			}
 		}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index f0d7343..d8d8c7a 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1504,9 +1504,6 @@
 
 		if Bool(sanProps.Memtag_globals) {
 			sanitizers = append(sanitizers, "memtag-globals")
-			// TODO(mitchp): For now, enable memtag-heap with memtag-globals because the linker
-			// isn't new enough (https://reviews.llvm.org/differential/changeset/?ref=4243566).
-			sanitizers = append(sanitizers, "memtag-heap")
 		}
 
 		if Bool(sanProps.Fuzzer) {
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state.go b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
index f0242b7..2b8c395 100644
--- a/cmd/find_input_delta/find_input_delta_lib/internal_state.go
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state.go
@@ -18,7 +18,7 @@
 	"errors"
 	"fmt"
 	"io/fs"
-	"path/filepath"
+	"regexp"
 	"slices"
 
 	fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto_internal"
@@ -73,15 +73,16 @@
 	return ret, nil
 }
 
+// We ignore any suffix digit caused by sharding.
+var InspectExtsZipRegexp = regexp.MustCompile("\\.(jar|apex|apk)[0-9]*$")
+
 // Inspect the file and extract the state of the elements in the archive.
 // If this is not an archive of some sort, nil is returned.
 func InspectFileContents(name string) ([]*fid_proto.PartialCompileInput, error) {
-	switch filepath.Ext(name) {
-	case ".jar", ".apex", ".apk":
+	if InspectExtsZipRegexp.Match([]byte(name)) {
 		return inspectZipFileContents(name)
-	default:
-		return nil, nil
 	}
+	return nil, nil
 }
 
 func inspectZipFileContents(name string) ([]*fid_proto.PartialCompileInput, error) {
diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go
index e69424c..c168d5a 100644
--- a/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go
+++ b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go
@@ -259,3 +259,25 @@
 		}
 	}
 }
+
+func TestCompareInspectExtsZipRegexp(t *testing.T) {
+	testCases := []struct {
+		Name     string
+		Expected bool
+	}{
+		{Name: ".jar", Expected: true},
+		{Name: ".jar5", Expected: true},
+		{Name: ".apex", Expected: true},
+		{Name: ".apex9", Expected: true},
+		{Name: ".apexx", Expected: false},
+		{Name: ".apk", Expected: true},
+		{Name: ".apk3", Expected: true},
+		{Name: ".go", Expected: false},
+	}
+	for _, tc := range testCases {
+		actual := InspectExtsZipRegexp.Match([]byte(tc.Name))
+		if tc.Expected != actual {
+			t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual)
+		}
+	}
+}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index c9bd617..226d95c 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -26,19 +26,19 @@
 )
 
 func init() {
-	android.RegisterModuleType("bootimg", bootimgFactory)
+	android.RegisterModuleType("bootimg", BootimgFactory)
 }
 
 type bootimg struct {
 	android.ModuleBase
 
-	properties bootimgProperties
+	properties BootimgProperties
 
 	output     android.Path
 	installDir android.InstallPath
 }
 
-type bootimgProperties struct {
+type BootimgProperties struct {
 	// Set the name of the output. Defaults to <module_name>.img.
 	Stem *string
 
@@ -82,7 +82,7 @@
 }
 
 // bootimg is the image for the boot partition. It consists of header, kernel, ramdisk, and dtb.
-func bootimgFactory() android.Module {
+func BootimgFactory() android.Module {
 	module := &bootimg{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index f325d96..7c342cc 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -666,7 +666,9 @@
 
 	partition := result.ModuleForTests("myfilesystem", "android_common")
 	fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
-	android.AssertDeepEquals(t, "cc_library listed in deps", "lib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo.so\nlib64/libm.so\n", fileList)
+	android.AssertDeepEquals(t, "cc_library listed in deps",
+		"lib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo.so\nlib64/libm.so\n",
+		fileList)
 }
 
 // binfoo1 overrides binbar. transitive deps of binbar should not be installed.
@@ -701,7 +703,9 @@
 
 	partition := result.ModuleForTests("myfilesystem", "android_common")
 	fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
-	android.AssertDeepEquals(t, "Shared library dep of overridden binary should not be installed", fileList, "bin/binfoo1\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo2.so\nlib64/libm.so\n")
+	android.AssertDeepEquals(t, "Shared library dep of overridden binary should not be installed",
+		"bin/binfoo1\nlib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo2.so\nlib64/libm.so\n",
+		fileList)
 }
 
 func TestInstallLinkerConfigFile(t *testing.T) {
diff --git a/fsgen/Android.bp b/fsgen/Android.bp
index 8cd7518..a022581 100644
--- a/fsgen/Android.bp
+++ b/fsgen/Android.bp
@@ -13,6 +13,7 @@
         "soong-kernel",
     ],
     srcs: [
+        "boot_imgs.go",
         "filesystem_creator.go",
         "fsgen_mutators.go",
         "prebuilt_etc_modules_gen.go",
diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go
new file mode 100644
index 0000000..66d9107
--- /dev/null
+++ b/fsgen/boot_imgs.go
@@ -0,0 +1,78 @@
+package fsgen
+
+import (
+	"android/soong/android"
+	"android/soong/filesystem"
+	"path/filepath"
+
+	"github.com/google/blueprint/proptools"
+)
+
+func createBootImage(ctx android.LoadHookContext) bool {
+	partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+
+	if partitionVariables.TargetKernelPath == "" {
+		// There are potentially code paths that don't set TARGET_KERNEL_PATH
+		return false
+	}
+
+	kernelDir := filepath.Dir(partitionVariables.TargetKernelPath)
+	kernelBase := filepath.Base(partitionVariables.TargetKernelPath)
+	kernelFilegroupName := generatedModuleName(ctx.Config(), "kernel")
+
+	ctx.CreateModuleInDirectory(
+		android.FileGroupFactory,
+		kernelDir,
+		&struct {
+			Name       *string
+			Srcs       []string
+			Visibility []string
+		}{
+			Name:       proptools.StringPtr(kernelFilegroupName),
+			Srcs:       []string{kernelBase},
+			Visibility: []string{"//visibility:public"},
+		},
+	)
+
+	bootImageName := generatedModuleNameForPartition(ctx.Config(), "boot")
+
+	ctx.CreateModule(
+		filesystem.BootimgFactory,
+		&filesystem.BootimgProperties{
+			Kernel_prebuilt: proptools.StringPtr(":" + kernelFilegroupName),
+			Ramdisk_module:  proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")),
+			Header_version:  proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+		},
+		&struct {
+			Name *string
+		}{
+			Name: proptools.StringPtr(bootImageName),
+		},
+	)
+	return true
+}
+
+// Returns the equivalent of the BUILDING_BOOT_IMAGE variable in make. Derived from this logic:
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=458;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
+func buildingBootImage(partitionVars android.PartitionVariables) bool {
+	if partitionVars.BoardUsesRecoveryAsBoot {
+		return false
+	}
+
+	if partitionVars.ProductBuildBootImage {
+		return true
+	}
+
+	if len(partitionVars.BoardPrebuiltBootimage) > 0 {
+		return false
+	}
+
+	if len(partitionVars.BoardBootimagePartitionSize) > 0 {
+		return true
+	}
+
+	// TODO: return true if BOARD_KERNEL_BINARIES is set and has a *_BOOTIMAGE_PARTITION_SIZE
+	// variable. However, I don't think BOARD_KERNEL_BINARIES is ever set in practice.
+
+	return false
+}
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index dca44f0..b1b8f6a 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -47,6 +47,8 @@
 
 	Vbmeta_module_names    []string `blueprint:"mutated"`
 	Vbmeta_partition_names []string `blueprint:"mutated"`
+
+	Boot_image string `blueprint:"mutated" android:"path_device_first"`
 }
 
 type filesystemCreator struct {
@@ -71,6 +73,38 @@
 	return module
 }
 
+func generatedPartitions(ctx android.LoadHookContext) []string {
+	generatedPartitions := []string{"system"}
+	if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
+		generatedPartitions = append(generatedPartitions, "system_ext")
+	}
+	if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
+		generatedPartitions = append(generatedPartitions, "vendor")
+	}
+	if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" {
+		generatedPartitions = append(generatedPartitions, "product")
+	}
+	if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
+		generatedPartitions = append(generatedPartitions, "odm")
+	}
+	if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" {
+		generatedPartitions = append(generatedPartitions, "userdata")
+	}
+	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
+		generatedPartitions = append(generatedPartitions, "system_dlkm")
+	}
+	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingVendorDlkmImage {
+		generatedPartitions = append(generatedPartitions, "vendor_dlkm")
+	}
+	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingOdmDlkmImage {
+		generatedPartitions = append(generatedPartitions, "odm_dlkm")
+	}
+	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingRamdiskImage {
+		generatedPartitions = append(generatedPartitions, "ramdisk")
+	}
+	return generatedPartitions
+}
+
 func (f *filesystemCreator) createInternalModules(ctx android.LoadHookContext) {
 	soongGeneratedPartitions := generatedPartitions(ctx)
 	finalSoongGeneratedPartitions := make([]string, 0, len(soongGeneratedPartitions))
@@ -83,6 +117,14 @@
 		}
 	}
 
+	if buildingBootImage(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse) {
+		if createBootImage(ctx) {
+			f.properties.Boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "boot")
+		} else {
+			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "boot")
+		}
+	}
+
 	for _, x := range createVbmetaPartitions(ctx, finalSoongGeneratedPartitions) {
 		f.properties.Vbmeta_module_names = append(f.properties.Vbmeta_module_names, x.moduleName)
 		f.properties.Vbmeta_partition_names = append(f.properties.Vbmeta_partition_names, x.partitionName)
@@ -176,7 +218,6 @@
 				Name:   proptools.StringPtr("system/lib/modules"),
 			},
 		}
-		fsProps.Base_dir = proptools.StringPtr("system")
 	case "system_ext":
 		fsProps.Fsverity.Inputs = []string{
 			"framework/*",
@@ -198,7 +239,6 @@
 				Name:   proptools.StringPtr("vendor/lib/modules"),
 			},
 		}
-		fsProps.Base_dir = proptools.StringPtr("vendor")
 	case "odm":
 		fsProps.Symlinks = []filesystem.SymlinkDefinition{
 			filesystem.SymlinkDefinition{
@@ -206,7 +246,6 @@
 				Name:   proptools.StringPtr("odm/lib/modules"),
 			},
 		}
-		fsProps.Base_dir = proptools.StringPtr("odm")
 	case "userdata":
 		fsProps.Base_dir = proptools.StringPtr("data")
 
@@ -546,7 +585,7 @@
 	return fsProps, true
 }
 
-func (f *filesystemCreator) createDiffTest(ctx android.ModuleContext, partitionType string) android.Path {
+func (f *filesystemCreator) createFileListDiffTest(ctx android.ModuleContext, partitionType string) android.Path {
 	partitionModuleName := generatedModuleNameForPartition(ctx.Config(), partitionType)
 	systemImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag)
 	filesystemInfo, ok := android.OtherModuleProvider(ctx, systemImage, filesystem.FilesystemProvider)
@@ -591,13 +630,17 @@
 	makeVbmetaFile := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/%s.img", ctx.Config().DeviceName(), vbmetaPartitionName))
 
 	diffTestResultFile := android.PathForModuleOut(ctx, fmt.Sprintf("diff_test_%s.txt", vbmetaModuleName))
+	createDiffTest(ctx, diffTestResultFile, soongVbMetaFile, makeVbmetaFile)
+	return diffTestResultFile
+}
+
+func createDiffTest(ctx android.ModuleContext, diffTestResultFile android.WritablePath, file1 android.Path, file2 android.Path) {
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().Text("diff").
-		Input(soongVbMetaFile).
-		Input(makeVbmetaFile)
+		Input(file1).
+		Input(file2)
 	builder.Command().Text("touch").Output(diffTestResultFile)
-	builder.Build(vbmetaModuleName+" diff test", vbmetaModuleName+" diff test")
-	return diffTestResultFile
+	builder.Build("diff test "+diffTestResultFile.String(), "diff test")
 }
 
 type systemImageDepTagType struct {
@@ -634,7 +677,7 @@
 
 	var diffTestFiles []android.Path
 	for _, partitionType := range f.properties.Generated_partition_types {
-		diffTestFile := f.createDiffTest(ctx, partitionType)
+		diffTestFile := f.createFileListDiffTest(ctx, partitionType)
 		diffTestFiles = append(diffTestFiles, diffTestFile)
 		ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile)
 	}
@@ -648,6 +691,14 @@
 		diffTestFiles = append(diffTestFiles, diffTestFile)
 		ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", f.properties.Vbmeta_partition_names[i]), diffTestFile)
 	}
+	if f.properties.Boot_image != "" {
+		diffTestFile := android.PathForModuleOut(ctx, "boot_diff_test.txt")
+		soongBootImg := android.PathForModuleSrc(ctx, f.properties.Boot_image)
+		makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/boot.img", ctx.Config().DeviceName()))
+		createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage)
+		diffTestFiles = append(diffTestFiles, diffTestFile)
+		ctx.Phony("soong_generated_boot_filesystem_test", diffTestFile)
+	}
 	ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...)
 }
 
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 7b30264..0d18660 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -84,36 +84,6 @@
 	}
 }
 
-func generatedPartitions(ctx android.LoadHookContext) []string {
-	generatedPartitions := []string{"system", "ramdisk"}
-	if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
-		generatedPartitions = append(generatedPartitions, "system_ext")
-	}
-	if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
-		generatedPartitions = append(generatedPartitions, "vendor")
-	}
-	if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" {
-		generatedPartitions = append(generatedPartitions, "product")
-	}
-	if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
-		generatedPartitions = append(generatedPartitions, "odm")
-	}
-	if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" {
-		generatedPartitions = append(generatedPartitions, "userdata")
-	}
-	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
-		generatedPartitions = append(generatedPartitions, "system_dlkm")
-	}
-	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingVendorDlkmImage {
-		generatedPartitions = append(generatedPartitions, "vendor_dlkm")
-	}
-	if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingOdmDlkmImage {
-		generatedPartitions = append(generatedPartitions, "odm_dlkm")
-	}
-
-	return generatedPartitions
-}
-
 func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string, avbpubkeyGenerated bool) *FsGenState {
 	return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
 		partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
diff --git a/fsgen/vbmeta_partitions.go b/fsgen/vbmeta_partitions.go
index b7fff68..11c5759 100644
--- a/fsgen/vbmeta_partitions.go
+++ b/fsgen/vbmeta_partitions.go
@@ -19,6 +19,7 @@
 	"android/soong/filesystem"
 	"slices"
 	"strconv"
+	"strings"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -153,8 +154,10 @@
 			// Already handled by a chained vbmeta partition
 			continue
 		}
-		if partitionType == "ramdisk" {
+		if strings.Contains(partitionType, "ramdisk") || strings.Contains(partitionType, "boot") {
 			// ramdisk is never signed with avb information
+			// boot partitions just have the avb footer, and don't have a corresponding vbmeta
+			// partition.
 			continue
 		}
 		partitionModules = append(partitionModules, generatedModuleNameForPartition(ctx.Config(), partitionType))
diff --git a/java/base.go b/java/base.go
index 8dad2d9..3bf2e23 100644
--- a/java/base.go
+++ b/java/base.go
@@ -714,10 +714,10 @@
 
 // helper method for java modules to set OutputFilesProvider
 func setOutputFiles(ctx android.ModuleContext, m Module) {
-	ctx.SetOutputFiles(append(android.Paths{m.outputFile}, m.extraOutputFiles...), "")
-	ctx.SetOutputFiles(android.Paths{m.outputFile}, android.DefaultDistTag)
-	ctx.SetOutputFiles(android.Paths{m.implementationAndResourcesJar}, ".jar")
-	ctx.SetOutputFiles(android.Paths{m.headerJarFile}, ".hjar")
+	ctx.SetOutputFiles(append(android.PathsIfNonNil(m.outputFile), m.extraOutputFiles...), "")
+	ctx.SetOutputFiles(android.PathsIfNonNil(m.outputFile), android.DefaultDistTag)
+	ctx.SetOutputFiles(android.PathsIfNonNil(m.implementationAndResourcesJar), ".jar")
+	ctx.SetOutputFiles(android.PathsIfNonNil(m.headerJarFile), ".hjar")
 	if m.dexer.proguardDictionary.Valid() {
 		ctx.SetOutputFiles(android.Paths{m.dexer.proguardDictionary.Path()}, ".proguard_map")
 	}
@@ -766,7 +766,8 @@
 	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
 
-	if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() {
+	compileDex := Bool(j.dexProperties.Compile_dex) || Bool(j.properties.Installable)
+	if compileDex && !isJacocoAgent && !apexInfo.IsForPlatform() {
 		if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
 			return true
 		} else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
@@ -1735,7 +1736,12 @@
 
 	completeStaticLibsImplementationJarsToCombine := completeStaticLibsImplementationJars
 
-	if j.shouldInstrument(ctx) {
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+
+	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
+	compileDex := Bool(j.dexProperties.Compile_dex) || Bool(j.properties.Installable)
+
+	if j.shouldInstrument(ctx) && (!ctx.Device() || compileDex) {
 		instrumentedOutputFile := j.instrument(ctx, flags, outputFile, jarName, specs)
 		completeStaticLibsImplementationJarsToCombine = depset.New(depset.PREORDER, android.Paths{instrumentedOutputFile}, nil)
 		outputFile = instrumentedOutputFile
@@ -1764,19 +1770,7 @@
 
 	j.implementationAndResourcesJar = outputFile
 
-	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
-	compileDex := j.dexProperties.Compile_dex
-	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
-	if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
-		if compileDex == nil {
-			compileDex = proptools.BoolPtr(true)
-		}
-		if j.deviceProperties.Hostdex == nil {
-			j.deviceProperties.Hostdex = proptools.BoolPtr(true)
-		}
-	}
-
-	if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) {
+	if ctx.Device() && compileDex {
 		if j.hasCode(ctx) {
 			if j.shouldInstrumentStatic(ctx) {
 				j.dexer.extraProguardFlagsFiles = append(j.dexer.extraProguardFlagsFiles,
@@ -2328,7 +2322,10 @@
 		"stable.core.platform.api.stubs",
 		"stub-annotations", "private-stub-annotations-jar",
 		"core-lambda-stubs",
-		"core-generated-annotation-stubs":
+		"core-generated-annotation-stubs",
+		// jacocoagent only uses core APIs, but has to specify a non-core sdk_version so it can use
+		// a prebuilt SDK to avoid circular dependencies when it statically included in the bootclasspath.
+		"jacocoagent":
 		return javaCore, true
 	case android.SdkPublic.DefaultJavaLibraryName():
 		return javaSdk, true
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 8271392..2dda72b 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -578,7 +578,6 @@
 
 	rule.Build("javadoc", "javadoc")
 
-	ctx.SetOutputFiles(android.Paths{j.stubsSrcJar}, "")
 	ctx.SetOutputFiles(android.Paths{j.docZip}, ".docs.zip")
 }
 
diff --git a/java/droidstubs.go b/java/droidstubs.go
index cf3e219..bc26527 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -1011,7 +1011,7 @@
 			cmd.FlagWithOutput("--update-baseline:api-lint ", updatedBaselineOutput)
 
 			msg += fmt.Sprintf(``+
-				`3. FOR LSC ONLY: You can update the baseline by executing\n` +
+				`3. FOR LSC ONLY: You can update the baseline by executing\n`+
 				`   the following command:\n`+
 				`       (cd $ANDROID_BUILD_TOP && cp \\\n`+
 				`       "%s" \\\n`+
@@ -1374,7 +1374,7 @@
 		for _, stubType := range android.SortedKeys(stubsTypeToPrefix) {
 			tagWithPrefix := stubsTypeToPrefix[stubType] + tag
 			outputFile, err := tagToOutputFileFunc[tag](stubType)
-			if err == nil {
+			if err == nil && outputFile != nil {
 				ctx.SetOutputFiles(android.Paths{outputFile}, tagWithPrefix)
 			}
 		}
diff --git a/java/java_test.go b/java/java_test.go
index 54eb3e1..d415679 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -3050,6 +3050,7 @@
 		java_library {
 			name: "android.car",
 			srcs: ["android.car.java"],
+			installable: true,
 		}
 	`)
 
diff --git a/java/testing.go b/java/testing.go
index 988514d..cb3245b 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -190,6 +190,7 @@
 				"//apex_available:anyapex",
 				"//apex_available:platform",
 			],
+			compile_dex: true,
 		}
 	`)),
 )