Merge "Mark "Ravenwood-tests" and "robo-test" modules as being TestOnly and top-level-tests for code coverage reporting." into main
diff --git a/android/neverallow.go b/android/neverallow.go
index a7bfd2d..5c90501 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -252,6 +252,7 @@
 			NotModuleType("prebuilt_system").
 			NotModuleType("prebuilt_first_stage_ramdisk").
 			NotModuleType("prebuilt_res").
+			NotModuleType("prebuilt_any").
 			Because("install_in_root is only for init_first_stage or librecovery_ui_ext."),
 	}
 }
@@ -309,6 +310,10 @@
 		"trusty_tee_package_goog",
 		"trusty_tee_package",
 		// Trusty vm target names
+		"trusty_desktop_vm_arm64.bin",
+		"trusty_desktop_vm_x86_64.elf",
+		"trusty_desktop_test_vm_arm64.bin",
+		"trusty_desktop_test_vm_x86_64.elf",
 		"trusty_test_vm_arm64.bin",
 		"trusty_test_vm_x86_64.elf",
 		"trusty_test_vm_os_arm64.bin",
@@ -364,6 +369,7 @@
 func createPrebuiltEtcBpDefineRule() Rule {
 	return NeverAllow().
 		ModuleType(
+			"prebuilt_any",
 			"prebuilt_usr_srec",
 			"prebuilt_priv_app",
 			"prebuilt_rfs",
@@ -381,6 +387,7 @@
 			"prebuilt_first_stage_ramdisk",
 			"prebuilt_radio",
 			"prebuilt_gpu",
+			"prebuilt_vendor_overlay",
 		).
 		DefinedInBpFile().
 		Because("module type not allowed to be defined in bp file")
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index ddc86c2..d2f88ef 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -28,7 +28,7 @@
 		"-fno-omit-frame-pointer",
 
 		"-U_FORTIFY_SOURCE",
-		"-D_FORTIFY_SOURCE=2",
+		"-D_FORTIFY_SOURCE=3",
 		"-fstack-protector-strong",
 
 		// From x86_64_device
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index c070050..c3f25aa 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -29,7 +29,7 @@
 		"-fno-omit-frame-pointer",
 
 		"-U_FORTIFY_SOURCE",
-		"-D_FORTIFY_SOURCE=2",
+		"-D_FORTIFY_SOURCE=3",
 		"-fstack-protector",
 
 		"--gcc-toolchain=${LinuxGccRoot}",
diff --git a/cc/sanitize.go b/cc/sanitize.go
index db99a53..b704ef4 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -79,7 +79,7 @@
 
 	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
 		"-fno-sanitize-recover=integer,undefined"}
-	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
+	memtagStackCommonFlags = []string{"-Xclang -target-feature -Xclang +mte"}
 	memtagStackLlvmFlags   = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
 
 	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
diff --git a/ci_tests/ci_test_package_zip.go b/ci_tests/ci_test_package_zip.go
index f8c4578..95249aa 100644
--- a/ci_tests/ci_test_package_zip.go
+++ b/ci_tests/ci_test_package_zip.go
@@ -140,6 +140,9 @@
 }
 
 func (p *testPackageZip) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Never install this test package, it's for disting only
+	p.SkipInstall()
+
 	if !android.InList(ctx.ModuleName(), moduleNamesAllowed) {
 		ctx.ModuleErrorf("%s is not allowed to use module type test_package")
 	}
