Propagate AconfigFiles in ModuleBase.

Aconfig file dependencies are module-independent, and properly part of
ModuleBase.

Bug: b/308625757
Test: manual

Change-Id: I38c5907d1671cc69bb198345201316ae781fdc9f
This commit is contained in:
LaMont Jones 2024-01-10 23:42:36 +00:00
parent dbc88dc4d0
commit b509938e4f
10 changed files with 164 additions and 17 deletions

View file

@ -163,7 +163,6 @@ func TestAndroidMkCcLibrary(t *testing.T) {
entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 1, len(makeVar))
android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb")
}

View file

@ -60,7 +60,6 @@ func runJavaAndroidMkTest(t *testing.T, bp string) {
entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 1, len(makeVar))
android.EnsureListContainsSuffix(t, makeVar, "android_common/aconfig_merged.pb")
}

View file

@ -15,6 +15,10 @@
package android
import (
"fmt"
"io"
"reflect"
"github.com/google/blueprint"
)
@ -45,6 +49,8 @@ type AconfigTransitiveDeclarationsInfo struct {
var AconfigTransitiveDeclarationsInfoProvider = blueprint.NewProvider[AconfigTransitiveDeclarationsInfo]()
// CollectDependencyAconfigFiles is used by some module types to provide finer dependency graphing than
// we can do in ModuleBase.
func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[string]Paths) {
if *mergedAconfigFiles == nil {
*mergedAconfigFiles = make(map[string]Paths)
@ -54,7 +60,14 @@ func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[st
(*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
return
}
if dep, _ := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); len(dep.AconfigFiles) > 0 {
if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
for container, v := range dep.AconfigFiles {
(*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
}
}
// We process these last, so that they determine the final value, eliminating any duplicates that we picked up
// from UpdateAndroidBuildActions.
if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
for container, v := range dep.AconfigFiles {
(*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
}
@ -62,7 +75,7 @@ func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[st
})
for container, aconfigFiles := range *mergedAconfigFiles {
(*mergedAconfigFiles)[container] = mergeAconfigFiles(ctx, container, aconfigFiles)
(*mergedAconfigFiles)[container] = mergeAconfigFiles(ctx, container, aconfigFiles, false)
}
SetProvider(ctx, AconfigTransitiveDeclarationsInfoProvider, AconfigTransitiveDeclarationsInfo{
@ -70,7 +83,94 @@ func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[st
})
}
func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths) Paths {
func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
setAconfigFileMkEntries(m, entries, aconfigFiles)
}
type aconfigPropagatingDeclarationsInfo struct {
AconfigFiles map[string]Paths
}
var aconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
mergedAconfigFiles := make(map[string]Paths)
ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
// If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them.
if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
}
if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
for container, v := range dep.AconfigFiles {
mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
}
}
if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
for container, v := range dep.AconfigFiles {
mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
}
}
})
// We only need to set the provider if we have aconfig files.
if len(mergedAconfigFiles) > 0 {
for container, aconfigFiles := range mergedAconfigFiles {
mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
}
SetProvider(ctx, aconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
AconfigFiles: mergedAconfigFiles,
})
}
}
func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
// If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done.
if !ok || len(info.AconfigFiles) == 0 {
return
}
data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
AndroidMkEmitAssignList(w, "LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles).Strings())
})
// If there is a Custom writer, it needs to support this provider.
if data.Custom != nil {
switch reflect.TypeOf(mod).String() {
case "*aidl.aidlApi": // writes non-custom before adding .phony
case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
case "*apex.apexBundle": // aconfig_file properties written
case "*bpf.bpf": // properties written (both for module and objs)
case "*genrule.Module": // writes non-custom before adding .phony
case "*java.SystemModules": // doesn't go through base_rules
case "*phony.phony": // properties written
case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
case "*sysprop.syspropLibrary": // properties written
default:
panic(fmt.Errorf("custom make rules do not handle aconfig files for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), mod))
}
}
}
func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries *[]AndroidMkEntries) {
// If there are no entries, then we can ignore this module, even if it has aconfig files.
if len(*entries) == 0 {
return
}
info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
if !ok || len(info.AconfigFiles) == 0 {
return
}
// All of the files in the module potentially depend on the aconfig flag values.
for idx, _ := range *entries {
(*entries)[idx].ExtraEntries = append((*entries)[idx].ExtraEntries,
func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
setAconfigFileMkEntries(mod.base(), entries, info.AconfigFiles)
},
)
}
}
func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
inputs = LastUniquePaths(inputs)
if len(inputs) == 1 {
return Paths{inputs[0]}
@ -78,22 +178,28 @@ func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths) Paths
output := PathForModuleOut(ctx, container, "aconfig_merged.pb")
ctx.Build(pctx, BuildParams{
Rule: mergeAconfigFilesRule,
Description: "merge aconfig files",
Inputs: inputs,
Output: output,
Args: map[string]string{
"flags": JoinWithPrefix(inputs.Strings(), "--cache "),
},
})
if generateRule {
ctx.Build(pctx, BuildParams{
Rule: mergeAconfigFilesRule,
Description: "merge aconfig files",
Inputs: inputs,
Output: output,
Args: map[string]string{
"flags": JoinWithPrefix(inputs.Strings(), "--cache "),
},
})
}
return Paths{output}
}
func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
func setAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(m, aconfigFiles))
}
func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Paths) {
// TODO(b/311155208): The default container here should be system.
container := ""
container := "system"
if m.SocSpecific() {
container = "vendor"
@ -103,5 +209,18 @@ func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFi
container = "system_ext"
}
entries.SetPaths("LOCAL_ACONFIG_FILES", aconfigFiles[container])
paths = append(paths, aconfigFiles[container]...)
if container == "system" {
// TODO(b/311155208): Once the default container is system, we can drop this.
paths = append(paths, aconfigFiles[""]...)
}
if container != "system" {
if len(aconfigFiles[container]) == 0 && len(aconfigFiles[""]) > 0 {
// TODO(b/308625757): Either we guessed the container wrong, or the flag is misdeclared.
// For now, just include the system (aka "") container if we get here.
//fmt.Printf("container_mismatch: module=%v container=%v files=%v\n", m, container, aconfigFiles)
}
paths = append(paths, aconfigFiles[""]...)
}
return
}

