2023-12-19 20:01:57 +01:00
|
|
|
// Copyright 2023 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 (
|
2024-01-11 00:42:36 +01:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2024-03-05 01:36:31 +01:00
|
|
|
"maps"
|
2024-01-11 00:42:36 +01:00
|
|
|
"reflect"
|
|
|
|
|
2023-12-19 20:01:57 +01:00
|
|
|
"github.com/google/blueprint"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule",
|
|
|
|
blueprint.RuleParams{
|
|
|
|
Command: `${aconfig} dump --dedup --format protobuf --out $out $flags`,
|
|
|
|
CommandDeps: []string{"${aconfig}"},
|
|
|
|
}, "flags")
|
|
|
|
_ = pctx.HostBinToolVariable("aconfig", "aconfig")
|
|
|
|
)
|
|
|
|
|
|
|
|
// Provider published by aconfig_value_set
|
|
|
|
type AconfigDeclarationsProviderData struct {
|
|
|
|
Package string
|
|
|
|
Container string
|
2024-02-08 07:19:34 +01:00
|
|
|
Exportable bool
|
2023-12-19 20:01:57 +01:00
|
|
|
IntermediateCacheOutputPath WritablePath
|
|
|
|
IntermediateDumpOutputPath WritablePath
|
|
|
|
}
|
|
|
|
|
|
|
|
var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]()
|
|
|
|
|
2024-03-05 01:36:31 +01:00
|
|
|
type ModeInfo struct {
|
|
|
|
Container string
|
|
|
|
Mode string
|
|
|
|
}
|
|
|
|
type CodegenInfo struct {
|
|
|
|
// AconfigDeclarations is the name of the aconfig_declarations modules that
|
|
|
|
// the codegen module is associated with
|
|
|
|
AconfigDeclarations []string
|
|
|
|
|
|
|
|
// Paths to the cache files of the associated aconfig_declaration modules
|
|
|
|
IntermediateCacheOutputPaths Paths
|
|
|
|
|
|
|
|
// Paths to the srcjar files generated from the java_aconfig_library modules
|
|
|
|
Srcjars Paths
|
|
|
|
|
|
|
|
ModeInfos map[string]ModeInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]()
|
|
|
|
|
|
|
|
func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) {
|
|
|
|
if len(from) > 0 {
|
|
|
|
depTag := ctx.OtherModuleDependencyTag(module)
|
|
|
|
if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() {
|
|
|
|
maps.Copy(to, from)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-11 00:42:36 +01:00
|
|
|
type aconfigPropagatingDeclarationsInfo struct {
|
|
|
|
AconfigFiles map[string]Paths
|
2024-03-05 01:36:31 +01:00
|
|
|
ModeInfos map[string]ModeInfo
|
2024-01-11 00:42:36 +01:00
|
|
|
}
|
|
|
|
|
2024-05-07 03:22:19 +02:00
|
|
|
var AconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
|
2024-01-11 00:42:36 +01:00
|
|
|
|
2024-03-05 01:36:31 +01:00
|
|
|
func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) {
|
2024-05-07 03:22:19 +02:00
|
|
|
if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
|
2024-03-05 01:36:31 +01:00
|
|
|
for k, v := range dep.ModeInfos {
|
|
|
|
msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n",
|
|
|
|
module.Name(), container, k, v.Container, v.Mode)
|
|
|
|
if v.Container != container && v.Mode != "exported" && v.Mode != "force-read-only" {
|
|
|
|
if asError {
|
|
|
|
ctx.ModuleErrorf(msg)
|
|
|
|
} else {
|
|
|
|
fmt.Printf("WARNING: " + msg)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if !asError {
|
|
|
|
fmt.Printf("PASSED: " + msg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-11 00:42:36 +01:00
|
|
|
func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
|
|
|
|
mergedAconfigFiles := make(map[string]Paths)
|
2024-03-05 01:36:31 +01:00
|
|
|
mergedModeInfos := make(map[string]ModeInfo)
|
|
|
|
|
2024-01-11 00:42:36 +01:00
|
|
|
ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
|
2024-03-05 01:36:31 +01:00
|
|
|
if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
|
|
|
|
maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
|
|
|
|
}
|
|
|
|
|
2024-01-11 00:42:36 +01:00
|
|
|
// 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)
|
|
|
|
}
|
2024-05-07 03:22:19 +02:00
|
|
|
if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
|
2024-01-11 00:42:36 +01:00
|
|
|
for container, v := range dep.AconfigFiles {
|
|
|
|
mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
|
|
|
|
}
|
2024-03-05 01:36:31 +01:00
|
|
|
propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos)
|
2024-01-11 00:42:36 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
// We only need to set the provider if we have aconfig files.
|
|
|
|
if len(mergedAconfigFiles) > 0 {
|
2024-03-28 22:22:37 +01:00
|
|
|
for _, container := range SortedKeys(mergedAconfigFiles) {
|
|
|
|
aconfigFiles := mergedAconfigFiles[container]
|
2024-01-11 00:42:36 +01:00
|
|
|
mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
|
|
|
|
}
|
|
|
|
|
2024-05-07 03:22:19 +02:00
|
|
|
SetProvider(ctx, AconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
|
2024-01-11 00:42:36 +01:00
|
|
|
AconfigFiles: mergedAconfigFiles,
|
2024-03-05 01:36:31 +01:00
|
|
|
ModeInfos: mergedModeInfos,
|
2024-01-11 00:42:36 +01:00
|
|
|
})
|
2024-05-07 07:32:14 +02:00
|
|
|
ctx.Module().base().aconfigFilePaths = getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)
|
2024-01-11 00:42:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
|
2024-05-07 03:22:19 +02:00
|
|
|
info, ok := SingletonModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
|
2024-01-11 00:42:36 +01:00
|
|
|
// 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
|
|
|
|
}
|
2024-05-07 03:22:19 +02:00
|
|
|
info, ok := SingletonModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
|
2024-01-11 00:42:36 +01:00
|
|
|
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) {
|
2024-05-07 03:22:19 +02:00
|
|
|
entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles))
|
2024-01-11 00:42:36 +01:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
|
2024-02-05 20:27:06 +01:00
|
|
|
inputs = SortedUniquePaths(inputs)
|
2023-12-19 20:01:57 +01:00
|
|
|
if len(inputs) == 1 {
|
|
|
|
return Paths{inputs[0]}
|
|
|
|
}
|
|
|
|
|
2024-01-11 00:07:35 +01:00
|
|
|
output := PathForModuleOut(ctx, container, "aconfig_merged.pb")
|
2023-12-19 20:01:57 +01:00
|
|
|
|
2024-01-11 00:42:36 +01:00
|
|
|
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 "),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
2023-12-19 20:01:57 +01:00
|
|
|
|
|
|
|
return Paths{output}
|
|
|
|
}
|
2024-01-09 23:53:52 +01:00
|
|
|
|
2024-01-11 00:42:36 +01:00
|
|
|
func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Paths) {
|
2024-01-09 23:53:52 +01:00
|
|
|
// TODO(b/311155208): The default container here should be system.
|
2024-01-11 00:42:36 +01:00
|
|
|
container := "system"
|
2024-01-09 23:53:52 +01:00
|
|
|
|
|
|
|
if m.SocSpecific() {
|
|
|
|
container = "vendor"
|
|
|
|
} else if m.ProductSpecific() {
|
|
|
|
container = "product"
|
|
|
|
} else if m.SystemExtSpecific() {
|
|
|
|
container = "system_ext"
|
|
|
|
}
|
|
|
|
|
2024-01-11 00:42:36 +01:00
|
|
|
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
|
2024-01-09 23:53:52 +01:00
|
|
|
}
|