Merge "release_config: Inheritance should honor Redacted" into main
diff --git a/Android.bp b/Android.bp
index 9763622..1219c62 100644
--- a/Android.bp
+++ b/Android.bp
@@ -234,3 +234,12 @@
     relative_install_path: "etc", // odm_dlkm/etc/build.prop
     visibility: ["//visibility:private"],
 }
+
+build_prop {
+    name: "ramdisk-build.prop",
+    stem: "build.prop",
+    ramdisk: true,
+    product_config: ":product_config",
+    relative_install_path: "etc/ramdisk", // ramdisk/system/etc/ramdisk/build.prop
+    visibility: ["//visibility:private"],
+}
diff --git a/aconfig/build_flags/build_flags.go b/aconfig/build_flags/build_flags.go
index e878b5a..94e1eb1 100644
--- a/aconfig/build_flags/build_flags.go
+++ b/aconfig/build_flags/build_flags.go
@@ -35,7 +35,7 @@
 type buildFlags struct {
 	android.ModuleBase
 
-	outputPath android.OutputPath
+	outputPath android.Path
 }
 
 func buildFlagsFactory() android.Module {
@@ -48,7 +48,7 @@
 	// Read the build_flags_<partition>.json file generated by soong
 	// 'release-config' command.
 	srcPath := android.PathForOutput(ctx, "release-config", fmt.Sprintf("build_flags_%s.json", m.PartitionTag(ctx.DeviceConfig())))
-	m.outputPath = android.PathForModuleOut(ctx, outJsonFileName).OutputPath
+	outputPath := android.PathForModuleOut(ctx, outJsonFileName)
 
 	// The 'release-config' command is called for every build, and generates the
 	// build_flags_<partition>.json file.
@@ -56,11 +56,12 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   android.CpIfChanged,
 		Input:  srcPath,
-		Output: m.outputPath,
+		Output: outputPath,
 	})
 
 	installPath := android.PathForModuleInstall(ctx, "etc")
-	ctx.InstallFile(installPath, outJsonFileName, m.outputPath)
+	ctx.InstallFile(installPath, outJsonFileName, outputPath)
+	m.outputPath = outputPath
 }
 
 func (m *buildFlags) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/android/apex.go b/android/apex.go
index d140833..9277ff3 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -896,8 +896,8 @@
 type DepNameToDepInfoMap map[string]ApexModuleDepInfo
 
 type ApexBundleDepsInfo struct {
-	flatListPath OutputPath
-	fullListPath OutputPath
+	flatListPath Path
+	fullListPath Path
 }
 
 type ApexBundleDepsInfoIntf interface {
@@ -934,13 +934,15 @@
 		fmt.Fprintf(&flatContent, "%s\n", toName)
 	}
 
-	d.fullListPath = PathForModuleOut(ctx, "depsinfo", "fulllist.txt").OutputPath
-	WriteFileRule(ctx, d.fullListPath, fullContent.String())
+	fullListPath := PathForModuleOut(ctx, "depsinfo", "fulllist.txt")
+	WriteFileRule(ctx, fullListPath, fullContent.String())
+	d.fullListPath = fullListPath
 
-	d.flatListPath = PathForModuleOut(ctx, "depsinfo", "flatlist.txt").OutputPath
-	WriteFileRule(ctx, d.flatListPath, flatContent.String())
+	flatListPath := PathForModuleOut(ctx, "depsinfo", "flatlist.txt")
+	WriteFileRule(ctx, flatListPath, flatContent.String())
+	d.flatListPath = flatListPath
 
-	ctx.Phony(fmt.Sprintf("%s-depsinfo", ctx.ModuleName()), d.fullListPath, d.flatListPath)
+	ctx.Phony(fmt.Sprintf("%s-depsinfo", ctx.ModuleName()), fullListPath, flatListPath)
 }
 
 // Function called while walking an APEX's payload dependencies.
diff --git a/android/base_module_context.go b/android/base_module_context.go
index ab28676..1f89dea 100644
--- a/android/base_module_context.go
+++ b/android/base_module_context.go
@@ -211,6 +211,12 @@
 	// data modified by the current mutator.
 	VisitAllModuleVariants(visit func(Module))
 
+	// VisitAllModuleVariantProxies calls visit for each variant of the current module.  Variants of a module are always
+	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
+	// from all variants if the current module is the last one. Otherwise, care must be taken to not access any
+	// data modified by the current mutator.
+	VisitAllModuleVariantProxies(visit func(proxy ModuleProxy))
+
 	// GetTagPath is supposed to be called in visit function passed in WalkDeps()
 	// and returns a top-down dependency tags path from a start module to current child module.
 	// It has one less entry than GetWalkPath() as it contains the dependency tags that
@@ -382,7 +388,7 @@
 		return &aModule
 	}
 
-	if !OtherModuleProviderOrDefault(b, module, CommonPropertiesProviderKey).Enabled {
+	if !OtherModuleProviderOrDefault(b, module, CommonModuleInfoKey).Enabled {
 		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependencyProxy(b, aModule) {
 			if b.Config().AllowMissingDependencies() {
 				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
@@ -594,6 +600,10 @@
 	})
 }
 
+func (b *baseModuleContext) VisitAllModuleVariantProxies(visit func(ModuleProxy)) {
+	b.bp.VisitAllModuleVariantProxies(visitProxyAdaptor(visit))
+}
+
 func (b *baseModuleContext) PrimaryModule() Module {
 	return b.bp.PrimaryModule().(Module)
 }
diff --git a/android/build_prop.go b/android/build_prop.go
index 8389470..cda56f1 100644
--- a/android/build_prop.go
+++ b/android/build_prop.go
@@ -55,7 +55,7 @@
 
 	properties buildPropProperties
 
-	outputFilePath OutputPath
+	outputFilePath Path
 	installPath    InstallPath
 }
 
@@ -115,33 +115,22 @@
 		return "vendor_dlkm"
 	} else if p.InstallInOdmDlkm() {
 		return "odm_dlkm"
+	} else if p.InstallInRamdisk() {
+		// From this hardcoding in make:
+		// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/sysprop.mk;l=311;drc=274435657e4682e5cee3fffd11fb301ab32a828d
+		return "bootimage"
 	}
 	return "system"
 }
 
-var validPartitions = []string{
-	"system",
-	"system_ext",
-	"product",
-	"odm",
-	"vendor",
-	"system_dlkm",
-	"vendor_dlkm",
-	"odm_dlkm",
-}
-
 func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 	if !p.SocSpecific() && p.properties.Android_info != nil {
 		ctx.ModuleErrorf("Android_info cannot be set if build.prop is not installed in vendor partition")
 	}
 
-	p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath
+	outputFilePath := PathForModuleOut(ctx, "build.prop")
 
 	partition := p.partition(ctx.DeviceConfig())
-	if !InList(partition, validPartitions) {
-		ctx.PropertyErrorf("partition", "unsupported partition %q: only %q are supported", partition, validPartitions)
-		return
-	}
 
 	rule := NewRuleBuilder(pctx, ctx)
 
@@ -168,7 +157,7 @@
 	cmd.FlagWithInput("--product-config=", PathForModuleSrc(ctx, proptools.String(p.properties.Product_config)))
 	cmd.FlagWithArg("--partition=", partition)
 	cmd.FlagForEachInput("--prop-files=", p.propFiles(ctx))
-	cmd.FlagWithOutput("--out=", p.outputFilePath)
+	cmd.FlagWithOutput("--out=", outputFilePath)
 
 	postProcessCmd := rule.Command().BuiltTool("post_process_props")
 	if ctx.DeviceConfig().BuildBrokenDupSysprop() {
@@ -181,17 +170,18 @@
 		// still need to pass an empty string to kernel-version-file-for-uffd-gc
 		postProcessCmd.FlagWithArg("--kernel-version-file-for-uffd-gc ", `""`)
 	}
-	postProcessCmd.Text(p.outputFilePath.String())
+	postProcessCmd.Text(outputFilePath.String())
 	postProcessCmd.Flags(p.properties.Block_list)
 
-	rule.Command().Text("echo").Text(proptools.NinjaAndShellEscape("# end of file")).FlagWithArg(">> ", p.outputFilePath.String())
+	rule.Command().Text("echo").Text(proptools.NinjaAndShellEscape("# end of file")).FlagWithArg(">> ", outputFilePath.String())
 
 	rule.Build(ctx.ModuleName(), "generating build.prop")
 
 	p.installPath = PathForModuleInstall(ctx, proptools.String(p.properties.Relative_install_path))
-	ctx.InstallFile(p.installPath, p.stem(), p.outputFilePath)
+	ctx.InstallFile(p.installPath, p.stem(), outputFilePath)
 
