Fix few issues with filegroups

Bug: http://b/64121881
Bug: http://b/78188880

- Allow filegroup's properties to be extended by a LoadHook
- Support a filegroup (':module') in a prebuilt's 'Srcs' property to
export files from a different path as the prebuilt's sources.

This change also includes a refactoring that moves genrule/filegroup.go
to android/filegroup.go so that FileGroupFactory is visible in
prebuilt_test.go.

Test: Test
https://android-review.googlesource.com/c/platform/development/+/469159
in clang-tools branch on Linux, Darwin.  Test regular build in
aosp/master.

Change-Id: I3ff6215ab2e62955f039fd1086c31f1bd50ebcf6
diff --git a/android/filegroup.go b/android/filegroup.go
new file mode 100644
index 0000000..b284ce0
--- /dev/null
+++ b/android/filegroup.go
@@ -0,0 +1,94 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"io"
+	"strings"
+	"text/template"
+)
+
+func init() {
+	RegisterModuleType("filegroup", FileGroupFactory)
+}
+
+type fileGroupProperties struct {
+	// srcs lists files that will be included in this filegroup
+	Srcs []string
+
+	Exclude_srcs []string
+
+	// The base path to the files.  May be used by other modules to determine which portion
+	// of the path to use.  For example, when a filegroup is used as data in a cc_test rule,
+	// the base path is stripped off the path and the remaining path is used as the
+	// installation directory.
+	Path *string
+
+	// Create a make variable with the specified name that contains the list of files in the
+	// filegroup, relative to the root of the source tree.
+	Export_to_make_var *string
+}
+
+type fileGroup struct {
+	ModuleBase
+	properties fileGroupProperties
+	srcs       Paths
+}
+
+var _ SourceFileProducer = (*fileGroup)(nil)
+
+// filegroup modules contain a list of files, and can be used to export files across package
+// boundaries.  filegroups (and genrules) can be referenced from srcs properties of other modules
+// using the syntax ":module".
+func FileGroupFactory() Module {
+	module := &fileGroup{}
+	module.AddProperties(&module.properties)
+	InitAndroidModule(module)
+	return module
+}
+
+func (fg *fileGroup) DepsMutator(ctx BottomUpMutatorContext) {
+	ExtractSourcesDeps(ctx, fg.properties.Srcs)
+	ExtractSourcesDeps(ctx, fg.properties.Exclude_srcs)
+}
+
+func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) {
+	fg.srcs = ctx.ExpandSourcesSubDir(fg.properties.Srcs, fg.properties.Exclude_srcs, String(fg.properties.Path))
+}
+
+func (fg *fileGroup) Srcs() Paths {
+	return append(Paths{}, fg.srcs...)
+}
+
+var androidMkTemplate = template.Must(template.New("filegroup").Parse(`
+ifdef {{.makeVar}}
+  $(error variable {{.makeVar}} set by soong module is already set in make)
+endif
+{{.makeVar}} := {{.value}}
+.KATI_READONLY := {{.makeVar}}
+`))
+
+func (fg *fileGroup) AndroidMk() AndroidMkData {
+	return AndroidMkData{
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
+			if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
+				androidMkTemplate.Execute(w, map[string]string{
+					"makeVar": makeVar,
+					"value":   strings.Join(fg.srcs.Strings(), " "),
+				})
+			}
+		},
+	}
+}
diff --git a/android/module.go b/android/module.go
index a011f57..3bd256a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -323,6 +323,7 @@
 		&base.nameProperties,
 		&base.commonProperties,
 		&base.variableProperties)
+	base.customizableProperties = m.GetProperties()
 }
 
 func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 9356aab..47c5cf5 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -59,7 +59,9 @@
 		return nil
 	}
 
-	return PathForModuleSrc(ctx, (*p.srcs)[0])
+	// Return the singleton source after expanding any filegroup in the
+	// sources.
+	return ctx.ExpandSource((*p.srcs)[0], "")
 }
 
 func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
@@ -79,7 +81,7 @@
 
 func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
 	ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
-	ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
+	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
 }
 
 // prebuiltMutator ensures that there is always a module with an undecorated name, and marks
@@ -119,10 +121,12 @@
 	}
 }
 
-// PrebuiltReplaceMutator replaces dependencies on the source module with dependencies on the
-// prebuilt when both modules exist and the prebuilt should be used.  When the prebuilt should not
-// be used, disable installing it.
-func PrebuiltReplaceMutator(ctx BottomUpMutatorContext) {
+// PrebuiltPostDepsMutator does two operations.  It replace dependencies on the
+// source module with dependencies on the prebuilt when both modules exist and
+// the prebuilt should be used.  When the prebuilt should not be used, disable
+// installing it.  Secondly, it also adds a sourcegroup to any filegroups found
+// in the prebuilt's 'Srcs' property.
+func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
 	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
 		p := m.Prebuilt()
 		name := m.base().BaseModuleName()
@@ -133,6 +137,9 @@
 		} else {
 			m.SkipInstall()
 		}
+		if len(*p.srcs) > 0 {
+			ExtractSourceDeps(ctx, &(*p.srcs)[0])
+		}
 	}
 }
 
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index 69ce16a..cd1ffae 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -109,6 +109,19 @@
 			}`,
 		prebuilt: false,
 	},
+	{
+		name: "prebuilt file from filegroup preferred",
+		modules: `
+			filegroup {
+				name: "fg",
+			}
+			prebuilt {
+				name: "bar",
+				prefer: true,
+				srcs: [":fg"],
+			}`,
+		prebuilt: true,
+	},
 }
 
 func TestPrebuilts(t *testing.T) {
@@ -125,6 +138,7 @@
 			ctx := NewTestContext()
 			ctx.PreArchMutators(RegisterPrebuiltsPreArchMutators)
 			ctx.PostDepsMutators(RegisterPrebuiltsPostDepsMutators)
+			ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
 			ctx.RegisterModuleType("prebuilt", ModuleFactoryAdaptor(newPrebuiltModule))
 			ctx.RegisterModuleType("source", ModuleFactoryAdaptor(newSourceModule))
 			ctx.Register()