@@ -167,6 +170,9 @@
 	builder.Command().Text("mkdir").Flag("-p").Output(stagingDir)
 	builder.Temporary(stagingDir)
 	ctx.WalkDeps(func(child, parent android.Module) bool {
+		if !child.Enabled(ctx) {
+			return false
+		}
 		if android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == testPackageZipDepTag {
 			// handle direct deps
 			extendBuilderCommand(ctx, child, builder, stagingDir, productOut, arch, secondArch)
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index d0da728..3b0c032 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -81,6 +81,7 @@
 	ctx.RegisterModuleType("prebuilt_wlc_upt", PrebuiltWlcUptFactory)
 	ctx.RegisterModuleType("prebuilt_odm", PrebuiltOdmFactory)
 	ctx.RegisterModuleType("prebuilt_vendor_dlkm", PrebuiltVendorDlkmFactory)
+	ctx.RegisterModuleType("prebuilt_vendor_overlay", PrebuiltVendorOverlayFactory)
 	ctx.RegisterModuleType("prebuilt_bt_firmware", PrebuiltBtFirmwareFactory)
 	ctx.RegisterModuleType("prebuilt_tvservice", PrebuiltTvServiceFactory)
 	ctx.RegisterModuleType("prebuilt_optee", PrebuiltOpteeFactory)
@@ -89,6 +90,7 @@
 	ctx.RegisterModuleType("prebuilt_sbin", PrebuiltSbinFactory)
 	ctx.RegisterModuleType("prebuilt_system", PrebuiltSystemFactory)
 	ctx.RegisterModuleType("prebuilt_first_stage_ramdisk", PrebuiltFirstStageRamdiskFactory)
+	ctx.RegisterModuleType("prebuilt_any", PrebuiltAnyFactory)
 
 	ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
 
@@ -115,12 +117,6 @@
 	// set. May use globs in filenames.
 	Srcs proptools.Configurable[[]string] `android:"path,arch_variant"`
 
-	// Destination files of this prebuilt. Requires srcs to be used and causes srcs not to implicitly
-	// set filename_from_src. This can be used to install each source file to a different directory
-	// and/or change filenames when files are installed. Must be exactly one entry per source file,
-	// which means care must be taken if srcs has globs.
-	Dsts proptools.Configurable[[]string] `android:"path,arch_variant"`
-
 	// Optional name for the installed file. If unspecified, name of the module is used as the file
 	// name. Only available when using a single source (src).
 	Filename *string `android:"arch_variant"`
@@ -159,6 +155,20 @@
 	Oem_specific *bool `android:"arch_variant"`
 }
 
+// Dsts is useful in that it allows prebuilt_* modules to easily map the source files to the
+// install path within the partition. Dsts values are allowed to contain filepath separator
+// so that the source files can be installed in subdirectories within the partition.
+// However, this functionality should not be supported for prebuilt_root module type, as it
+// allows the module to install to any arbitrary location. Thus, this property is defined in
+// a separate struct so that it's not available to be set in prebuilt_root module type.
+type PrebuiltDstsProperties struct {
+	// Destination files of this prebuilt. Requires srcs to be used and causes srcs not to implicitly
+	// set filename_from_src. This can be used to install each source file to a different directory
+	// and/or change filenames when files are installed. Must be exactly one entry per source file,
+	// which means care must be taken if srcs has globs.
+	Dsts proptools.Configurable[[]string] `android:"path,arch_variant"`
+}
+
 type prebuiltSubdirProperties struct {
 	// Optional subdirectory under which this file is installed into, cannot be specified with
 	// relative_install_path, prefer relative_install_path.
@@ -194,6 +204,8 @@
 
 	properties PrebuiltEtcProperties
 
+	dstsProperties PrebuiltDstsProperties
+
 	// rootProperties is used to return the value of the InstallInRoot() method. Currently, only
 	// prebuilt_avb and prebuilt_root modules use this.
 	rootProperties prebuiltRootProperties
@@ -384,7 +396,7 @@
 	if srcProperty.IsPresent() && len(srcsProperty) > 0 {
 		ctx.PropertyErrorf("src", "src is set. Cannot set srcs")
 	}
-	dstsProperty := p.properties.Dsts.GetOrDefault(ctx, nil)
+	dstsProperty := p.dstsProperties.Dsts.GetOrDefault(ctx, nil)
 	if len(dstsProperty) > 0 && len(srcsProperty) == 0 {
 		ctx.PropertyErrorf("dsts", "dsts is set. Must use srcs")
 	}
@@ -612,6 +624,7 @@
 	p.AddProperties(&p.properties)
 	p.AddProperties(&p.subdirProperties)
 	p.AddProperties(&p.rootProperties)
+	p.AddProperties(&p.dstsProperties)
 }
 
 func InitPrebuiltRootModule(p *PrebuiltEtc) {
@@ -623,6 +636,7 @@
 func InitPrebuiltAvbModule(p *PrebuiltEtc) {
 	p.installDirBase = "avb"
 	p.AddProperties(&p.properties)
+	p.AddProperties(&p.dstsProperties)
 	p.rootProperties.Install_in_root = proptools.BoolPtr(true)
 }
 
@@ -666,6 +680,20 @@
 	return module
 }
 
+// prebuilt_any is a special module where the module can define the subdirectory that the files
+// are installed to. This is only used for converting the PRODUCT_COPY_FILES entries to Soong
+// modules, and should never be defined in the bp files. If none of the existing prebuilt_*
+// modules allow installing the file at the desired location, introduce a new prebuilt_* module
+// type instead.
+func PrebuiltAnyFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, ".")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_etc_host is for a host prebuilt artifact that is installed in
 // <partition>/etc/<sub_dir> directory.
 func PrebuiltEtcCaCertsFactory() android.Module {
@@ -1052,6 +1080,16 @@
 	return module
 }
 
+// prebuilt_vendor_overlay is for a prebuilt artifact in <partition>/vendor_overlay directory.
+func PrebuiltVendorOverlayFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "vendor_overlay")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_sbin installs files in <partition>/sbin directory.
 func PrebuiltSbinFactory() android.Module {
 	module := &PrebuiltEtc{}
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 45a8620..bd887c7 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -780,6 +780,16 @@
 		builder.Command().Textf("echo boot_images=boot.img >> %s", miscInfo)
 	}
 