-	ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
+	ctx.SetOutputFiles(Paths{outputFilePath}, "")
+	p.outputFilePath = outputFilePath
 }
 
 func (p *buildPropModule) AndroidMkEntries() []AndroidMkEntries {
diff --git a/android/csuite_config.go b/android/csuite_config.go
index 20bd035..26ad6e1 100644
--- a/android/csuite_config.go
+++ b/android/csuite_config.go
@@ -30,11 +30,11 @@
 type CSuiteConfig struct {
 	ModuleBase
 	properties     csuiteConfigProperties
-	OutputFilePath OutputPath
+	OutputFilePath Path
 }
 
 func (me *CSuiteConfig) GenerateAndroidBuildActions(ctx ModuleContext) {
-	me.OutputFilePath = PathForModuleOut(ctx, me.BaseModuleName()).OutputPath
+	me.OutputFilePath = PathForModuleOut(ctx, me.BaseModuleName())
 }
 
 func (me *CSuiteConfig) AndroidMkEntries() []AndroidMkEntries {
diff --git a/android/module.go b/android/module.go
index 4314357..ce995ad 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1643,25 +1643,27 @@
 func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) {
 	var allInstalledFiles InstallPaths
 	var allCheckbuildTargets Paths
-	ctx.VisitAllModuleVariants(func(module Module) {
-		a := module.base()
+	ctx.VisitAllModuleVariantProxies(func(module ModuleProxy) {
 		var checkbuildTarget Path
 		var uncheckedModule bool
-		if a == m {
+		var skipAndroidMkProcessing bool
+		if ctx.EqualModules(m.module, module) {
 			allInstalledFiles = append(allInstalledFiles, ctx.installFiles...)
 			checkbuildTarget = ctx.checkbuildTarget
 			uncheckedModule = ctx.uncheckedModule
+			skipAndroidMkProcessing = shouldSkipAndroidMkProcessing(ctx, m)
 		} else {
 			info := OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider)
 			allInstalledFiles = append(allInstalledFiles, info.InstallFiles...)
 			checkbuildTarget = info.CheckbuildTarget
 			uncheckedModule = info.UncheckedModule
+			skipAndroidMkProcessing = OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).SkipAndroidMkProcessing
 		}
 		// A module's -checkbuild phony targets should
 		// not be created if the module is not exported to make.
 		// Those could depend on the build target and fail to compile
 		// for the current build target.
-		if (!ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, a)) && !uncheckedModule && checkbuildTarget != nil {
+		if (!ctx.Config().KatiEnabled() || !skipAndroidMkProcessing) && !uncheckedModule && checkbuildTarget != nil {
 			allCheckbuildTargets = append(allCheckbuildTargets, checkbuildTarget)
 		}
 	})
@@ -1850,15 +1852,16 @@
 
 var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]()
 
-type CommonPropertiesProviderData struct {
+type CommonModuleInfo struct {
 	Enabled bool
 	// Whether the module has been replaced by a prebuilt
 	ReplacedByPrebuilt bool
 	// The Target of artifacts that this module variant is responsible for creating.
-	CompileTarget Target
+	CompileTarget           Target
+	SkipAndroidMkProcessing bool
 }
 
-var CommonPropertiesProviderKey = blueprint.NewProvider[CommonPropertiesProviderData]()
+var CommonModuleInfoKey = blueprint.NewProvider[CommonModuleInfo]()
 
 type PrebuiltModuleProviderData struct {
 	// Empty for now
@@ -2120,16 +2123,17 @@
 	}
 	buildComplianceMetadataProvider(ctx, m)
 
-	commonData := CommonPropertiesProviderData{
-		ReplacedByPrebuilt: m.commonProperties.ReplacedByPrebuilt,
-		CompileTarget:      m.commonProperties.CompileTarget,
+	commonData := CommonModuleInfo{
+		ReplacedByPrebuilt:      m.commonProperties.ReplacedByPrebuilt,
+		CompileTarget:           m.commonProperties.CompileTarget,
+		SkipAndroidMkProcessing: shouldSkipAndroidMkProcessing(ctx, m),
 	}
 	if m.commonProperties.ForcedDisabled {
 		commonData.Enabled = false
 	} else {
 		commonData.Enabled = m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled)
 	}
-	SetProvider(ctx, CommonPropertiesProviderKey, commonData)
+	SetProvider(ctx, CommonModuleInfoKey, commonData)
 	if p, ok := m.module.(PrebuiltInterface); ok && p.Prebuilt() != nil {
 		SetProvider(ctx, PrebuiltModuleProviderKey, PrebuiltModuleProviderData{})
 	}
@@ -2138,7 +2142,7 @@
 			HostToolPath: h.HostToolPath()})
 	}
 
-	if p, ok := m.module.(AndroidMkProviderInfoProducer); ok && !shouldSkipAndroidMkProcessing(ctx, m) {
+	if p, ok := m.module.(AndroidMkProviderInfoProducer); ok && !commonData.SkipAndroidMkProcessing {
 		SetProvider(ctx, AndroidMkInfoProvider, p.PrepareAndroidMKProviderInfo(ctx.Config()))
 	}
 }
diff --git a/android/paths.go b/android/paths.go
index 8f066cc..7ab1f22 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -675,7 +675,7 @@
 	if module == nil {
 		return nil, missingDependencyError{[]string{moduleName}}
 	}
-	if !OtherModuleProviderOrDefault(ctx, *module, CommonPropertiesProviderKey).Enabled {
+	if !OtherModuleProviderOrDefault(ctx, *module, CommonModuleInfoKey).Enabled {
 		return nil, missingDependencyError{[]string{moduleName}}
 	}
 
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 51e72af..0ac67b3 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -381,7 +381,7 @@
 // the right module. This function is only safe to call after all TransitionMutators
 // have run, e.g. in GenerateAndroidBuildActions.
 func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module {
-	if !OtherModuleProviderOrDefault(ctx, module, CommonPropertiesProviderKey).ReplacedByPrebuilt {
+	if !OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).ReplacedByPrebuilt {
 		return module
 	}
 	if _, ok := OtherModuleProvider(ctx, module, PrebuiltModuleProviderKey); ok {
diff --git a/android/product_config.go b/android/product_config.go
index ce3acc9..850f003 100644
--- a/android/product_config.go
+++ b/android/product_config.go
@@ -32,7 +32,7 @@
 		ctx.ModuleErrorf("There can only be one product_config module in build/soong")
 		return
 	}
-	outputFilePath := PathForModuleOut(ctx, p.Name()+".json").OutputPath
+	outputFilePath := PathForModuleOut(ctx, p.Name()+".json")
 
 	// DeviceProduct can be null so calling ctx.Config().DeviceProduct() may cause null dereference
 	targetProduct := proptools.String(ctx.Config().config.productVariables.DeviceProduct)
diff --git a/android/vintf_data.go b/android/vintf_data.go
index 7823397..401f4d2 100644
--- a/android/vintf_data.go
+++ b/android/vintf_data.go
@@ -49,7 +49,7 @@
 	properties vintfDataProperties
 
 	installDirPath InstallPath
-	outputFilePath OutputPath
+	outputFilePath Path
 	noAction       bool
 }
 
@@ -148,7 +148,7 @@
 	builder.Build("assemble_vintf", "Process vintf data "+gensrc.String())
 
 	m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf")
-	m.outputFilePath = gensrc.OutputPath
+	m.outputFilePath = gensrc
 
 	installFileName := "manifest.xml"
 	if filename := proptools.String(m.properties.Filename); filename != "" {
diff --git a/android/vintf_fragment.go b/android/vintf_fragment.go
index 42eaaf0..a3343fd 100644
--- a/android/vintf_fragment.go
+++ b/android/vintf_fragment.go
@@ -25,7 +25,7 @@
 	properties vintfFragmentProperties
 
 	installDirPath InstallPath
-	outputFilePath OutputPath
+	outputFilePath Path
 }
 
 func init() {
@@ -64,7 +64,7 @@
 	builder.Build("assemble_vintf", "Process vintf fragment "+processedVintfFragment.String())
 
 	m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf", "manifest")
-	m.outputFilePath = processedVintfFragment.OutputPath
+	m.outputFilePath = processedVintfFragment
 
 	ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment)
 }
diff --git a/apex/apex.go b/apex/apex.go
index e0195d3..dc24df3 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -511,7 +511,7 @@
 
 	// Text file having the list of individual files that are included in this APEX. Used for
 	// debugging purpose.
-	installedFilesFile android.WritablePath
+	installedFilesFile android.Path
 
 	// List of module names that this APEX is including (to be shown via *-deps-info target).
 	// Used for debugging purpose.
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 00dd446..d46104e 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -64,12 +64,14 @@
 			if grep -v -h '^#' ${allowed_deps_list} | sort -u -f| diff -B -u - ${new_allowed_deps}; then
 			   touch ${out};
 			else
-				echo -e "\n******************************";
+				echo;
+				echo "******************************";
 				echo "ERROR: go/apex-allowed-deps-error contains more information";
 				echo "******************************";
 				echo "Detected changes to allowed dependencies in updatable modules.";
 				echo "To fix and update packages/modules/common/build/allowed_deps.txt, please run:";
-				echo -e "$$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)\n";
+				echo "$$ (croot && packages/modules/common/build/update-apex-allowed-deps.sh)";
+				echo;
 				echo "When submitting the generated CL, you must include the following information";
 				echo "in the commit message if you are adding a new dependency:";
 				echo "Apex-Size-Increase: Expected binary size increase for affected APEXes (or the size of the .jar / .so file of the new library)";
