Disallow prebuilt_root module type from setting Dsts property

...to prevent prebuilt_root module type from installing files in
arbitrary locations within the partition.

Test: m nothing --no-skip-soong-tests
Bug: 402903576
Change-Id: I6999c3256668bbe738a38abc4accc05e390511ba
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index e6d50cc..3d1e242 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -103,12 +103,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"`
@@ -147,6 +141,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.
@@ -182,6 +190,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
@@ -372,7 +382,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")
 	}
@@ -579,6 +589,7 @@
 	p.AddProperties(&p.properties)
 	p.AddProperties(&p.subdirProperties)
 	p.AddProperties(&p.rootProperties)
+	p.AddProperties(&p.dstsProperties)
 }
 
 func InitPrebuiltRootModule(p *PrebuiltEtc) {
@@ -590,6 +601,7 @@
 func InitPrebuiltAvbModule(p *PrebuiltEtc) {
 	p.installDirBase = "avb"
 	p.AddProperties(&p.properties)
+	p.AddProperties(&p.dstsProperties)
 	p.rootProperties.Install_in_root = proptools.BoolPtr(true)
 }
 
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
index b47b21e..97c890d 100644
--- a/fsgen/filesystem_creator_test.go
+++ b/fsgen/filesystem_creator_test.go
@@ -349,15 +349,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
@@ -368,15 +378,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/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go
index 0adf7a1..df945b3 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
 
@@ -355,11 +354,14 @@
 				moduleFactory = etc.PrebuiltAnyFactory
 			}
 			modulePropsPtr.Srcs = srcBaseFiles
-			dsts := []string{}
+			dsts := proptools.NewConfigurable[[]string](nil, nil)
 			for _, installBaseFile := range installBaseFiles {
-				dsts = append(dsts, filepath.Join(relDestDirFromInstallDirBase, installBaseFile))
+				dsts.AppendSimpleValue([]string{filepath.Join(relDestDirFromInstallDirBase, installBaseFile)})
 			}
-			modulePropsPtr.Dsts = dsts
+
+			propsList = append(propsList, &etc.PrebuiltDstsProperties{
+				Dsts: dsts,
+			})
 		}
 
 		ctx.CreateModuleInDirectory(moduleFactory, srcDir, propsList...)