Introduce module type to autogenerate RROS

At ToT, soong emits metadata to make (LOCAL_SOONG_PRODUCT_RRO_DIRS and
LOCAL_SOONG_DEVICE_RRO_DIRS), and make uses this metadata to build and
install apks that are intalled in /vendor or /product. This CL ports
this logic to soong using a new module type. The module type will have a
dependency on the base module (e.g. SystemUI). This dependency edge will
be used to get information such as
- rroDirsDepSet
- manifest (to get package_name)

To reduce code duplication, `aaptBuildActions` has been extended to
accept a manifest and rroDirs parameter.

This should be a no op for now. The followup work includes
- Autogenerating these module in the load hook of android_app and
  override_android_app
- Including the autogenerated modules in kati built img files
- Including the autogenerated modules in soong built img files

Test: go test ./java
Bug: 375277835
Change-Id: Icd34f59eb751ba60db3c265acada946e20db5f26
diff --git a/java/rro.go b/java/rro.go
index f225e1f..d277e4a 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -20,6 +20,7 @@
 import (
 	"android/soong/android"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -29,6 +30,7 @@
 
 func RegisterRuntimeResourceOverlayBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory)
+	ctx.RegisterModuleType("autogen_runtime_resource_overlay", AutogenRuntimeResourceOverlayFactory)
 	ctx.RegisterModuleType("override_runtime_resource_overlay", OverrideRuntimeResourceOverlayModuleFactory)
 }
 
@@ -269,3 +271,145 @@
 	android.InitOverrideModule(m)
 	return m
 }
+
+var (
+	generateOverlayManifestFile = pctx.AndroidStaticRule("generate_overlay_manifest",
+		blueprint.RuleParams{
+			Command: "build/make/tools/generate-enforce-rro-android-manifest.py " +
+				"--package-info $in " +
+				"--partition ${partition} " +
+				"--priority ${priority} -o $out",
+			CommandDeps: []string{"build/make/tools/generate-enforce-rro-android-manifest.py"},
+		}, "partition", "priority",
+	)
+)
+
+type AutogenRuntimeResourceOverlay struct {
+	android.ModuleBase
+	aapt
+
+	properties AutogenRuntimeResourceOverlayProperties
+
+	outputFile android.Path
+}
+
+type AutogenRuntimeResourceOverlayProperties struct {
+	Base        *string
+	Sdk_version *string
+	Manifest    *string `android:"path"`
+}
+
+func AutogenRuntimeResourceOverlayFactory() android.Module {
+	m := &AutogenRuntimeResourceOverlay{}
+	m.AddProperties(&m.properties)
+	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+
+	return m
+}
+
+type rroDependencyTag struct {
+	blueprint.DependencyTag
+}
+
+// Autogenerated RROs should always depend on the source android_app that created it.
+func (tag rroDependencyTag) ReplaceSourceWithPrebuilt() bool {
+	return false
+}
+
+var rroDepTag = rroDependencyTag{}
+
+func (a *AutogenRuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
+	sdkDep := decodeSdkDep(ctx, android.SdkContext(a))
+	if sdkDep.hasFrameworkLibs() {
+		a.aapt.deps(ctx, sdkDep)
+	}
+	ctx.AddDependency(ctx.Module(), rroDepTag, proptools.String(a.properties.Base))
+}
+
+func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if !a.Enabled(ctx) {
+		return
+	}
+	var rroDirs android.Paths
+	// Get rro dirs of the base app
+	ctx.VisitDirectDepsWithTag(rroDepTag, func(m android.Module) {
+		aarDep, _ := m.(AndroidLibraryDependency)
+		if ctx.InstallInProduct() {
+			rroDirs = filterRRO(aarDep.RRODirsDepSet(), product)
+		} else {
+			rroDirs = filterRRO(aarDep.RRODirsDepSet(), device)
+		}
+	})
+
+	if len(rroDirs) == 0 {
+		return
+	}
+
+	// Generate a manifest file
+	genManifest := android.PathForModuleGen(ctx, "AndroidManifest.xml")
+	partition := "vendor"
+	priority := "0"
+	if ctx.InstallInProduct() {
+		partition = "product"
+		priority = "1"
+	}
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   generateOverlayManifestFile,
+		Input:  android.PathForModuleSrc(ctx, proptools.String(a.properties.Manifest)),
+		Output: genManifest,
+		Args: map[string]string{
+			"partition": partition,
+			"priority":  priority,
+		},
+	})
+
+	// Compile and link resources into package-res.apk
+	a.aapt.hasNoCode = true
+	aaptLinkFlags := []string{"--auto-add-overlay", "--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
+
+	a.aapt.buildActions(ctx,
+		aaptBuildActionOptions{
+			sdkContext:      a,
+			extraLinkFlags:  aaptLinkFlags,
+			rroDirs:         &rroDirs,
+			manifestForAapt: genManifest,
+		},
+	)
+
+	if a.exportPackage == nil {
+		return
+	}
+	// Sign the built package
+	_, certificates := processMainCert(a.ModuleBase, "", nil, ctx)
+	signed := android.PathForModuleOut(ctx, "signed", a.Name()+".apk")
+	SignAppPackage(ctx, signed, a.exportPackage, certificates, nil, nil, "")
+	a.outputFile = signed
+
+	// Install the signed apk
+	installDir := android.PathForModuleInstall(ctx, "overlay")
+	ctx.InstallFile(installDir, signed.Base(), signed)
+}
+
+func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
+	return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version))
+}
+
+func (a *AutogenRuntimeResourceOverlay) SystemModules() string {
+	return ""
+}
+
+func (a *AutogenRuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return a.SdkVersion(ctx).ApiLevel
+}
+
+func (r *AutogenRuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
+	return android.SdkSpecPrivate.ApiLevel
+}
+
+func (a *AutogenRuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	return a.SdkVersion(ctx).ApiLevel
+}
+
+func (a *AutogenRuntimeResourceOverlay) InstallInProduct() bool {
+	return a.ProductSpecific()
+}