@@ -78,7 +80,8 @@
 				echo "Test-Info: What’s the testing strategy for the new dependency? Does it have its own tests, and are you adding integration tests? How/when are the tests run?";
 				echo "You do not need OWNERS approval to submit the change, but mainline-modularization@";
 				echo "will periodically review additions and may require changes.";
-				echo -e "******************************\n";
+				echo "******************************";
+				echo;
 				exit 1;
 			fi;
 		`,
diff --git a/apex/builder.go b/apex/builder.go
index b04a9d7..d0acc8d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -196,7 +196,7 @@
 		Command: `diff --unchanged-group-format='' \` +
 			`--changed-group-format='%<' \` +
 			`${image_content_file} ${allowed_files_file} || (` +
-			`echo -e "New unexpected files were added to ${apex_module_name}." ` +
+			`echo "New unexpected files were added to ${apex_module_name}." ` +
 			` "To fix the build run following command:" && ` +
 			`echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` +
 			`exit 1); touch ${out}`,
@@ -388,7 +388,7 @@
 // file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from
 // the file_contexts property of this APEX. This is to make sure that the manifest file is correctly
 // labeled as system_file or vendor_apex_metadata_file.
-func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
+func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Path {
 	var fileContexts android.Path
 	var fileContextsDir string
 	isFileContextsModule := false
@@ -443,13 +443,13 @@
 	}
 
 	rule.Build("file_contexts."+a.Name(), "Generate file_contexts")
-	return output.OutputPath
+	return output
 }
 
 // buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of
 // files included in this APEX is shown. The text file is dist'ed so that people can see what's
 // included in the APEX without actually downloading and extracting it.
-func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath {
+func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.Path {
 	output := android.PathForModuleOut(ctx, "installed-files.txt")
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
@@ -459,12 +459,12 @@
 		Text(" | sort -nr > ").
 		Output(output)
 	rule.Build("installed-files."+a.Name(), "Installed files")
-	return output.OutputPath
+	return output
 }
 
 // buildBundleConfig creates a build rule for the bundle config file that will control the bundle
 // creation process.
-func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.OutputPath {
+func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Path {
 	output := android.PathForModuleOut(ctx, "bundle_config.json")
 
 	type ApkConfig struct {
@@ -509,7 +509,7 @@
 
 	android.WriteFileRule(ctx, output, string(j))
 
-	return output.OutputPath
+	return output
 }
 
 func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android.Path) android.Path {
@@ -922,17 +922,17 @@
 		args["outCommaList"] = signedOutputFile.String()
 	}
 	var validations android.Paths
-	validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
+	validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile, imageDir))
 	// TODO(b/279688635) deapexer supports [ext4]
 	if !a.testApex && suffix == imageApexSuffix && ext4 == a.payloadFsType {
-		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
+		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile))
 	}
 	if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 {
 		validations = append(validations,
-			runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
+			runApexElfCheckerUnwanted(ctx, unsignedOutputFile, a.properties.Unwanted_transitive_deps))
 	}
 	if !a.testApex && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
-		validations = append(validations, runApexHostVerifier(ctx, a, unsignedOutputFile.OutputPath))
+		validations = append(validations, runApexHostVerifier(ctx, a, unsignedOutputFile))
 	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
@@ -1135,7 +1135,7 @@
 	a.lintReports = java.BuildModuleLintReportZips(ctx, depSets, validations)
 }
 
-func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
+func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Path {
 	var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
 	var executablePaths []string // this also includes dirs
 	var appSetDirs []string
@@ -1199,10 +1199,10 @@
 	cmd.Text(")").FlagWithOutput("> ", cannedFsConfig)
 	builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName()))
 
-	return cannedFsConfig.OutputPath
+	return cannedFsConfig
 }
 
-func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path {
+func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.Path, imageDir android.Path) android.Path {
 	timestamp := android.PathForModuleOut(ctx, "apex_linkerconfig_validation.timestamp")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   apexLinkerconfigValidationRule,
@@ -1219,7 +1219,7 @@
 //
 // $ deapexer list -Z {apex_file} > {file_contexts}
 // $ apex_sepolicy_tests -f {file_contexts}
-func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.OutputPath) android.Path {
+func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.Path) android.Path {
 	timestamp := android.PathForModuleOut(ctx, "sepolicy_tests.timestamp")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   apexSepolicyTestsRule,
@@ -1229,7 +1229,7 @@
 	return timestamp
 }
 
-func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.OutputPath, unwanted []string) android.Path {
+func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.Path, unwanted []string) android.Path {
 	timestamp := android.PathForModuleOut(ctx, "apex_elf_unwanted.timestamp")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   apexElfCheckerUnwantedRule,
@@ -1243,7 +1243,7 @@
 	return timestamp
 }
 
-func runApexHostVerifier(ctx android.ModuleContext, a *apexBundle, apexFile android.OutputPath) android.Path {
+func runApexHostVerifier(ctx android.ModuleContext, a *apexBundle, apexFile android.Path) android.Path {
 	timestamp := android.PathForModuleOut(ctx, "host_apex_verifier.timestamp")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   apexHostVerifierRule,
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 9cd5688..acf3b91 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -386,7 +386,7 @@
 
 	inputApex android.Path
 
-	provenanceMetaDataFile android.OutputPath
+	provenanceMetaDataFile android.Path
 }
 
 type ApexFileProperties struct {
@@ -697,7 +697,7 @@
 	ctx.SetOutputFiles(android.Paths{p.outputApex}, "")
 }
 
-func (p *Prebuilt) ProvenanceMetaDataFile() android.OutputPath {
+func (p *Prebuilt) ProvenanceMetaDataFile() android.Path {
 	return p.provenanceMetaDataFile
 }
 
diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go
index 790a865..f553f27 100644
--- a/cc/cmake_snapshot.go
+++ b/cc/cmake_snapshot.go
@@ -484,7 +484,7 @@
 	// Packaging all make files into the zip file
 	makefilesRspFile := android.PathForModuleObj(ctx, ctx.ModuleName()+"_makefiles.rsp")
 	zipCmd.
-		FlagWithArg("-C ", android.PathForModuleGen(ctx).OutputPath.String()).
+		FlagWithArg("-C ", android.PathForModuleGen(ctx).String()).
 		FlagWithRspFileInputList("-r ", makefilesRspFile, makefilesList)
 
 	// Packaging all prebuilts into the zip file
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 124dda4..f0d7343 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1813,7 +1813,7 @@
 type sanitizerLibrariesTxtModule struct {
 	android.ModuleBase
 
-	outputFile android.OutputPath
+	outputFile android.Path
 }
 
 var _ etc.PrebuiltEtcModule = (*sanitizerLibrariesTxtModule)(nil)
@@ -1896,13 +1896,14 @@
 func (txt *sanitizerLibrariesTxtModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	filename := txt.Name()
 
-	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
-	android.WriteFileRule(ctx, txt.outputFile, txt.getSanitizerLibs(ctx))
+	outputFile := android.PathForModuleOut(ctx, filename)
+	android.WriteFileRule(ctx, outputFile, txt.getSanitizerLibs(ctx))
 
 	installPath := android.PathForModuleInstall(ctx, "etc")
-	ctx.InstallFile(installPath, filename, txt.outputFile)
+	ctx.InstallFile(installPath, filename, outputFile)
 
-	ctx.SetOutputFiles(android.Paths{txt.outputFile}, "")
+	ctx.SetOutputFiles(android.Paths{outputFile}, "")
+	txt.outputFile = outputFile
 }
 
 func (txt *sanitizerLibrariesTxtModule) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo {
diff --git a/cc/tidy.go b/cc/tidy.go
index 5cbf8f0..6481b95 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -220,7 +220,7 @@
 
 	// (1) Collect all obj/tidy files into OS-specific groups.
 	ctx.VisitAllModuleVariantProxies(module, func(variant android.ModuleProxy) {
-		osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonPropertiesProviderKey).CompileTarget.Os.Name
+		osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonModuleInfoKey).CompileTarget.Os.Name
 		info := android.OtherModuleProviderOrDefault(ctx, variant, CcObjectInfoProvider)
 		addToOSGroup(osName, info.objFiles, allObjFileGroups, subsetObjFileGroups)
 		addToOSGroup(osName, info.tidyFiles, allTidyFileGroups, subsetTidyFileGroups)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3dd6f9a..e3804e5 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -465,7 +465,7 @@
 func (d dex2oatDependencyTag) AllowDisabledModuleDependencyProxy(
 	ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool {
 	return android.OtherModuleProviderOrDefault(
-		ctx, target, android.CommonPropertiesProviderKey).ReplacedByPrebuilt
+		ctx, target, android.CommonModuleInfoKey).ReplacedByPrebuilt
 }
 
 // Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that
diff --git a/etc/adb_keys.go b/etc/adb_keys.go
index 73bc347..cfcb1d5 100644
--- a/etc/adb_keys.go
+++ b/etc/adb_keys.go
@@ -24,7 +24,7 @@
 
 type AdbKeysModule struct {
 	android.ModuleBase
-	outputPath  android.OutputPath
+	outputPath  android.Path
 	installPath android.InstallPath
 }
 
@@ -46,15 +46,16 @@
 		return
 	}
 
-	m.outputPath = android.PathForModuleOut(ctx, "adb_keys").OutputPath
+	outputPath := android.PathForModuleOut(ctx, "adb_keys")
 	input := android.ExistentPathForSource(ctx, android.String(productVariables.AdbKeys))
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   android.Cp,
-		Output: m.outputPath,
+		Output: outputPath,
 		Input:  input.Path(),
 	})
 	m.installPath = android.PathForModuleInstall(ctx, "etc/security")
-	ctx.InstallFile(m.installPath, "adb_keys", m.outputPath)
+	ctx.InstallFile(m.installPath, "adb_keys", outputPath)
+	m.outputPath = outputPath
 }
 
 func (m *AdbKeysModule) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/etc/otacerts_zip.go b/etc/otacerts_zip.go
index d12bdac..8220cea 100644
--- a/etc/otacerts_zip.go
+++ b/etc/otacerts_zip.go
@@ -44,7 +44,7 @@
 	android.ModuleBase
 
 	properties otacertsZipProperties
-	outputPath android.OutputPath
+	outputPath android.Path
 }
 
 // otacerts_zip collects key files defined in PRODUCT_DEFAULT_DEV_CERTIFICATE
@@ -117,11 +117,11 @@
 	// Read .x509.pem files listed  in PRODUCT_EXTRA_OTA_KEYS or PRODUCT_EXTRA_RECOVERY_KEYS.
 	extras := ctx.Config().ExtraOtaKeys(ctx, m.InRecovery())
 	srcPaths := append([]android.SourcePath{pem}, extras...)
-	m.outputPath = android.PathForModuleOut(ctx, m.outputFileName()).OutputPath
+	outputPath := android.PathForModuleOut(ctx, m.outputFileName())
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 	cmd := rule.Command().BuiltTool("soong_zip").
-		FlagWithOutput("-o ", m.outputPath).
+		FlagWithOutput("-o ", outputPath).
 		Flag("-j ").
 		Flag("-symlinks=false ")
 	for _, src := range srcPaths {
@@ -130,7 +130,8 @@
 	rule.Build(ctx.ModuleName(), "Generating the otacerts zip file")
 
 	installPath := android.PathForModuleInstall(ctx, "etc", proptools.String(m.properties.Relative_install_path))
-	ctx.InstallFile(installPath, m.outputFileName(), m.outputPath)
+	ctx.InstallFile(installPath, m.outputFileName(), outputPath)
+	m.outputPath = outputPath
 }
 
 func (m *otacertsZipModule) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 943ec81..b0b5da9 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -184,7 +184,7 @@
 	subdirProperties prebuiltSubdirProperties
 
 	sourceFilePaths android.Paths
-	outputFilePaths android.OutputPaths
+	outputFilePaths android.WritablePaths
 	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
 	installDirBase               string
 	installDirBase64             string
@@ -317,7 +317,7 @@
 	p.additionalDependencies = &paths
 }
 
-func (p *PrebuiltEtc) OutputFile() android.OutputPath {
+func (p *PrebuiltEtc) OutputFile() android.Path {
 	if p.usedSrcsProperty {
 		panic(fmt.Errorf("OutputFile not available on multi-source prebuilt %q", p.Name()))
 	}
@@ -410,7 +410,7 @@
 			ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
 			return
 		}
-		p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+		p.outputFilePaths = android.WritablePaths{android.PathForModuleOut(ctx, filename)}
 
 		ip := installProperties{
 			filename:       filename,
@@ -453,7 +453,7 @@
 				filename = src.Base()
 				installDirPath = baseInstallDirPath
 			}
-			output := android.PathForModuleOut(ctx, filename).OutputPath
+			output := android.PathForModuleOut(ctx, filename)
 			ip := installProperties{
 				filename:       filename,
 				sourceFilePath: src,
@@ -473,7 +473,7 @@
 		if filename == "" {
 			filename = ctx.ModuleName()
 		}
-		p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+		p.outputFilePaths = android.WritablePaths{android.PathForModuleOut(ctx, filename)}
 		ip := installProperties{
 			filename:       filename,
 			sourceFilePath: p.sourceFilePaths[0],
@@ -501,7 +501,7 @@
 type installProperties struct {
 	filename       string
 	sourceFilePath android.Path
-	outputFilePath android.OutputPath
+	outputFilePath android.WritablePath
 	installDirPath android.InstallPath
 	symlinks       []string
 }
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
index 469f1fb..9d4ba3e 100644
--- a/filesystem/avb_add_hash_footer.go
+++ b/filesystem/avb_add_hash_footer.go
@@ -29,7 +29,7 @@
 
 	properties avbAddHashFooterProperties
 
-	output     android.OutputPath
+	output     android.Path
 	installDir android.InstallPath
 }
 
@@ -97,8 +97,8 @@
 		return
 	}
 	input := android.PathForModuleSrc(ctx, proptools.String(a.properties.Src))
-	a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath
-	builder.Command().Text("cp").Input(input).Output(a.output)
+	output := android.PathForModuleOut(ctx, a.installFileName())
+	builder.Command().Text("cp").Input(input).Output(output)
 
 	cmd := builder.Command().BuiltTool("avbtool").Text("add_hash_footer")
 
@@ -141,12 +141,13 @@
 		cmd.Flag(fmt.Sprintf(" --rollback_index %d", rollbackIndex))
 	}
 
-	cmd.FlagWithOutput("--image ", a.output)
+	cmd.FlagWithOutput("--image ", output)
 
 	builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName()))
 
 	a.installDir = android.PathForModuleInstall(ctx, "etc")
-	ctx.InstallFile(a.installDir, a.installFileName(), a.output)
+	ctx.InstallFile(a.installDir, a.installFileName(), output)
+	a.output = output
 }
 
 func addAvbProp(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, prop avbProp) {
diff --git a/filesystem/avb_gen_vbmeta_image.go b/filesystem/avb_gen_vbmeta_image.go
index a7fd782..0669a2c 100644
--- a/filesystem/avb_gen_vbmeta_image.go
+++ b/filesystem/avb_gen_vbmeta_image.go
@@ -28,7 +28,7 @@
 
 	properties avbGenVbmetaImageProperties
 
-	output     android.OutputPath
+	output     android.Path
 	installDir android.InstallPath
 }
 
@@ -78,11 +78,12 @@
 	}
 	cmd.FlagWithArg("--salt ", proptools.String(a.properties.Salt))
 
-	a.output = android.PathForModuleOut(ctx, a.installFileName()).OutputPath
-	cmd.FlagWithOutput("--output_vbmeta_image ", a.output)
+	output := android.PathForModuleOut(ctx, a.installFileName())
+	cmd.FlagWithOutput("--output_vbmeta_image ", output)
 	builder.Build("avbGenVbmetaImage", fmt.Sprintf("avbGenVbmetaImage %s", ctx.ModuleName()))
 
-	ctx.SetOutputFiles([]android.Path{a.output}, "")
+	ctx.SetOutputFiles([]android.Path{output}, "")
+	a.output = output
 }
 
 var _ android.AndroidMkEntriesProvider = (*avbGenVbmetaImage)(nil)
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 9d93925..c9bd617 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -34,7 +34,7 @@
 
 	properties bootimgProperties
 
-	output     android.OutputPath
+	output     android.Path
 	installDir android.InstallPath
 }
 
@@ -115,20 +115,20 @@
 	vendor := proptools.Bool(b.properties.Vendor_boot)
 	unsignedOutput := b.buildBootImage(ctx, vendor)
 
+	output := unsignedOutput
 	if proptools.Bool(b.properties.Use_avb) {
-		b.output = b.signImage(ctx, unsignedOutput)
-	} else {
-		b.output = unsignedOutput
+		output = b.signImage(ctx, unsignedOutput)
 	}
 
 	b.installDir = android.PathForModuleInstall(ctx, "etc")
-	ctx.InstallFile(b.installDir, b.installFileName(), b.output)
+	ctx.InstallFile(b.installDir, b.installFileName(), output)
 
-	ctx.SetOutputFiles([]android.Path{b.output}, "")
+	ctx.SetOutputFiles([]android.Path{output}, "")
+	b.output = output
 }
 
-func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android.OutputPath {
-	output := android.PathForModuleOut(ctx, "unsigned", b.installFileName()).OutputPath
+func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android.Path {
+	output := android.PathForModuleOut(ctx, "unsigned", b.installFileName())
 
 	builder := android.NewRuleBuilder(pctx, ctx)
 	cmd := builder.Command().BuiltTool("mkbootimg")
@@ -215,10 +215,10 @@
 	return output
 }
 
-func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.OutputPath) android.OutputPath {
+func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.Path) android.Path {
 	propFile, toolDeps := b.buildPropFile(ctx)
 
-	output := android.PathForModuleOut(ctx, b.installFileName()).OutputPath
+	output := android.PathForModuleOut(ctx, b.installFileName())
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().Text("cp").Input(unsignedImage).Output(output)
 	builder.Command().BuiltTool("verity_utils").
@@ -239,7 +239,7 @@
 	return sha1sum(input)
 }
 
-func (b *bootimg) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
+func (b *bootimg) buildPropFile(ctx android.ModuleContext) (android.Path, android.Paths) {
 	var sb strings.Builder
 	var deps android.Paths
 	addStr := func(name string, value string) {
@@ -261,7 +261,7 @@
 	addStr("partition_name", partitionName)
 	addStr("avb_salt", b.salt())
 
-	propFile = android.PathForModuleOut(ctx, "prop").OutputPath
+	propFile := android.PathForModuleOut(ctx, "prop")
 	android.WriteFileRule(ctx, propFile, sb.String())
 	return propFile, deps
 }
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index fa66451..c346770 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -52,10 +52,10 @@
 
 	properties FilesystemProperties
 
-	output     android.OutputPath
+	output     android.Path
 	installDir android.InstallPath
 
-	fileListFile android.OutputPath
+	fileListFile android.Path
 
 	// Keeps the entries installed from this filesystem
 	entries []string
@@ -340,19 +340,20 @@
 	ctx.InstallFile(f.installDir, f.installFileName(), f.output)
 	ctx.SetOutputFiles([]android.Path{f.output}, "")
 
-	f.fileListFile = android.PathForModuleOut(ctx, "fileList").OutputPath
-	android.WriteFileRule(ctx, f.fileListFile, f.installedFilesList())
+	fileListFile := android.PathForModuleOut(ctx, "fileList")
+	android.WriteFileRule(ctx, fileListFile, f.installedFilesList())
 
 	android.SetProvider(ctx, FilesystemProvider, FilesystemInfo{
-		FileListFile: f.fileListFile,
+		FileListFile: fileListFile,
 	})
+	f.fileListFile = fileListFile
 
 	if proptools.Bool(f.properties.Unchecked_module) {
 		ctx.UncheckedModule()
 	}
 }
 
-func (f *filesystem) appendToEntry(ctx android.ModuleContext, installedFile android.OutputPath) {
+func (f *filesystem) appendToEntry(ctx android.ModuleContext, installedFile android.Path) {
 	partitionBaseDir := android.PathForModuleOut(ctx, "root", f.partitionName()).String() + "/"
 
 	relPath, inTargetPartition := strings.CutPrefix(installedFile.String(), partitionBaseDir)
@@ -443,7 +444,7 @@
 	builder.Command().Textf("cp -prf %s/* %s", rebasedDir, installPath)
 }
 
-func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
+func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.Path {
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
 	rebasedDir := rootDir
 	if f.properties.Base_dir != nil {
@@ -472,7 +473,7 @@
 		FlagWithArg("--out_system=", rootDir.String()+"/system")
 
 	propFile, toolDeps := f.buildPropFile(ctx)
-	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
+	output := android.PathForModuleOut(ctx, f.installFileName())
 	builder.Command().BuiltTool("build_image").
 		Text(rootDir.String()). // input directory
 		Input(propFile).
@@ -486,14 +487,14 @@
 	return output
 }
 
-func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
+func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.Path {
 	builder := android.NewRuleBuilder(pctx, ctx)
 	fcBin := android.PathForModuleOut(ctx, "file_contexts.bin")
 	builder.Command().BuiltTool("sefcontext_compile").
 		FlagWithOutput("-o ", fcBin).
 		Input(android.PathForModuleSrc(ctx, proptools.String(f.properties.File_contexts)))
 	builder.Build("build_filesystem_file_contexts", fmt.Sprintf("Creating filesystem file contexts for %s", f.BaseModuleName()))
-	return fcBin.OutputPath
+	return fcBin
 }
 
 // Calculates avb_salt from entry list (sorted) for deterministic output.
@@ -501,7 +502,7 @@
 	return sha1sum(f.entries)
 }
 
-func (f *filesystem) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
+func (f *filesystem) buildPropFile(ctx android.ModuleContext) (android.Path, android.Paths) {
 	var deps android.Paths
 	var propFileString strings.Builder
 	addStr := func(name string, value string) {
@@ -597,7 +598,7 @@
 	}
 	f.checkFsTypePropertyError(ctx, fst, fsTypeStr(fst))
 
-	propFile = android.PathForModuleOut(ctx, "prop").OutputPath
+	propFile := android.PathForModuleOut(ctx, "prop")
 	android.WriteFileRuleVerbatim(ctx, propFile, propFileString.String())
 	return propFile, deps
 }
@@ -622,7 +623,7 @@
 	}
 }
 
-func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) android.OutputPath {
+func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) android.Path {
 	if proptools.Bool(f.properties.Use_avb) {
 		ctx.PropertyErrorf("use_avb", "signing compresed cpio image using avbtool is not supported."+
 			"Consider adding this to bootimg module and signing the entire boot image.")
@@ -654,7 +655,7 @@
 	f.filesystemBuilder.BuildLinkerConfigFile(ctx, builder, rebasedDir)
 	f.copyFilesToProductOut(ctx, builder, rebasedDir)
 
-	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
+	output := android.PathForModuleOut(ctx, f.installFileName())
 	cmd := builder.Command().
 		BuiltTool("mkbootfs").
 		Text(rootDir.String()) // input directory
diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go
index 199c845..3119f2f 100644
--- a/filesystem/fsverity_metadata.go
+++ b/filesystem/fsverity_metadata.go
@@ -33,7 +33,7 @@
 	Libs []string `android:"path"`
 }
 
-func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.OutputPath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
+func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.WritablePath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
 	var buf strings.Builder
 	for _, spec := range matchedSpecs {
 		buf.WriteString(rebasedDir.Join(ctx, spec.RelPathInPackage()).String())
@@ -113,12 +113,12 @@
 	f.appendToEntry(ctx, manifestPbPath)
 
 	manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list")
-	f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath.OutputPath, matchedSpecs, rebasedDir)
+	f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath, matchedSpecs, rebasedDir)
 	sb.WriteRune('@')
 	sb.WriteString(manifestGeneratorListPath.String())
 	sb.WriteRune('\n')
 	cmd.Implicit(manifestGeneratorListPath)
-	f.appendToEntry(ctx, manifestGeneratorListPath.OutputPath)
+	f.appendToEntry(ctx, manifestGeneratorListPath)
 
 	// STEP 2-2: generate BuildManifest.apk (unsigned)
 	aapt2Path := ctx.Config().HostToolPath(ctx, "aapt2")
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index 988a57b..d0888a9 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -32,7 +32,7 @@
 
 	properties logicalPartitionProperties
 
-	output     android.OutputPath
+	output     android.Path
 	installDir android.InstallPath
 }
 
@@ -95,11 +95,14 @@
 	builder := android.NewRuleBuilder(pctx, ctx)
 
 	// Sparse the filesystem images and calculate their sizes
-	sparseImages := make(map[string]android.OutputPath)
-	sparseImageSizes := make(map[string]android.OutputPath)
+	sparseImages := make(map[string]android.Path)
+	sparseImageSizes := make(map[string]android.Path)
 
 	sparsePartitions := func(partitions []partitionProperties) {
 		for _, part := range partitions {
+			if part.Filesystem == nil {
+				continue
+			}
 			sparseImg, sizeTxt := sparseFilesystem(ctx, part, builder)
 			pName := proptools.String(part.Name)
 			sparseImages[pName] = sparseImg
@@ -185,31 +188,29 @@
 		addPartitionsToGroup(group.Partitions, gName)
 	}
 
-	l.output = android.PathForModuleOut(ctx, l.installFileName()).OutputPath
-	cmd.FlagWithOutput("--output=", l.output)
+	output := android.PathForModuleOut(ctx, l.installFileName())
+	cmd.FlagWithOutput("--output=", output)
 
 	builder.Build("build_logical_partition", fmt.Sprintf("Creating %s", l.BaseModuleName()))
 
 	l.installDir = android.PathForModuleInstall(ctx, "etc")
-	ctx.InstallFile(l.installDir, l.installFileName(), l.output)
+	ctx.InstallFile(l.installDir, l.installFileName(), output)
 
-	ctx.SetOutputFiles([]android.Path{l.output}, "")
+	ctx.SetOutputFiles([]android.Path{output}, "")
+	l.output = output
 }
 
 // Add a rule that converts the filesystem for the given partition to the given rule builder. The
 // path to the sparse file and the text file having the size of the partition are returned.
-func sparseFilesystem(ctx android.ModuleContext, p partitionProperties, builder *android.RuleBuilder) (sparseImg android.OutputPath, sizeTxt android.OutputPath) {
-	if p.Filesystem == nil {
-		return
-	}
-	img := android.PathForModuleSrc(ctx, proptools.String(p.Filesystem))
+func sparseFilesystem(ctx android.ModuleContext, p partitionProperties, builder *android.RuleBuilder) (android.Path, android.Path) {
+	img := android.PathForModuleSrc(ctx, *p.Filesystem)
 	name := proptools.String(p.Name)
-	sparseImg = android.PathForModuleOut(ctx, name+".img").OutputPath
 
+	sparseImg := android.PathForModuleOut(ctx, name+".img")
 	builder.Temporary(sparseImg)
 	builder.Command().BuiltTool("img2simg").Input(img).Output(sparseImg)
 
-	sizeTxt = android.PathForModuleOut(ctx, name+"-size.txt").OutputPath
+	sizeTxt := android.PathForModuleOut(ctx, name+"-size.txt")
 	builder.Temporary(sizeTxt)
 	builder.Command().BuiltTool("sparse_img").Flag("--get_partition_size").Input(sparseImg).
 		Text("| ").Text("tr").FlagWithArg("-d ", "'\n'").
diff --git a/filesystem/raw_binary.go b/filesystem/raw_binary.go
index ad36c29..707fba0 100644
--- a/filesystem/raw_binary.go
+++ b/filesystem/raw_binary.go
@@ -42,7 +42,7 @@
 
 	properties rawBinaryProperties
 
-	output     android.OutputPath
+	output     android.Path
 	installDir android.InstallPath
 }
 
@@ -71,7 +71,7 @@
 
 func (r *rawBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	inputFile := android.PathForModuleSrc(ctx, proptools.String(r.properties.Src))
-	outputFile := android.PathForModuleOut(ctx, r.installFileName()).OutputPath
+	outputFile := android.PathForModuleOut(ctx, r.installFileName())
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        toRawBinary,
@@ -83,11 +83,11 @@
 		},
 	})
 
-	r.output = outputFile
 	r.installDir = android.PathForModuleInstall(ctx, "etc")
-	ctx.InstallFile(r.installDir, r.installFileName(), r.output)
+	ctx.InstallFile(r.installDir, r.installFileName(), outputFile)
 
-	ctx.SetOutputFiles([]android.Path{r.output}, "")
+	ctx.SetOutputFiles([]android.Path{outputFile}, "")
+	r.output = outputFile
 }
 
 var _ android.AndroidMkEntriesProvider = (*rawBinary)(nil)
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index ebb3ff9..6a47859 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -44,7 +44,7 @@
 
 	properties VbmetaProperties
 
-	output     android.OutputPath
+	output     android.Path
 	installDir android.InstallPath
 }
 
@@ -161,8 +161,6 @@
 const vbmetaMaxSize = 64 * 1024
 
 func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	v.output = android.PathForModuleOut(ctx, v.installFileName()).OutputPath
-
 	builder := android.NewRuleBuilder(pctx, ctx)
 	cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image")
 
@@ -274,18 +272,19 @@
 		cmd.Implicit(publicKey)
 	}
 
-	cmd.FlagWithOutput("--output ", v.output)
+	output := android.PathForModuleOut(ctx, v.installFileName())
+	cmd.FlagWithOutput("--output ", output)
 
 	// libavb expects to be able to read the maximum vbmeta size, so we must provide a partition
 	// which matches this or the read will fail.
 	builder.Command().Text("truncate").
 		FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)).
-		Output(v.output)
+		Output(output)
 
 	builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName()))
 
 	v.installDir = android.PathForModuleInstall(ctx, "etc")
-	ctx.InstallFile(v.installDir, v.installFileName(), v.output)
+	ctx.InstallFile(v.installDir, v.installFileName(), output)
 
 	extractedPublicKey := android.PathForModuleOut(ctx, v.partitionName()+".avbpubkey")
 	ctx.Build(pctx, android.BuildParams{
@@ -300,7 +299,8 @@
 		PublicKey:             extractedPublicKey,
 	})
 
-	ctx.SetOutputFiles([]android.Path{v.output}, "")
+	ctx.SetOutputFiles([]android.Path{output}, "")
+	v.output = output
 }
 
 // Returns the embedded shell command that prints the rollback index
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 2b967f7..d46f679 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -592,8 +592,10 @@
 	}
 
 	baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType)))
-	deps := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps[partitionType]
-	depProps := generateDepStruct(*deps)
+	fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
+	deps := fsGenState.fsDeps[partitionType]
+	highPriorityDeps := fsGenState.generatedPrebuiltEtcModuleNames
+	depProps := generateDepStruct(*deps, highPriorityDeps)
 
 	result, err := proptools.RepackProperties([]interface{}{baseProps, fsProps, depProps})
 	if err != nil {
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 1253f0d..e0e103a 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -66,6 +66,8 @@
 	fsDepsMutex sync.Mutex
 	// Map of _all_ soong module names to their corresponding installation properties
 	moduleToInstallationProps map[string]installationProperties
+	// List of prebuilt_* modules that are autogenerated.
+	generatedPrebuiltEtcModuleNames []string
 }
 
 type installationProperties struct {
@@ -174,8 +176,9 @@
 				},
 				"ramdisk": {},
 			},
-			fsDepsMutex:               sync.Mutex{},
-			moduleToInstallationProps: map[string]installationProperties{},
+			fsDepsMutex:                     sync.Mutex{},
+			moduleToInstallationProps:       map[string]installationProperties{},
+			generatedPrebuiltEtcModuleNames: generatedPrebuiltEtcModuleNames,
 		}
 
 		if avbpubkeyGenerated {
@@ -284,7 +287,7 @@
 	soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions)
 	m := mctx.Module()
 	if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok {
-		depsStruct := generateDepStruct(*fsDeps[partition])
+		depsStruct := generateDepStruct(*fsDeps[partition], fsGenState.generatedPrebuiltEtcModuleNames)
 		if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
 			mctx.ModuleErrorf(err.Error())
 		}
@@ -343,12 +346,12 @@
 	return false
 }
 
-func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct {
+func generateDepStruct(deps map[string]*depCandidateProps, highPriorityDeps []string) *packagingPropsStruct {
 	depsStruct := packagingPropsStruct{}
 	for depName, depProps := range deps {
 		bitness := getBitness(depProps.Arch)
 		fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
-		if isHighPriorityDep(depName) {
+		if android.InList(depName, highPriorityDeps) {
 			depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName)
 		} else if android.InList("32", bitness) && android.InList("64", bitness) {
 			// If both 32 and 64 bit variants are enabled for this module
diff --git a/fsgen/vbmeta_partitions.go b/fsgen/vbmeta_partitions.go
index 52f8ae5..b7fff68 100644
--- a/fsgen/vbmeta_partitions.go
+++ b/fsgen/vbmeta_partitions.go
@@ -53,7 +53,8 @@
 
 	var chainedPartitions []string
 	var partitionTypesHandledByChainedPartitions []string
-	for chainedName, props := range partitionVars.ChainedVbmetaPartitions {
+	for _, chainedName := range android.SortedKeys(partitionVars.ChainedVbmetaPartitions) {
+		props := partitionVars.ChainedVbmetaPartitions[chainedName]
 		chainedName = "vbmeta_" + chainedName
 		if len(props.Partitions) == 0 {
 			continue
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 1282bfb..9d2dbc7 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -115,7 +115,7 @@
 func (t hostToolDependencyTag) AllowDisabledModuleDependencyProxy(
 	ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool {
 	return android.OtherModuleProviderOrDefault(
-		ctx, target, android.CommonPropertiesProviderKey).ReplacedByPrebuilt
+		ctx, target, android.CommonModuleInfoKey).ReplacedByPrebuilt
 }
 
 var _ android.AllowDisabledModuleDependency = (*hostToolDependencyTag)(nil)
@@ -353,7 +353,7 @@
 				if h, ok := android.OtherModuleProvider(ctx, module, android.HostToolProviderKey); ok {
 					// A HostToolProvider provides the path to a tool, which will be copied
 					// into the sandbox.
-					if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonPropertiesProviderKey).Enabled {
+					if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled {
 						if ctx.Config().AllowMissingDependencies() {
 							ctx.AddMissingDependencies([]string{tool})
 						} else {
diff --git a/java/app.go b/java/app.go
index 0939d17..8bb73cb 100644
--- a/java/app.go
+++ b/java/app.go
@@ -848,7 +848,7 @@
 
 	packageName := packageNameProp.Get()
 	fileName := "privapp_allowlist_" + packageName + ".xml"
-	outPath := android.PathForModuleOut(ctx, fileName).OutputPath
+	outPath := android.PathForModuleOut(ctx, fileName)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   modifyAllowlist,
 		Input:  android.PathForModuleSrc(ctx, *a.appProperties.Privapp_allowlist),
@@ -857,7 +857,7 @@
 			"packageName": packageName,
 		},
 	})
-	return &outPath
+	return outPath
 }
 
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/app_import.go b/java/app_import.go
index 6b88f1c..f044c68 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -88,7 +88,7 @@
 
 	hideApexVariantFromMake bool
 
-	provenanceMetaDataFile android.OutputPath
+	provenanceMetaDataFile android.Path
 }
 
 type AndroidAppImportProperties struct {
@@ -259,7 +259,7 @@
 }
 
 func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
-	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
+	ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) {
 	// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
 	// with them may invalidate pre-existing signature data.
 	if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
@@ -345,7 +345,7 @@
 
 	// Uncompress JNI libraries in the apk
 	jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk")
-	a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
+	a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed)
 
 	var pathFragments []string
 	relInstallPath := String(a.properties.Relative_install_path)
@@ -493,7 +493,7 @@
 	return a.certificate
 }
 
-func (a *AndroidAppImport) ProvenanceMetaDataFile() android.OutputPath {
+func (a *AndroidAppImport) ProvenanceMetaDataFile() android.Path {
 	return a.provenanceMetaDataFile
 }
 
diff --git a/java/dex.go b/java/dex.go
index 1f71aee..dea71f5 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -428,17 +428,18 @@
 // Adds --art-profile to r8/d8 command.
 // r8/d8 will output a generated profile file to match the optimized dex code.
 func (d *dexer) addArtProfile(ctx android.ModuleContext, dexParams *compileDexParams) (flags []string, deps android.Paths, artProfileOutputPath *android.OutputPath) {
-	if dexParams.artProfileInput != nil {
-		artProfileInputPath := android.PathForModuleSrc(ctx, *dexParams.artProfileInput)
-		artProfileOutputPathValue := android.PathForModuleOut(ctx, "profile.prof.txt").OutputPath
-		artProfileOutputPath = &artProfileOutputPathValue
-		flags = []string{
-			"--art-profile",
-			artProfileInputPath.String(),
-			artProfileOutputPath.String(),
-		}
-		deps = append(deps, artProfileInputPath)
+	if dexParams.artProfileInput == nil {
+		return nil, nil, nil
 	}
+	artProfileInputPath := android.PathForModuleSrc(ctx, *dexParams.artProfileInput)
+	artProfileOutputPathValue := android.PathForModuleOut(ctx, "profile.prof.txt").OutputPath
+	artProfileOutputPath = &artProfileOutputPathValue
+	flags = []string{
+		"--art-profile",
+		artProfileInputPath.String(),
+		artProfileOutputPath.String(),
+	}
+	deps = append(deps, artProfileInputPath)
 	return flags, deps, artProfileOutputPath
 
 }
diff --git a/java/java.go b/java/java.go
index 078f578..64ef782 100644
--- a/java/java.go
+++ b/java/java.go
@@ -226,9 +226,9 @@
 
 	// Rule for generating device binary default wrapper
 	deviceBinaryWrapper = pctx.StaticRule("deviceBinaryWrapper", blueprint.RuleParams{
-		Command: `echo -e '#!/system/bin/sh\n` +
+		Command: `printf '#!/system/bin/sh\n` +
 			`export CLASSPATH=/system/framework/$jar_name\n` +
