Merge changes Ia21f1456,Ie966aa61 into main

* changes:
  Generate META/(root|vendor_boot)_filesystem_config.txt
  Create META/boot_filesystem_config.txt in target_files.zip
diff --git a/android/arch.go b/android/arch.go
index 3cd6e4b..d6b2971 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1553,7 +1553,7 @@
 	config.BuildOS = func() OsType {
 		switch runtime.GOOS {
 		case "linux":
-			if Bool(config.productVariables.HostMusl) {
+			if Bool(config.productVariables.HostMusl) || runtime.GOARCH == "arm64" {
 				return LinuxMusl
 			}
 			return Linux
@@ -1565,11 +1565,25 @@
 	}()
 
 	config.BuildArch = func() ArchType {
-		switch runtime.GOARCH {
-		case "amd64":
-			return X86_64
+		switch runtime.GOOS {
+		case "linux":
+			switch runtime.GOARCH {
+			case "amd64":
+				return X86_64
+			case "arm64":
+				return Arm64
+			default:
+				panic(fmt.Sprintf("unsupported arch: %s", runtime.GOARCH))
+			}
+		case "darwin":
+			switch runtime.GOARCH {
+			case "amd64":
+				return X86_64
+			default:
+				panic(fmt.Sprintf("unsupported arch: %s", runtime.GOARCH))
+			}
 		default:
-			panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
+			panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
 		}
 	}()
 
diff --git a/android/config.go b/android/config.go
index 0a1ed98..696e772 100644
--- a/android/config.go
+++ b/android/config.go
@@ -814,11 +814,18 @@
 func (c *config) PrebuiltOS() string {
 	switch runtime.GOOS {
 	case "linux":
-		return "linux-x86"
+		switch runtime.GOARCH {
+		case "amd64":
+			return "linux-x86"
+		case "arm64":
+			return "linux-arm64"
+		default:
+			panic(fmt.Errorf("Unknown GOARCH %s", runtime.GOARCH))
+		}
 	case "darwin":
 		return "darwin-x86"
 	default:
-		panic("Unknown GOOS")
+		panic(fmt.Errorf("Unknown GOOS %s", runtime.GOOS))
 	}
 }
 
diff --git a/android/paths.go b/android/paths.go
index a944c48..9c0c9a2 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -209,6 +209,10 @@
 
 var _ ModuleErrorfContext = blueprint.ModuleContext(nil)
 
+type AddMissingDependenciesContext interface {
+	AddMissingDependencies([]string)
+}
+
 // reportPathError will register an error with the attached context. It
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
@@ -220,7 +224,9 @@
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
 func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
-	if mctx, ok := ctx.(ModuleErrorfContext); ok {
+	if mctx, ok := ctx.(AddMissingDependenciesContext); ok && ctx.Config().AllowMissingDependencies() {
+		mctx.AddMissingDependencies([]string{fmt.Sprintf(format, args...)})
+	} else if mctx, ok := ctx.(ModuleErrorfContext); ok {
 		mctx.ModuleErrorf(format, args...)
 	} else if ectx, ok := ctx.(errorfContext); ok {
 		ectx.Errorf(format, args...)
diff --git a/cc/cc.go b/cc/cc.go
index 868d18a..eae12b8 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -193,6 +193,9 @@
 	// Symlinks returns a list of symlinks that should be created for this module.
 	Symlinks               []string
 	APIListCoverageXMLPath android.ModuleOutPath
+	// FuzzSharedLibraries returns the shared library dependencies for this module.
+	// Expects that IsFuzzModule returns true.
+	FuzzSharedLibraries android.RuleBuilderInstalls
 }
 
 var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]()
@@ -2446,6 +2449,12 @@
 		info.APIListCoverageXMLPath = vi.GetAPIListCoverageXMLPath()
 	}
 
+	if !mod.PreventInstall() && fuzz.IsValid(ctx, mod.FuzzModuleStruct()) && mod.IsFuzzModule() {
+		info.FuzzSharedLibraries = mod.FuzzSharedLibraries()
+		fm := mod.FuzzPackagedModule()
+		fuzz.SetFuzzPackagedModuleInfo(ctx, &fm)
+	}
+
 	return info
 }
 
diff --git a/cc/fuzz.go b/cc/fuzz.go
index bd3d8e4..325354b 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -470,43 +470,37 @@
 	// multiple fuzzers that depend on the same shared library.
 	sharedLibraryInstalled := make(map[string]bool)
 
-	ctx.VisitAllModules(func(module android.Module) {
-		ccModule, ok := module.(LinkableInterface)
-		if !ok || ccModule.PreventInstall() {
+	ctx.VisitAllModuleProxies(func(module android.ModuleProxy) {
+		ccModule, ok := android.OtherModuleProvider(ctx, module, LinkableInfoProvider)
+		if !ok {
 			return
 		}
 		// Discard non-fuzz targets.
-		if ok := fuzz.IsValid(ctx, ccModule.FuzzModuleStruct()); !ok {
+		fuzzInfo, ok := android.OtherModuleProvider(ctx, module, fuzz.FuzzPackagedModuleInfoProvider)
+		if !ok {
 			return
 		}
 
 		sharedLibsInstallDirPrefix := "lib"
-		if ccModule.InVendor() {
+		if ccModule.InVendor {
 			sharedLibsInstallDirPrefix = "lib/vendor"
 		}
 
-		if !ccModule.IsFuzzModule() {
-			return
-		}
-
+		commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey)
+		isHost := commonInfo.Target.Os.Class == android.Host
 		hostOrTargetString := "target"
-		if ccModule.Target().HostCross {
+		if commonInfo.Target.HostCross {
 			hostOrTargetString = "host_cross"
-		} else if ccModule.Host() {
+		} else if isHost {
 			hostOrTargetString = "host"
 		}
 		if s.onlyIncludePresubmits == true {
 			hostOrTargetString = "presubmit-" + hostOrTargetString
 		}
 
-		fpm := fuzz.FuzzPackagedModule{}
-		if ok {
-			fpm = ccModule.FuzzPackagedModule()
-		}
-
 		intermediatePath := "fuzz"
 
-		archString := ccModule.Target().Arch.ArchType.String()
+		archString := commonInfo.Target.Arch.ArchType.String()
 		archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
 		archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
 
@@ -514,23 +508,24 @@
 		builder := android.NewRuleBuilder(pctx, ctx)
 
 		// Package the corpus, data, dict and config into a zipfile.
-		files = s.PackageArtifacts(ctx, module, fpm, archDir, builder)
+		files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder)
 
 		// Package shared libraries
-		files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
+		files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries, isHost, ccModule.InVendor, &s.FuzzPackager,
+			archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
 
 		// The executable.
-		files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")})
+		files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, module, "unstripped")})
 
 		if s.onlyIncludePresubmits == true {
-			if fpm.FuzzProperties.Fuzz_config == nil {
+			if fuzzInfo.FuzzConfig == nil {
 				return
 			}
-			if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) {
+			if !fuzzInfo.FuzzConfig.UseForPresubmit {
 				return
 			}
 		}
-		archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
+		archDirs[archOs], ok = s.BuildZipFile(ctx, module, &fuzzInfo, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
 		if !ok {
 			return
 		}
@@ -559,7 +554,8 @@
 
 // GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for
 // packaging.
-func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
+func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, isHost bool, inVendor bool, s *fuzz.FuzzPackager,
+	archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
 	var files []fuzz.FileToZip
 
 	fuzzDir := "fuzz"
@@ -577,7 +573,7 @@
 		// install it to the output directory. Setup the install destination here,
 		// which will be used by $(copy-many-files) in the Make backend.
 		installDestination := SharedLibraryInstallLocation(
-			install, module.Host(), module.InVendor(), fuzzDir, archString)
+			install, isHost, inVendor, fuzzDir, archString)
 		if (*sharedLibraryInstalled)[installDestination] {
 			continue
 		}
@@ -594,8 +590,8 @@
 		// dir. Symbolized DSO's are always installed to the device when fuzzing, but
 		// we want symbolization tools (like `stack`) to be able to find the symbols
 		// in $ANDROID_PRODUCT_OUT/symbols automagically.
-		if !module.Host() {
-			symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString)
+		if !isHost {
+			symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, inVendor, fuzzDir, archString)
 			symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
 			s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
 				library.String()+":"+symbolsInstallDestination)
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 83ccd89..f08378d 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -22,6 +22,7 @@
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -309,14 +310,14 @@
 	return false
 }
 
-func IsValidConfig(fuzzModule FuzzPackagedModule, moduleName string) bool {
-	var config = fuzzModule.FuzzProperties.Fuzz_config
+func IsValidConfig(fuzzModule *FuzzPackagedModuleInfo, moduleName string) bool {
+	var config = fuzzModule.FuzzConfig
 	if config != nil {
 		if !config.Vector.isValidVector() {
 			panic(fmt.Errorf("Invalid vector in fuzz config in %s", moduleName))
 		}
 
-		if !config.Service_privilege.isValidServicePrivilege() {
+		if !config.ServicePrivilege.isValidServicePrivilege() {
 			panic(fmt.Errorf("Invalid service_privilege in fuzz config in %s", moduleName))
 		}
 
@@ -324,15 +325,15 @@
 			panic(fmt.Errorf("Invalid users (user_data) in fuzz config in %s", moduleName))
 		}
 
-		if !config.Fuzzed_code_usage.isValidFuzzedCodeUsage() {
+		if !config.FuzzedCodeUsage.isValidFuzzedCodeUsage() {
 			panic(fmt.Errorf("Invalid fuzzed_code_usage in fuzz config in %s", moduleName))
 		}
 
-		if !config.Automatically_route_to.isValidAutomaticallyRouteTo() {
+		if !config.AutomaticallyRouteTo.isValidAutomaticallyRouteTo() {
 			panic(fmt.Errorf("Invalid automatically_route_to in fuzz config in %s", moduleName))
 		}
 
-		if !config.Use_platform_libs.isValidUsePlatformLibs() {
+		if !config.UsePlatformLibs.isValidUsePlatformLibs() {
 			panic(fmt.Errorf("Invalid use_platform_libs in fuzz config in %s", moduleName))
 		}
 	}
@@ -451,6 +452,62 @@
 	Data           android.Paths
 }
 
+type FuzzConfigInfo struct {
+	Vector Vector
+	// How privileged the service being fuzzed is.
+	ServicePrivilege ServicePrivilege
+	// Whether the service being fuzzed handles data from multiple users or only
+	// a single one.
+	Users UserData
+	// Specifies the use state of the code being fuzzed. This state factors into
+	// how an issue is handled.
+	FuzzedCodeUsage FuzzedCodeUsage
+	// Which team to route this to, if it should be routed automatically.
+	AutomaticallyRouteTo AutomaticallyRouteTo
+	// Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
+	UsePlatformLibs UsePlatformLibs
+	// Specify whether to enable continuous fuzzing on devices. Defaults to true.
+	FuzzOnHaikuDevice bool
+	// Specify whether to enable continuous fuzzing on host. Defaults to true.
+	FuzzOnHaikuHost bool
+	// Specifies whether fuzz target should check presubmitted code changes for crashes.
+	// Defaults to false.
+	UseForPresubmit bool
+}
+type FuzzPackagedModuleInfo struct {
+	FuzzConfig *FuzzConfigInfo
+	Dictionary android.Path
+	Corpus     android.Paths
+	Config     android.Path
+	Data       android.Paths
+}
+
+var FuzzPackagedModuleInfoProvider = blueprint.NewProvider[FuzzPackagedModuleInfo]()
+
+func SetFuzzPackagedModuleInfo(ctx android.ModuleContext, fm *FuzzPackagedModule) {
+	info := FuzzPackagedModuleInfo{
+		Dictionary: fm.Dictionary,
+		Config:     fm.Config,
+		Corpus:     fm.Corpus,
+		Data:       fm.Data,
+	}
+	if fm.FuzzProperties.Fuzz_config != nil {
+		info.FuzzConfig = &FuzzConfigInfo{
+			Vector:               fm.FuzzProperties.Fuzz_config.Vector,
+			ServicePrivilege:     fm.FuzzProperties.Fuzz_config.Service_privilege,
+			Users:                fm.FuzzProperties.Fuzz_config.Users,
+			FuzzedCodeUsage:      fm.FuzzProperties.Fuzz_config.Fuzzed_code_usage,
+			AutomaticallyRouteTo: fm.FuzzProperties.Fuzz_config.Automatically_route_to,
+			FuzzOnHaikuDevice:    BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_device, true),
+			FuzzOnHaikuHost:      BoolDefault(fm.FuzzProperties.Fuzz_config.Fuzz_on_haiku_host, true),
+			UsePlatformLibs:      fm.FuzzProperties.Fuzz_config.Use_platform_libs,
+			UseForPresubmit:      BoolDefault(fm.FuzzProperties.Fuzz_config.Use_for_presubmit, false),
+		}
+	}
+
+	android.SetProvider(ctx, FuzzPackagedModuleInfoProvider, info)
+}
+
 func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
 	framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")
 
@@ -509,7 +566,9 @@
 	return true
 }
 
-func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
+// TODO(b/397766191): Change the signature to take ModuleProxy
+// Please only access the module's internal data through providers.
+func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip {
 	// Package the corpora into a zipfile.
 	var files []FileToZip
 	if fuzzModule.Corpus != nil {
@@ -548,7 +607,9 @@
 	return files
 }
 
-func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule FuzzPackagedModule, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) {
+// TODO(b/397766191): Change the signature to take ModuleProxy
+// Please only access the module's internal data through providers.
+func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) {
 	fuzzZip := archDir.Join(ctx, module.Name()+".zip")
 
 	command := builder.Command().BuiltTool("soong_zip").
@@ -570,10 +631,10 @@
 	builder.Build("create-"+fuzzZip.String(),
 		"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
 
-	if config := fuzzModule.FuzzProperties.Fuzz_config; config != nil {
-		if strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_host, true) {
+	if config := fuzzModule.FuzzConfig; config != nil {
+		if strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuHost {
 			return archDirs[archOs], false
-		} else if !strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_device, true) {
+		} else if !strings.Contains(hostOrTargetString, "host") && !config.FuzzOnHaikuDevice {
 			return archDirs[archOs], false
 		}
 	}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 313d8c7..2287043 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -675,6 +675,139 @@
 			installs: artBootImageHostInstalls,
 		},
 	)
+
+	d.buildBootZip(ctx)
+}
+
+// Build the boot.zip which contains the boot jars and their compilation output
+// We can do this only if preopt is enabled and if the product uses libart config (which sets the
+// default properties for preopting).
+// Origionally, this was only for ART Cloud.
+func (d *dexpreoptBootJars) buildBootZip(ctx android.ModuleContext) {
+	image := d.defaultBootImage
+	if image == nil || SkipDexpreoptBootJars(ctx) {
+		return
+	}
+	global := dexpreopt.GetGlobalConfig(ctx)
+	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage {
+		return
+	}
+
+	bootclasspathDexFiles, bootclassPathLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
+	if len(bootclasspathDexFiles) == 0 {
+		return
+	}
+
+	systemServerDexjarsDir := android.PathForOutput(ctx, dexpreopt.SystemServerDexjarsDir)
+
+	bootZipMetadataTmp := android.PathForModuleOut(ctx, "boot_zip", "METADATA.txt.tmp")
+	bootZipMetadata := android.PathForModuleOut(ctx, "boot_zip", "METADATA.txt")
+	newlineFile := android.PathForModuleOut(ctx, "boot_zip", "newline.txt")
+	android.WriteFileRule(ctx, newlineFile, "")
+
+	dexPreoptRootDir := filepath.Dir(filepath.Dir(bootclasspathDexFiles[0].String()))
+
+	var sb strings.Builder
+	sb.WriteString("bootclasspath = ")
+	for i, bootclasspathJar := range bootclasspathDexFiles {
+		if i > 0 {
+			sb.WriteString(":")
+		}
+		rel, err := filepath.Rel(dexPreoptRootDir, bootclasspathJar.String())
+		if err != nil {
+			ctx.ModuleErrorf("All dexpreopt jars should be under the same rootdir %q, but %q wasn't.", dexPreoptRootDir, bootclasspathJar)
+		} else {
+			sb.WriteString(rel)
+		}
+	}
+	sb.WriteString("\nbootclasspath-locations = ")
+	for i, bootclasspathLocation := range bootclassPathLocations {
+		if i > 0 {
+			sb.WriteString(":")
+		}
+		sb.WriteString(bootclasspathLocation)
+	}
+	sb.WriteString("\nboot-image = ")
+
+	// Infix can be 'art' (ART image for testing), 'boot' (primary), or 'mainline' (mainline
+	// extension). Soong creates a set of variables for Make, one or each boot image. The only
+	// reason why the ART image is exposed to Make is testing (art gtests) and benchmarking (art
+	// golem benchmarks). Install rules that use those variables are in dex_preopt_libart.mk. Here
+	// for dexpreopt purposes the infix is always 'boot' or 'mainline'.
+	dexpreoptInfix := "boot"
+	if global.PreoptWithUpdatableBcp {
+		dexpreoptInfix = "mainline"
+	}
+
+	var dexPreoptImageZipBoot android.Path
+	var dexPreoptImageZipArt android.Path
+	var dexPreoptImageZipMainline android.Path
+	for _, current := range append(d.otherImages, image) {
+		if current.name == dexpreoptInfix {
+			_, imageLocationsOnDevice := current.getAnyAndroidVariant().imageLocations()
+			for i, location := range imageLocationsOnDevice {
+				imageLocationsOnDevice[i] = strings.TrimPrefix(location, "/")
+			}
+			sb.WriteString(strings.Join(imageLocationsOnDevice, ":"))
+		}
+		switch current.name {
+		case "boot":
+			dexPreoptImageZipBoot = current.zip
+		case "art":
+			dexPreoptImageZipArt = current.zip
+		case "mainline":
+			dexPreoptImageZipMainline = current.zip
+		}
+	}
+	sb.WriteString("\nextra-args = ")
+	android.WriteFileRuleVerbatim(ctx, bootZipMetadataTmp, sb.String())
+	ctx.Build(pctx, android.BuildParams{
+		Rule: android.Cat,
+		Inputs: []android.Path{
+			bootZipMetadataTmp,
+			globalSoong.UffdGcFlag,
+			newlineFile,
+		},
+		Output: bootZipMetadata,
+	})
+
+	bootZipFirstPart := android.PathForModuleOut(ctx, "boot_zip", "boot_first_part.zip")
+	bootZip := android.PathForModuleOut(ctx, "boot_zip", "boot.zip")
+	builder := android.NewRuleBuilder(pctx, ctx)
+	cmd := builder.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", bootZipFirstPart).
+		FlagWithArg("-C ", filepath.Dir(filepath.Dir(bootclasspathDexFiles[0].String())))
+	for _, bootclasspathJar := range bootclasspathDexFiles {
+		cmd.FlagWithInput("-f ", bootclasspathJar)
+	}
+	for i := range global.SystemServerJars.Len() {
+		// Use "/system" path for JARs with "platform:" prefix. These JARs counterintuitively use
+		// "platform" prefix but they will be actually installed to /system partition.
+		// For the remaining system server JARs use the partition signified by the prefix.
+		// For example, prefix "system_ext:" will use "/system_ext" path.
+		dir := global.SystemServerJars.Apex(i)
+		if dir == "platform" {
+			dir = "system"
+		}
+		jar := global.SystemServerJars.Jar(i) + ".jar"
+		cmd.FlagWithArg("-e ", dir+"/framework/"+jar)
+		cmd.FlagWithInput("-f ", systemServerDexjarsDir.Join(ctx, jar))
+	}
+	cmd.Flag("-j")
+	cmd.FlagWithInput("-f ", bootZipMetadata)
+
+	builder.Command().BuiltTool("merge_zips").
+		Output(bootZip).
+		Input(bootZipFirstPart).
+		Input(dexPreoptImageZipBoot).
+		Input(dexPreoptImageZipArt).
+		Input(dexPreoptImageZipMainline)
+
+	builder.Build("boot_zip", "build boot.zip")
+
+	ctx.DistForGoal("droidcore", bootZipMetadata)
+	ctx.DistForGoal("droidcore", bootZip)
 }
 
 // GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
diff --git a/java/fuzz.go b/java/fuzz.go
index 5973957..0e239f0 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -132,6 +132,8 @@
 	}
 
 	j.Test.GenerateAndroidBuildActions(ctx)
+
+	fuzz.SetFuzzPackagedModuleInfo(ctx, &j.fuzzPackagedModule)
 }
 
 type javaFuzzPackager struct {
@@ -153,6 +155,10 @@
 		if !ok {
 			return
 		}
+		fuzzInfo, ok := android.OtherModuleProvider(ctx, module, fuzz.FuzzPackagedModuleInfoProvider)
+		if !ok {
+			return
+		}
 
 		hostOrTargetString := "target"
 		if javaFuzzModule.Target().HostCross {
@@ -179,7 +185,7 @@
 		builder := android.NewRuleBuilder(pctx, ctx)
 
 		// Package the artifacts (data, corpus, config and dictionary) into a zipfile.
-		files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
+		files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder)
 
 		// Add .jar
 		if !javaFuzzModule.Host() {
@@ -193,7 +199,7 @@
 			files = append(files, fuzz.FileToZip{SourceFilePath: fPath})
 		}
 
-		archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaFuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
+		archDirs[archOs], ok = s.BuildZipFile(ctx, module, &fuzzInfo, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
 		if !ok {
 			return
 		}
diff --git a/scripts/microfactory.bash b/scripts/microfactory.bash
index ce4a0e4..49988fa 100644
--- a/scripts/microfactory.bash
+++ b/scripts/microfactory.bash
@@ -23,7 +23,14 @@
 # Ensure GOROOT is set to the in-tree version.
 case $(uname) in
     Linux)
-        export GOROOT="${TOP}/prebuilts/go/linux-x86/"
+        case $(uname -m) in
+            x86_64)
+                export GOROOT="${TOP}/prebuilts/go/linux-x86/"
+                ;;
+            aarch64)
+                export GOROOT="${TOP}/prebuilts/go/linux-arm64/"
+                ;;
+        esac
         ;;
     Darwin)
         export GOROOT="${TOP}/prebuilts/go/darwin-x86/"
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index 640a82d..cd49ec8 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -70,8 +70,8 @@
 	}
 }
 
