|  | // 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 aconfig | 
|  |  | 
|  | import ( | 
|  | "android/soong/android" | 
|  | "fmt" | 
|  | "strings" | 
|  |  | 
|  | "github.com/google/blueprint" | 
|  | ) | 
|  |  | 
|  | // Properties for "aconfig_value_set" | 
|  | type ValueSetModule struct { | 
|  | android.ModuleBase | 
|  | android.DefaultableModuleBase | 
|  |  | 
|  | properties struct { | 
|  | // aconfig_values modules | 
|  | Values []string | 
|  |  | 
|  | // Paths to the Android.bp files where the aconfig_values modules are defined. | 
|  | Srcs []string | 
|  | } | 
|  | } | 
|  |  | 
|  | func ValueSetFactory() android.Module { | 
|  | module := &ValueSetModule{} | 
|  |  | 
|  | android.InitAndroidModule(module) | 
|  | android.InitDefaultableModule(module) | 
|  | module.AddProperties(&module.properties) | 
|  |  | 
|  | return module | 
|  | } | 
|  |  | 
|  | // Dependency tag for values property | 
|  | type valueSetType struct { | 
|  | blueprint.BaseDependencyTag | 
|  | } | 
|  |  | 
|  | var valueSetTag = valueSetType{} | 
|  |  | 
|  | // Provider published by aconfig_value_set | 
|  | type valueSetProviderData struct { | 
|  | // The package of each of the | 
|  | // (map of package --> aconfig_module) | 
|  | AvailablePackages map[string]android.Paths | 
|  | } | 
|  |  | 
|  | var valueSetProviderKey = blueprint.NewProvider[valueSetProviderData]() | 
|  |  | 
|  | func (module *ValueSetModule) FindAconfigValuesFromSrc(ctx android.BottomUpMutatorContext) map[string]android.Path { | 
|  | moduleDir := ctx.ModuleDir() | 
|  | srcs := android.PathsForModuleSrcExcludes(ctx, module.properties.Srcs, []string{ctx.BlueprintsFile()}) | 
|  |  | 
|  | aconfigValuesPrefix := strings.Replace(module.Name(), "aconfig_value_set", "aconfig-values", 1) | 
|  | moduleNamesSrcMap := make(map[string]android.Path) | 
|  | for _, src := range srcs { | 
|  | subDir := strings.TrimPrefix(src.String(), moduleDir+"/") | 
|  | packageName, _, found := strings.Cut(subDir, "/") | 
|  | if found { | 
|  | moduleName := fmt.Sprintf("%s-%s-all", aconfigValuesPrefix, packageName) | 
|  | moduleNamesSrcMap[moduleName] = src | 
|  | } | 
|  | } | 
|  | return moduleNamesSrcMap | 
|  | } | 
|  |  | 
|  | func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) { | 
|  |  | 
|  | // TODO: b/366285733 - Replace the file path based solution with more robust solution. | 
|  | aconfigValuesMap := module.FindAconfigValuesFromSrc(ctx) | 
|  | for _, moduleName := range android.SortedKeys(aconfigValuesMap) { | 
|  | if ctx.OtherModuleExists(moduleName) { | 
|  | ctx.AddDependency(ctx.Module(), valueSetTag, moduleName) | 
|  | } else { | 
|  | ctx.ModuleErrorf("module %q not found. Rename the aconfig_values module defined in %q to %q", moduleName, aconfigValuesMap[moduleName], moduleName) | 
|  | } | 
|  | } | 
|  |  | 
|  | deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...) | 
|  | for _, dep := range deps { | 
|  | _, ok := dep.(*ValuesModule) | 
|  | if !ok { | 
|  | ctx.PropertyErrorf("values", "values must be a aconfig_values module") | 
|  | return | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (module *ValueSetModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { | 
|  | // Accumulate the packages of the values modules listed, and set that as an | 
|  | // valueSetProviderKey provider that aconfig modules can read and use | 
|  | // to append values to their aconfig actions. | 
|  | packages := make(map[string]android.Paths) | 
|  | ctx.VisitDirectDeps(func(dep android.Module) { | 
|  | if depData, ok := android.OtherModuleProvider(ctx, dep, valuesProviderKey); ok { | 
|  | srcs := make([]android.Path, len(depData.Values)) | 
|  | copy(srcs, depData.Values) | 
|  | packages[depData.Package] = srcs | 
|  | } | 
|  |  | 
|  | }) | 
|  | android.SetProvider(ctx, valueSetProviderKey, valueSetProviderData{ | 
|  | AvailablePackages: packages, | 
|  | }) | 
|  | } |