-			`exec app_process /$partition/bin $main_class "$$@"'> ${out}`,
+			`exec app_process /$partition/bin $main_class "$$@"\n'> ${out}`,
 		Description: "Generating device binary wrapper ${jar_name}",
 	}, "jar_name", "partition", "main_class")
 )
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 8b0ca97..d09a02e 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -184,7 +184,7 @@
 	}
 	jarArgs := resourcePathsToJarArgs(transitiveSrcFiles)
 	jarArgs = append(jarArgs, "-srcjar") // Move srcfiles to the right package
-	srcjar := android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar").OutputPath
+	srcjar := android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar")
 	TransformResourcesToJar(ctx, srcjar, jarArgs, transitiveSrcFiles)
 
 	// Gather all the fragments dependencies.
diff --git a/java/ravenwood.go b/java/ravenwood.go
index 4c9fdc2..4c43a9f 100644
--- a/java/ravenwood.go
+++ b/java/ravenwood.go
@@ -14,6 +14,8 @@
 package java
 
 import (
+	"strconv"
+
 	"android/soong/android"
 	"android/soong/tradefed"
 
@@ -36,6 +38,14 @@
 var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"}
 var ravenwoodTestInstResourceApkTag = dependencyTag{name: "ravenwoodtest-inst-res-apk"}
 
+var genManifestProperties = pctx.AndroidStaticRule("genManifestProperties",
+	blueprint.RuleParams{
+		Command: "echo targetSdkVersionInt=$targetSdkVersionInt > $out && " +
+			"echo targetSdkVersionRaw=$targetSdkVersionRaw >> $out && " +
+			"echo packageName=$packageName >> $out && " +
+			"echo instPackageName=$instPackageName >> $out",
+	}, "targetSdkVersionInt", "targetSdkVersionRaw", "packageName", "instPackageName")
+
 const ravenwoodUtilsName = "ravenwood-utils"
 const ravenwoodRuntimeName = "ravenwood-runtime"
 
@@ -68,6 +78,17 @@
 	// the ravenwood test can access it. This APK will be loaded as resources of the test
 	// instrumentation app itself.
 	Inst_resource_apk *string
+
+	// Specify the package name of the test target apk.
+	// This will be set to the target Context's package name.
+	// (i.e. Instrumentation.getTargetContext().getPackageName())
+	// If this is omitted, Package_name will be used.
+	Package_name *string
+
+	// Specify the package name of this test module.
+	// This will be set to the test Context's package name.
+	//(i.e. Instrumentation.getContext().getPackageName())
+	Inst_package_name *string
 }
 
 type ravenwoodTest struct {
@@ -216,6 +237,27 @@
 	copyResApk(ravenwoodTestResourceApkTag, "ravenwood-res.apk")
 	copyResApk(ravenwoodTestInstResourceApkTag, "ravenwood-inst-res.apk")
 
+	// Generate manifest properties
+	propertiesOutputPath := android.PathForModuleGen(ctx, "ravenwood.properties")
+
+	targetSdkVersion := proptools.StringDefault(r.deviceProperties.Target_sdk_version, "")
+	targetSdkVersionInt := r.TargetSdkVersion(ctx).FinalOrFutureInt() // FinalOrFutureInt may be 10000.
+	packageName := proptools.StringDefault(r.ravenwoodTestProperties.Package_name, "")
+	instPackageName := proptools.StringDefault(r.ravenwoodTestProperties.Inst_package_name, "")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        genManifestProperties,
+		Description: "genManifestProperties",
+		Output:      propertiesOutputPath,
+		Args: map[string]string{
+			"targetSdkVersionInt": strconv.Itoa(targetSdkVersionInt),
+			"targetSdkVersionRaw": targetSdkVersion,
+			"packageName":         packageName,
+			"instPackageName":     instPackageName,
+		},
+	})
+	installProps := ctx.InstallFile(installPath, "ravenwood.properties", propertiesOutputPath)
+	installDeps = append(installDeps, installProps)
+
 	// Install our JAR with all dependencies
 	ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
 }
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
index 5d62ede..6394a9a 100644
--- a/java/ravenwood_test.go
+++ b/java/ravenwood_test.go
@@ -177,6 +177,12 @@
 			resource_apk: "app2",
 			inst_resource_apk: "app3",
 			sdk_version: "test_current",