-// The Android.mk files in these directories are for NDK build system.
-var external_ndk_androidmks []string = []string{
+var external_androidmks []string = []string{
+	// The Android.mk files in these directories are for NDK build system.
 	"external/fmtlib/",
 	"external/google-breakpad/",
 	"external/googletest/",
@@ -83,6 +83,9 @@
 	"external/vulkan-validation-layers/",
 	"external/walt/",
 	"external/webp/",
+	// These directories hold the published Android SDK, used in Unbundled Gradle builds.
+	"prebuilts/fullsdk-darwin",
+	"prebuilts/fullsdk-linux",
 }
 
 var art_androidmks = []string{
@@ -90,8 +93,8 @@
 }
 
 func ignoreSomeAndroidMks(androidMks []string) (filtered []string) {
-	ignore_androidmks := make([]string, 0, len(external_ndk_androidmks)+len(art_androidmks))
-	ignore_androidmks = append(ignore_androidmks, external_ndk_androidmks...)
+	ignore_androidmks := make([]string, 0, len(external_androidmks)+len(art_androidmks))
+	ignore_androidmks = append(ignore_androidmks, external_androidmks...)
 	ignore_androidmks = append(ignore_androidmks, art_androidmks...)
 
 	shouldKeep := func(androidmk string) bool {
diff --git a/ui/build/config.go b/ui/build/config.go
index a4f778d..94b0781 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -1117,11 +1117,18 @@
 func (c *configImpl) PrebuiltOS() string {
 	switch runtime.GOOS {
 	case "linux":
-		return "linux-x86"
+		switch runtime.GOARCH {
+		case "amd64":
+			return "linux-x86"
+		case "arm64":
+			return "linux-arm64"
+		default:
+			panic(fmt.Errorf("Unknown GOARCH %s", runtime.GOARCH))
+		}
 	case "darwin":
 		return "darwin-x86"
 	default:
-		panic("Unknown GOOS")
+		panic(fmt.Errorf("Unknown GOOS %s", runtime.GOOS))
 	}
 }
 
@@ -1711,13 +1718,7 @@
 }
 
 func (c *configImpl) HostPrebuiltTag() string {
-	if runtime.GOOS == "linux" {
-		return "linux-x86"
-	} else if runtime.GOOS == "darwin" {
-		return "darwin-x86"
-	} else {
-		panic("Unsupported OS")
-	}
+	return c.PrebuiltOS()
 }
 
 func (c *configImpl) KatiBin() string {
diff --git a/ui/build/path.go b/ui/build/path.go
index cc1d7e9..b92d799 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -20,7 +20,6 @@
 	"os"
 	"os/exec"
 	"path/filepath"
-	"runtime"
 	"strings"
 
 	"github.com/google/blueprint/microfactory"
@@ -122,7 +121,7 @@
 	myPath, _ = filepath.Abs(myPath)
 
 	// Set up the checked-in prebuilts path directory for the current host OS.
-	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
+	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + config.PrebuiltOS())
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
 	// Set $PATH to be the directories containing the host tool symlinks, and
@@ -258,7 +257,7 @@
 
 	// We put some prebuilts in $PATH, since it's infeasible to add dependencies
 	// for all of them.
-	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
+	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + config.PrebuiltOS())
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
 	// Replace the $PATH variable with the path_interposer symlinks, and