View file

@ -859,6 +859,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *
}
data.fillInData(ctx, mod)
aconfigUpdateAndroidMkData(ctx, mod.(Module), &data)
prefix := ""
if amod.ArchSpecific() {
@ -943,6 +944,7 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleIn
}
entriesList := provider.AndroidMkEntries()
aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList)
// Any new or special cases here need review to verify correct propagation of license information.
for _, entries := range entriesList {

View file

@ -1777,6 +1777,11 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
return
}
aconfigUpdateAndroidBuildActions(ctx)
if ctx.Failed() {
return
}
// Create the set of tagged dist files after calling GenerateAndroidBuildActions
// as GenerateTaggedDistFiles() calls OutputFiles(tag) and so relies on the
// output paths being set which must be done before or during

View file

@ -1121,6 +1121,7 @@ func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Modul
}
entriesList := p.AndroidMkEntries()
aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList)
for i, _ := range entriesList {
entriesList[i].fillInEntries(ctx, mod)
}
@ -1136,6 +1137,7 @@ func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module)
}
data := p.AndroidMk()
data.fillInData(ctx, mod)
aconfigUpdateAndroidMkData(ctx, mod.(Module), &data)
return data
}

View file

@ -124,6 +124,10 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st
pathForSymbol := filepath.Join("$(PRODUCT_OUT)", "apex", apexBundleName, fi.installDir)
modulePath := pathForSymbol
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
// AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
for _, extra := range apexAndroidMkData.Extra {
extra(w, fi.builtFile)
}
// For non-flattend APEXes, the merged notice file is attached to the APEX itself.
// We don't need to have notice file for the individual modules in it. Otherwise,
@ -229,6 +233,7 @@ func (a *apexBundle) writeRequiredModules(w io.Writer, moduleNames []string) {
func (a *apexBundle) androidMkForType() android.AndroidMkData {
return android.AndroidMkData{
// While we do not provide a value for `Extra`, AconfigUpdateAndroidMkData may add some, which we must honor.
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
moduleNames := []string{}
if a.installable() {
@ -269,6 +274,10 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData {
android.AndroidMkEmitAssignList(w, "LOCAL_OVERRIDES_MODULES", a.overridableProperties.Overrides)
a.writeRequiredModules(w, moduleNames)
// AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
for _, extra := range data.Extra {
extra(w, a.outputFile)
}
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String())

View file

@ -231,6 +231,10 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData {
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
fmt.Fprintln(w, localModulePath)
// AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
for _, extra := range data.Extra {
extra(w, nil)
}
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
fmt.Fprintln(w)
}

View file

@ -68,6 +68,10 @@ func (p *phony) AndroidMk() android.AndroidMkData {
fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=",
strings.Join(p.targetRequiredModuleNames, " "))
}
// AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
for _, extra := range data.Extra {
extra(w, nil)
}
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
},
}

View file

@ -345,6 +345,10 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData {
fmt.Fprintln(w, "LOCAL_MODULE :=", m.Name())
fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n")
fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n")
// AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
for _, extra := range data.Extra {
extra(w, nil)
}
fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n")
fmt.Fprintf(w, "$(LOCAL_BUILT_MODULE): %s\n", m.checkApiFileTimeStamp.String())
fmt.Fprintf(w, "\ttouch $@\n\n")