diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go index ef92cc871..05449bc6c 100644 --- a/aconfig/codegen/cc_aconfig_library_test.go +++ b/aconfig/codegen/cc_aconfig_library_test.go @@ -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") } diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go index 7361d44c1..85d2675d2 100644 --- a/aconfig/codegen/java_aconfig_library_test.go +++ b/aconfig/codegen/java_aconfig_library_test.go @@ -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") } diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go index 68fff58c1..be9beb1ba 100644 --- a/android/aconfig_providers.go +++ b/android/aconfig_providers.go @@ -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 } diff --git a/android/androidmk.go b/android/androidmk.go index 235d7c0d6..07f7c58d0 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -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 { diff --git a/android/module.go b/android/module.go index 6fd8657ff..5c7bbbf2b 100644 --- a/android/module.go +++ b/android/module.go @@ -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 diff --git a/android/testing.go b/android/testing.go index f88049c6a..7b4411e2f 100644 --- a/android/testing.go +++ b/android/testing.go @@ -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 } diff --git a/apex/androidmk.go b/apex/androidmk.go index bc68ad36b..619be8dc4 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -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()) diff --git a/bpf/bpf.go b/bpf/bpf.go index 32d62b520..e1b512f20 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -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) } diff --git a/phony/phony.go b/phony/phony.go index bb4878899..b8dbd00d0 100644 --- a/phony/phony.go +++ b/phony/phony.go @@ -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)") }, } diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 4a0796bd9..766f3e7dc 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -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")