+	if a.partitionProps.Super_partition_name != nil {
+		superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag)
+		if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok {
+			// cat dynamic_partition_info.txt
+			builder.Command().Text("cat").Input(info.DynamicPartitionsInfo).Textf(" >> %s", miscInfo)
+		} else {
+			ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name())
+		}
+	}
+
 	builder.Build("misc_info", "Building misc_info")
 
 	return miscInfo
diff --git a/filesystem/super_image.go b/filesystem/super_image.go
index 8e2b532..cd7df02 100644
--- a/filesystem/super_image.go
+++ b/filesystem/super_image.go
@@ -325,39 +325,43 @@
 		sb.WriteRune('\n')
 	}
 
-	addStr("build_super_partition", "true")
-	if proptools.Bool(s.properties.Create_super_empty) {
-		addStr("build_super_empty_partition", "true")
-	}
 	addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
 	if proptools.Bool(s.properties.Retrofit) {
 		addStr("dynamic_partition_retrofit", "true")
 	}
 	addStr("lpmake", "lpmake")
+	addStr("build_super_partition", "true")
+	if proptools.Bool(s.properties.Create_super_empty) {
+		addStr("build_super_empty_partition", "true")
+	}
 	addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
 	if len(s.properties.Block_devices) > 0 {
 		addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
 	}
-	if proptools.Bool(s.properties.Super_image_in_update_package) {
-		addStr("super_image_in_update_package", "true")
-	}
-	addStr("super_partition_size", strconv.Itoa(proptools.Int(s.properties.Size)))
 	// TODO: In make, there's more complicated logic than just this surrounding super_*_device_size
 	addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
 	var groups, partitionList []string
 	for _, groupInfo := range s.properties.Partition_groups {
 		groups = append(groups, groupInfo.Name)
 		partitionList = append(partitionList, groupInfo.PartitionList...)
-		addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
-		addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
 	}
+	addStr("dynamic_partition_list", strings.Join(android.SortedUniqueStrings(partitionList), " "))
+	addStr("super_partition_groups", strings.Join(groups, " "))
 	initialPartitionListLen := len(partitionList)
 	partitionList = android.SortedUniqueStrings(partitionList)
 	if len(partitionList) != initialPartitionListLen {
 		ctx.ModuleErrorf("Duplicate partitions found in the partition_groups property")
 	}