+			target_sdk_version: "34",
+			package_name: "a.b.c",
+			inst_package_name: "x.y.z",
+		}
+		android_ravenwood_test {
+			name: "ravenwood-test-empty",
 		}
 	`)
 
@@ -199,12 +205,16 @@
 	// Verify that we've emitted test artifacts in expected location
 	outputJar := module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.jar")
 	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.config")
+	module.Output(installPathPrefix + "/ravenwood-test/ravenwood.properties")
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib1.so")
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so")
 	module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so")
 	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk")
 	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-inst-res.apk")
 
+	module = ctx.ModuleForTests("ravenwood-test-empty", "android_common")
+	module.Output(installPathPrefix + "/ravenwood-test-empty/ravenwood.properties")
+
 	// ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted.
 	for _, o := range module.AllOutputs() {
 		android.AssertStringDoesNotContain(t, "runtime libs shouldn't be included", o, "/ravenwood-test/lib64/ravenwood-runtime")
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index 679632c..c372db2 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -46,7 +46,7 @@
 )
 
 type ProvenanceMetadata interface {
-	ProvenanceMetaDataFile() android.OutputPath
+	ProvenanceMetaDataFile() android.Path
 }
 
 func init() {
@@ -74,7 +74,7 @@
 			return false
 		}
 		if p, ok := module.(ProvenanceMetadata); ok {
-			return p.ProvenanceMetaDataFile().String() != ""
+			return p.ProvenanceMetaDataFile() != nil
 		}
 		return false
 	}
@@ -101,7 +101,7 @@
 	context.Phony("droidcore", android.PathForPhony(context, "provenance_metadata"))
 }
 
-func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) android.OutputPath {
+func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) android.Path {
 	onDevicePathOfInstalledFile := android.InstallPathToOnDevicePath(ctx, installedFile)
 	artifactMetaDataFile := android.PathForIntermediates(ctx, "provenance_metadata", ctx.ModuleDir(), ctx.ModuleName(), "provenance_metadata.textproto")
 	ctx.Build(pctx, android.BuildParams{
diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py
index 0b7780e..5f52d6f 100644
--- a/scripts/gen_build_prop.py
+++ b/scripts/gen_build_prop.py
@@ -608,7 +608,7 @@
         build_product_prop(args)
       case "vendor":
         build_vendor_prop(args)
-      case "system_dlkm" | "vendor_dlkm" | "odm_dlkm":
+      case "system_dlkm" | "vendor_dlkm" | "odm_dlkm" | "bootimage":
         build_prop(args, gen_build_info=False, gen_common_build_props=True, variables=[])
       case _:
         sys.exit(f"not supported partition {args.partition}")
diff --git a/scripts/ninja_determinism_test.py b/scripts/ninja_determinism_test.py
new file mode 100755
index 0000000..e207b96
--- /dev/null
+++ b/scripts/ninja_determinism_test.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+
+import asyncio
+import argparse
+import dataclasses
+import hashlib
+import os
+import re
+import socket
+import subprocess
+import sys
+import zipfile
+
+from typing import List
+
+def get_top() -> str:
+  path = '.'
+  while not os.path.isfile(os.path.join(path, 'build/soong/soong_ui.bash')):
+    if os.path.abspath(path) == '/':
+      sys.exit('Could not find android source tree root.')
+    path = os.path.join(path, '..')
+  return os.path.abspath(path)
+
+
+_PRODUCT_REGEX = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*)(?:(?:-([a-zA-Z_][a-zA-Z0-9_]*))?-(user|userdebug|eng))?')
+
+
+@dataclasses.dataclass(frozen=True)
+class Product:
+  """Represents a TARGET_PRODUCT and TARGET_BUILD_VARIANT."""
+  product: str
+  release: str
+  variant: str
+
+  def __post_init__(self):
+    if not _PRODUCT_REGEX.match(str(self)):
+      raise ValueError(f'Invalid product name: {self}')
+
+  def __str__(self):
+    return self.product + '-' + self.release + '-' + self.variant
+
+
+async def run_make_nothing(product: Product, out_dir: str) -> bool:
+  """Runs a build and returns if it succeeded or not."""
+  with open(os.path.join(out_dir, 'build.log'), 'wb') as f:
+    result = await asyncio.create_subprocess_exec(
+        'prebuilts/build-tools/linux-x86/bin/nsjail',
+        '-q',
+        '--cwd',
+        os.getcwd(),
+        '-e',
+        '-B',
+        '/',
+        '-B',
+        f'{os.path.abspath(out_dir)}:{os.path.join(os.getcwd(), "out")}',
+        '--time_limit',
+        '0',
+        '--skip_setsid',
+        '--keep_caps',
+        '--disable_clone_newcgroup',
+        '--disable_clone_newnet',
+        '--rlimit_as',
+        'soft',
+        '--rlimit_core',
+        'soft',
+        '--rlimit_cpu',
+        'soft',
+        '--rlimit_fsize',
+        'soft',
+        '--rlimit_nofile',
+        'soft',
+        '--proc_rw',
+        '--hostname',
+        socket.gethostname(),
+        '--',
+        'build/soong/soong_ui.bash',
+        '--make-mode',
+        f'TARGET_PRODUCT={product.product}',
+        f'TARGET_RELEASE={product.release}',
+        f'TARGET_BUILD_VARIANT={product.variant}',
+        '--skip-ninja',
+        'nothing', stdout=f, stderr=subprocess.STDOUT)
+    return await result.wait() == 0
+
+SUBNINJA_OR_INCLUDE_REGEX = re.compile(rb'\n(?:include|subninja) ')
+
+def find_subninjas_and_includes(contents) -> List[str]:
+  results = []
+  def get_path_from_directive(i):
+    j = contents.find(b'\n', i)
+    if j < 0:
+      path_bytes = contents[i:]
+    else:
+      path_bytes = contents[i:j]
+    path_bytes = path_bytes.removesuffix(b'\r')
+    path = path_bytes.decode()
+    if '$' in path:
+      sys.exit('includes/subninjas with variables are unsupported: '+path)
+    return path
+
+  if contents.startswith(b"include "):
+    results.append(get_path_from_directive(len(b"include ")))
+  elif contents.startswith(b"subninja "):
+    results.append(get_path_from_directive(len(b"subninja ")))
+
+  for match in SUBNINJA_OR_INCLUDE_REGEX.finditer(contents):
+    results.append(get_path_from_directive(match.end()))
+
+  return results
+
+
+def transitively_included_ninja_files(out_dir: str, ninja_file: str, seen):
+  with open(ninja_file, 'rb') as f:
+    contents = f.read()
+
+  results = [ninja_file]
+  seen[ninja_file] = True
+  sub_files = find_subninjas_and_includes(contents)
+  for sub_file in sub_files:
+    sub_file = os.path.join(out_dir, sub_file.removeprefix('out/'))
+    if sub_file not in seen:
+      results.extend(transitively_included_ninja_files(out_dir, sub_file, seen))
+
+  return results
+
+
+def hash_ninja_file(out_dir: str, ninja_file: str, hasher):
+  with open(ninja_file, 'rb') as f:
+    contents = f.read()
+
+  sub_files = find_subninjas_and_includes(contents)
+
+  hasher.update(contents)
+
+  for sub_file in sub_files:
+    hash_ninja_file(out_dir, os.path.join(out_dir, sub_file.removeprefix('out/')), hasher)
+
+
+def hash_files(files: List[str]) -> str:
+  hasher = hashlib.md5()
+  for file in files:
+    with open(file, 'rb') as f:
+      hasher.update(f.read())
+  return hasher.hexdigest()
+
+
+def dist_ninja_files(out_dir: str, zip_name: str, ninja_files: List[str]):
+  dist_dir = os.getenv('DIST_DIR', os.path.join(os.getenv('OUT_DIR', 'out'), 'dist'))
+  os.makedirs(dist_dir, exist_ok=True)
+
+  with open(os.path.join(dist_dir, zip_name), 'wb') as f:
+    with zipfile.ZipFile(f, mode='w') as zf:
+      for ninja_file in ninja_files:
+        zf.write(ninja_file, arcname=os.path.basename(out_dir)+'/out/' + os.path.relpath(ninja_file, out_dir))
+
+
+async def main():
+    parser = argparse.ArgumentParser()
+    args = parser.parse_args()
+
+    os.chdir(get_top())
+    subprocess.check_call(['touch', 'build/soong/Android.bp'])
+
+    product = Product(
+      'aosp_cf_x86_64_phone',
+      'trunk_staging',
+      'userdebug',
+    )
+    os.environ['TARGET_PRODUCT'] = 'aosp_cf_x86_64_phone'
+    os.environ['TARGET_RELEASE'] = 'trunk_staging'
+    os.environ['TARGET_BUILD_VARIANT'] = 'userdebug'
+
+    out_dir1 = os.path.join(os.getenv('OUT_DIR', 'out'), 'determinism_test_out1')
+    out_dir2 = os.path.join(os.getenv('OUT_DIR', 'out'), 'determinism_test_out2')
+
+    os.makedirs(out_dir1, exist_ok=True)
+    os.makedirs(out_dir2, exist_ok=True)
+
+    success1, success2 = await asyncio.gather(
+      run_make_nothing(product, out_dir1),
+      run_make_nothing(product, out_dir2))
+
+    if not success1:
+      with open(os.path.join(out_dir1, 'build.log'), 'r') as f:
+        print(f.read(), file=sys.stderr)
+      sys.exit('build failed')
+    if not success2:
+      with open(os.path.join(out_dir2, 'build.log'), 'r') as f:
+        print(f.read(), file=sys.stderr)
+      sys.exit('build failed')
+
+    ninja_files1 = transitively_included_ninja_files(out_dir1, os.path.join(out_dir1, f'combined-{product.product}.ninja'), {})
+    ninja_files2 = transitively_included_ninja_files(out_dir2, os.path.join(out_dir2, f'combined-{product.product}.ninja'), {})
+
+    dist_ninja_files(out_dir1, 'determinism_test_files_1.zip', ninja_files1)
+    dist_ninja_files(out_dir2, 'determinism_test_files_2.zip', ninja_files2)
+
+    hash1 = hash_files(ninja_files1)
+    hash2 = hash_files(ninja_files2)
+
+    if hash1 != hash2:
+        sys.exit("ninja files were not deterministic! See disted determinism_test_files_1/2.zip")
+
+    print("Success, ninja files were deterministic")
+
+
+if __name__ == "__main__":
+    asyncio.run(main())
+
+
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 320e97f..7f5a426 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -204,7 +204,7 @@
 func (s *ShBinary) DepsMutator(ctx android.BottomUpMutatorContext) {
 }
 
-func (s *ShBinary) OutputFile() android.OutputPath {
+func (s *ShBinary) OutputFile() android.Path {
 	return s.outputFilePath
 }
 
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index c54d55f..6f57cb1 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -29,6 +29,9 @@
 	"device/google_car/",
 	"device/sample/",
 	"frameworks/",
+	"hardware/libhardware/",
+	"hardware/libhardware_legacy/",
+	"hardware/ril/",
 	// Do not block other directories in kernel/, see b/319658303.
 	"kernel/configs/",
 	"kernel/prebuilts/",
@@ -37,8 +40,10 @@
 	"libnativehelper/",
 	"packages/",
 	"pdk/",
+	"platform_testing/",
 	"prebuilts/",
 	"sdk/",
+	"system/",
 	"test/",
 	"trusty/",
 	// Add back toolchain/ once defensive Android.mk files are removed