-	addStr("super_partition_groups", strings.Join(groups, " "))
-	addStr("dynamic_partition_list", strings.Join(partitionList, " "))
+	// Add Partition group info after adding `super_partition_groups` and `dynamic_partition_list`
+	for _, groupInfo := range s.properties.Partition_groups {
+		addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
+		addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
+	}
+
+	if proptools.Bool(s.properties.Super_image_in_update_package) {
+		addStr("super_image_in_update_package", "true")
+	}
+	addStr("super_partition_size", strconv.Itoa(proptools.Int(s.properties.Size)))
 
 	if proptools.Bool(s.properties.Virtual_ab.Enable) {
 		addStr("virtual_ab", "true")
@@ -372,12 +376,12 @@
 			}
 			addStr("virtual_ab_compression_method", *s.properties.Virtual_ab.Compression_method)
 		}
-		if s.properties.Virtual_ab.Compression_factor != nil {
-			addStr("virtual_ab_compression_factor", strconv.FormatInt(*s.properties.Virtual_ab.Compression_factor, 10))
-		}
 		if s.properties.Virtual_ab.Cow_version != nil {
 			addStr("virtual_ab_cow_version", strconv.FormatInt(*s.properties.Virtual_ab.Cow_version, 10))
 		}
+		if s.properties.Virtual_ab.Compression_factor != nil {
+			addStr("virtual_ab_compression_factor", strconv.FormatInt(*s.properties.Virtual_ab.Compression_factor, 10))
+		}
 
 	} else {
 		if s.properties.Virtual_ab.Retrofit != nil {
@@ -401,6 +405,6 @@
 	var contents strings.Builder
 	s.dumpDynamicPartitionInfo(ctx, &contents)
 	dynamicPartitionsInfo := android.PathForModuleOut(ctx, "dynamic_partitions_info.txt")
-	android.WriteFileRule(ctx, dynamicPartitionsInfo, contents.String())
+	android.WriteFileRuleVerbatim(ctx, dynamicPartitionsInfo, contents.String())
 	return dynamicPartitionsInfo
 }
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
index 418e48b..81236a0 100644
--- a/fsgen/filesystem_creator_test.go
+++ b/fsgen/filesystem_creator_test.go
@@ -287,6 +287,8 @@
 				"some/non/existing/file.txt:system/etc/file.txt",
 				"device/sample/etc/apns-full-conf.xml:product/etc/apns-conf.xml:google",
 				"device/sample/etc/apns-full-conf.xml:product/etc/apns-conf-2.xml",
+				"device/sample/etc/apns-full-conf.xml:system/foo/file.txt",
+				"device/sample/etc/apns-full-conf.xml:system/foo/apns-full-conf.xml",
 			}
 			config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
 				map[string]android.PartitionQualifiedVariablesType{
@@ -364,15 +366,25 @@
 	eval := generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
 	android.AssertBoolEquals(
 		t,
-		"module expected to set correct srcs and dsts properties",
+		"module expected to set correct srcs property",
 		true,
 		checkModuleProp(generatedModule0, func(actual interface{}) bool {
 			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
 				srcs := p.Srcs.GetOrDefault(eval, nil)
-				dsts := p.Dsts.GetOrDefault(eval, nil)
 				return len(srcs) == 1 &&
-					srcs[0] == "apns-full-conf.xml" &&
-					len(dsts) == 1 &&
+					srcs[0] == "apns-full-conf.xml"
+			}
+			return false
+		}),
+	)
+	android.AssertBoolEquals(
+		t,
+		"module expected to set correct dsts property",
+		true,
+		checkModuleProp(generatedModule0, func(actual interface{}) bool {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				return len(dsts) == 1 &&
 					dsts[0] == "apns-conf.xml"
 			}
 			return false
@@ -383,15 +395,25 @@
 	eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
 	android.AssertBoolEquals(
 		t,
-		"module expected to set correct srcs and dsts properties",
+		"module expected to set correct srcs property",
 		true,
 		checkModuleProp(generatedModule1, func(actual interface{}) bool {
 			if p, ok := actual.(*etc.PrebuiltEtcProperties); ok {
 				srcs := p.Srcs.GetOrDefault(eval, nil)
-				dsts := p.Dsts.GetOrDefault(eval, nil)
 				return len(srcs) == 1 &&
-					srcs[0] == "apns-full-conf.xml" &&
-					len(dsts) == 1 &&
+					srcs[0] == "apns-full-conf.xml"
+			}
+			return false
+		}),
+	)
+	android.AssertBoolEquals(
+		t,
+		"module expected to set correct dsts property",
+		true,
+		checkModuleProp(generatedModule1, func(actual interface{}) bool {
+			if p, ok := actual.(*etc.PrebuiltDstsProperties); ok {
+				dsts := p.Dsts.GetOrDefault(eval, nil)
+				return len(dsts) == 1 &&
 					dsts[0] == "apns-conf-2.xml"
 			}
 			return false
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index d34ae77..4f3d2a7 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -187,6 +187,10 @@
 			(*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config())
 		}
 
+		if len(ctx.Config().DeviceManifestFiles()) > 0 {
+			(*fsGenState.fsDeps["vendor"])["vendor_manifest.xml"] = defaultDepCandidateProps(ctx.Config())
+		}
+
 		// Add common resources `prebuilt_res` module as dep of recovery partition
 		(*fsGenState.fsDeps["recovery"])[fmt.Sprintf("recovery-resources-common-%s", getDpi(ctx))] = defaultDepCandidateProps(ctx.Config())
 		(*fsGenState.fsDeps["recovery"])[getRecoveryFontModuleName(ctx)] = defaultDepCandidateProps(ctx.Config())
diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
index 2025c91..df36197 100644
--- a/fsgen/prebuilt_etc_modules_gen.go
+++ b/fsgen/prebuilt_etc_modules_gen.go
@@ -164,7 +164,6 @@
 	Ramdisk             *bool
 
 	Srcs []string
-	Dsts []string
 
 	No_full_install *bool
 
@@ -227,6 +226,7 @@
 		"usr/idc":             etc.PrebuiltUserIdcFactory,
 		"vendor":              etc.PrebuiltVendorFactory,
 		"vendor_dlkm":         etc.PrebuiltVendorDlkmFactory,
+		"vendor_overlay":      etc.PrebuiltVendorOverlayFactory,
 		"wallpaper":           etc.PrebuiltWallpaperFactory,
 		"wlc_upt":             etc.PrebuiltWlcUptFactory,
 	}
@@ -301,6 +301,7 @@
 			etcInstallPathKey = etcInstallPath
 		}
 	}
+	moduleFactory := etcInstallPathToFactoryList[etcInstallPathKey]
 	relDestDirFromInstallDirBase, _ := filepath.Rel(etcInstallPathKey, destDir)
 
 	for fileIndex := range maxLen {
@@ -350,15 +351,23 @@
 				})
 			}
 		} else {
-			modulePropsPtr.Srcs = srcBaseFiles
-			dsts := []string{}
-			for _, installBaseFile := range installBaseFiles {
-				dsts = append(dsts, filepath.Join(relDestDirFromInstallDirBase, installBaseFile))
+			// If dsts property has to be set and the selected module type is prebuilt_root,
+			// use prebuilt_any instead.
+			if etcInstallPathKey == "" {
+				moduleFactory = etc.PrebuiltAnyFactory
 			}
-			modulePropsPtr.Dsts = dsts
+			modulePropsPtr.Srcs = srcBaseFiles
+			dsts := proptools.NewConfigurable[[]string](nil, nil)
+			for _, installBaseFile := range installBaseFiles {
+				dsts.AppendSimpleValue([]string{filepath.Join(relDestDirFromInstallDirBase, installBaseFile)})
+			}
+
+			propsList = append(propsList, &etc.PrebuiltDstsProperties{
+				Dsts: dsts,
+			})
 		}
 
-		ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...)
+		ctx.CreateModuleInDirectory(moduleFactory, srcDir, propsList...)
 		moduleNames = append(moduleNames, moduleName)
 	}
 
diff --git a/java/app_import.go b/java/app_import.go
index b9e91cd..c0e8171 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -177,7 +177,7 @@
 	Prebuilt_info *string `android:"path"`
 
 	// Path of extracted apk which is extracted from prebuilt apk. Use this extracted to import.
-	Extract_apk *string
+	Extract_apk proptools.Configurable[string]
 
 	// Compress the output APK using gzip. Defaults to false.
 	Compress_apk proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"`
@@ -307,7 +307,7 @@
 
 func (a *AndroidAppImport) extractSubApk(
 	ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) {
-	extractApkPath := *a.properties.Extract_apk
+	extractApkPath := a.properties.Extract_apk.GetOrDefault(ctx, "")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   extractApkRule,
 		Input:  inputPath,
@@ -405,7 +405,7 @@
 	// TODO: LOCAL_PACKAGE_SPLITS
 
 	srcApk := a.prebuilt.SingleSourcePath(ctx)
-	if a.properties.Extract_apk != nil {
+	if a.properties.Extract_apk.GetOrDefault(ctx, "") != "" {
 		extract_apk := android.PathForModuleOut(ctx, "extract-apk", ctx.ModuleName()+".apk")
 		a.extractSubApk(ctx, srcApk, extract_apk)
 		srcApk = extract_apk
diff --git a/java/rro.go b/java/rro.go
index 42d42b8..4ae8d7f 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -99,15 +99,6 @@
 	Overrides []string
 }
 
-// RuntimeResourceOverlayModule interface is used by the apex package to gather information from
-// a RuntimeResourceOverlay module.
-type RuntimeResourceOverlayModule interface {
-	android.Module
-	OutputFile() android.Path
-	Certificate() Certificate
-	Theme() string
-}
-
 // RRO's partition logic is different from the partition logic of other modules defined in soong/android/paths.go
 // The default partition for RRO is "/product" and not "/system"
 func rroPartition(ctx android.ModuleContext) string {
@@ -217,11 +208,13 @@
 	})
 
 	android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{
-		OutputFile:  r.OutputFile(),
+		OutputFile:  r.outputFile,
 		Certificate: r.Certificate(),
 		Theme:       r.Theme(),
 	})
 
+	ctx.SetOutputFiles([]android.Path{r.outputFile}, "")
+
 	buildComplianceMetadata(ctx)
 }
 
@@ -252,10 +245,6 @@
 	return r.certificate
 }
 
-func (r *RuntimeResourceOverlay) OutputFile() android.Path {
-	return r.outputFile
-}
-
 func (r *RuntimeResourceOverlay) Theme() string {
 	return String(r.properties.Theme)
 }
diff --git a/java/rro_test.go b/java/rro_test.go
index 0ccc8e7..3e4fed5 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -358,3 +358,21 @@
 		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
 	)
 }
+
+func TestCanBeDataOfTest(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+		runtime_resource_overlay {
+			name: "foo",
+			sdk_version: "current",
+		}
+		android_test {
+			name: "bar",
+			data: [
+				":foo",
+			],
+		}
+	`)
+	// Just test that this doesn't get errors
+}
diff --git a/python/binary.go b/python/binary.go
index af7d30f..f894299 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -125,6 +125,7 @@
 func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
 	embeddedLauncher := p.isEmbeddedLauncherEnabled()
 	depsSrcsZips := p.collectPathsFromTransitiveDeps(ctx, embeddedLauncher)
+	bundleSharedLibs := p.collectSharedLibDeps(ctx)
 	main := ""
 	if p.autorun() {
 		main = p.getPyMainFile(ctx, p.srcsPathMappings)
@@ -149,6 +150,11 @@
 		srcsZips = append(srcsZips, p.srcsZip)
 	}
 	srcsZips = append(srcsZips, depsSrcsZips...)
+	if ctx.Host() && len(bundleSharedLibs) > 0 {
+		// only bundle shared libs for host binaries
+		sharedLibZip := p.zipSharedLibs(ctx, bundleSharedLibs)
+		srcsZips = append(srcsZips, sharedLibZip)
+	}
 	p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath,
 		"python3", main, p.getStem(ctx), srcsZips)
 
diff --git a/python/python.go b/python/python.go
index 10c11ad..e2786b8 100644
--- a/python/python.go
+++ b/python/python.go
@@ -20,11 +20,13 @@
 	"fmt"
 	"path/filepath"
 	"regexp"
+	"sort"
 	"strings"
 
 	"android/soong/cc"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/depset"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -36,6 +38,7 @@
 	SrcsZip            android.Path
 	PrecompiledSrcsZip android.Path
 	PkgPath            string
+	BundleSharedLibs   android.Paths
 }
 
 var PythonLibraryInfoProvider = blueprint.NewProvider[PythonLibraryInfo]()
@@ -105,6 +108,10 @@
 	// list of the Python libraries compatible both with Python2 and Python3.
 	Libs []string `android:"arch_variant"`
 
+	// TODO: b/403060602 - add unit tests for this property and related code
+	// list of shared libraries that should be packaged with the python code for this module.
+	Shared_libs []string `android:"arch_variant"`
+
 	Version struct {
 		// Python2-specific properties, including whether Python2 is supported for this module
 		// and version-specific sources, exclusions and dependencies.
@@ -158,6 +165,10 @@
 	precompiledSrcsZip android.Path
 
 	sourceProperties android.SourceProperties
+
+	// The shared libraries that should be bundled with the python code for
+	// any standalone python binaries that depend on this module.
+	bundleSharedLibs android.Paths
 }
 
 // newModule generates new Python base module
@@ -197,6 +208,10 @@
 	return &p.properties
 }
 
+func (p *PythonLibraryModule) getBundleSharedLibs() android.Paths {
+	return p.bundleSharedLibs
+}
+
 func (p *PythonLibraryModule) init() android.Module {
 	p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
@@ -224,6 +239,7 @@
 var (
 	pythonLibTag = dependencyTag{name: "pythonLib"}
 	javaDataTag  = dependencyTag{name: "javaData"}
+	sharedLibTag = dependencyTag{name: "sharedLib"}
 	// The python interpreter, with soong module name "py3-launcher" or "py3-launcher-autorun".
 	launcherTag          = dependencyTag{name: "launcher"}
 	launcherSharedLibTag = installDependencyTag{name: "launcherSharedLib"}
@@ -288,6 +304,12 @@
 	javaDataVariation := []blueprint.Variation{{"arch", android.Common.String()}}
 	ctx.AddVariationDependencies(javaDataVariation, javaDataTag, p.properties.Java_data...)
 
+	if ctx.Host() {
+		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), sharedLibTag, p.properties.Shared_libs...)
+	} else if len(p.properties.Shared_libs) > 0 {
+		ctx.PropertyErrorf("shared_libs", "shared_libs is not supported for device builds")
+	}
+
 	p.AddDepsOnPythonLauncherAndStdlib(ctx, hostStdLibTag, hostLauncherTag, hostlauncherSharedLibTag, false, ctx.Config().BuildOSTarget)
 }
 
@@ -377,6 +399,25 @@
 		expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
 	}
 
+	var directImplementationDeps android.Paths
+	var transitiveImplementationDeps []depset.DepSet[android.Path]
+	ctx.VisitDirectDepsProxyWithTag(sharedLibTag, func(dep android.ModuleProxy) {
+		sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
+		if sharedLibInfo.SharedLibrary != nil {
+			expandedData = append(expandedData, android.OutputFilesForModule(ctx, dep, "")...)
+			directImplementationDeps = append(directImplementationDeps, android.OutputFilesForModule(ctx, dep, "")...)
+			if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok {
+				transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps)
+				p.bundleSharedLibs = append(p.bundleSharedLibs, info.ImplementationDeps.ToList()...)
+			}
+		} else {
+			ctx.PropertyErrorf("shared_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+		}
+	})
+	android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+		ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps),
+	})
+
 	// Validate pkg_path property
 	pkgPath := String(p.properties.Pkg_path)
 	if pkgPath != "" {
@@ -408,6 +449,7 @@
 		SrcsZip:            p.getSrcsZip(),
 		PkgPath:            p.getPkgPath(),
 		PrecompiledSrcsZip: p.getPrecompiledSrcsZip(),
+		BundleSharedLibs:   p.getBundleSharedLibs(),
 	})
 }
 
@@ -684,6 +726,57 @@
 	return result
 }
 
+func (p *PythonLibraryModule) collectSharedLibDeps(ctx android.ModuleContext) android.Paths {
+	seen := make(map[android.Module]bool)
+
+	var result android.Paths
+
+	ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool {
+		// we only collect dependencies tagged as python library deps
+		if ctx.OtherModuleDependencyTag(child) != pythonLibTag {
+			return false
+		}
+		if seen[child] {
+			return false
+		}
+		seen[child] = true
+		dep, isLibrary := android.OtherModuleProvider(ctx, child, PythonLibraryInfoProvider)
+		if isLibrary {
+			result = append(result, dep.BundleSharedLibs...)
+		}
+		return true
+	})
+	return result
+}
+
+func (p *PythonLibraryModule) zipSharedLibs(ctx android.ModuleContext, bundleSharedLibs android.Paths) android.Path {
+	// sort the paths to keep the output deterministic
+	sort.Slice(bundleSharedLibs, func(i, j int) bool {
+		return bundleSharedLibs[i].String() < bundleSharedLibs[j].String()
+	})
+
+	parArgs := []string{"-symlinks=false", "-P lib64"}
+	paths := android.Paths{}
+	for _, path := range bundleSharedLibs {
+		// specify relative root of file in following -f arguments
+		parArgs = append(parArgs, `-C `+filepath.Dir(path.String()))
+		parArgs = append(parArgs, `-f `+path.String())
+		paths = append(paths, path)
+	}
+	srcsZip := android.PathForModuleOut(ctx, ctx.ModuleName()+".sharedlibs.srcszip")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        zip,
+		Description: "bundle shared libraries for python binary",
+		Output:      srcsZip,
+		Implicits:      paths,
+		Args: map[string]string{
+			"args": strings.Join(parArgs, " "),
+		},
+	})
+	return srcsZip
+}
+
+
 // chckForDuplicateOutputPath checks whether outputPath has already been included in map m, which
 // would result in two files being placed in the same location.
 // If there is a duplicate path, an error is thrown and true is returned
diff --git a/python/scripts/main.py b/python/scripts/main.py
index 225dbe4..35cdfc4 100644
--- a/python/scripts/main.py
+++ b/python/scripts/main.py
@@ -1,5 +1,13 @@
+
+import os
 import runpy
+import shutil
 import sys
+import tempfile
+import zipfile
+
+from pathlib import PurePath
+
 
 sys.argv[0] = __loader__.archive
 
@@ -9,4 +17,32 @@
 # when people try to use it.
 sys.executable = None
 
-runpy._run_module_as_main("ENTRY_POINT", alter_argv=False)
+# Extract the shared libraries from the zip file into a temporary directory.
+# This works around the limitations of dynamic linker.  Some Python libraries
+# reference the .so files relatively and so extracting only the .so files
+# does not work, so we extract the entire parent directory of the .so files to a
+# tempdir and then add that to sys.path.
+tempdir = None
+with zipfile.ZipFile(__loader__.archive) as z:
+  # any root so files or root directories that contain so files will be
+  # extracted to the tempdir so the linker load them, this minimizes the
+  # number of files that need to be extracted to a tempdir
+  extract_paths = {}
+  for member in z.infolist():
+    if member.filename.endswith('.so'):
+      extract_paths[PurePath(member.filename).parts[0]] = member.filename
+  if extract_paths:
+    tempdir = tempfile.mkdtemp()
+    for member in z.infolist():
+      if not PurePath(member.filename).parts[0] in extract_paths.keys():
+        continue
+      if member.is_dir():
+        os.makedirs(os.path.join(tempdir, member.filename))
+      else:
+        z.extract(member, tempdir)
+    sys.path.insert(0, tempdir)
+try:
+  runpy._run_module_as_main("ENTRY_POINT", alter_argv=False)
+finally:
+  if tempdir is not None:
+    shutil.rmtree(tempdir)