Generate android_certificate_directory

Previously, partners were required to add an
android_certificate_directory filegroup in their certificate
directories, and allowlist that BUILD file. Now, we generate the
filegroup automatically.

We're using a different name, generated_android_certificate_directory,
to avoid conflicts with already-checked-in filegroups.

Bug: 285777389
Test: b test //build/bazel/rules/apex/...
Change-Id: Ib1bde487acd79d58368faf0aad02ded0bcdaceb4
This commit is contained in:
Cole Faust 2023-09-12 10:07:07 -07:00
parent d753c2e53c
commit 6054cdf3b1
4 changed files with 141 additions and 78 deletions

View file

@ -82,15 +82,25 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics {
os.Exit(1)
}
var bp2buildFiles []BazelFile
productConfig, err := createProductConfigFiles(ctx, res.metrics)
ctx.Context().EventHandler.Do("CreateBazelFile", func() {
bp2buildFiles = CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode)
allTargets := make(map[string]BazelTargets)
for k, v := range res.buildFileToTargets {
allTargets[k] = append(allTargets[k], v...)
}
for k, v := range productConfig.bp2buildTargets {
allTargets[k] = append(allTargets[k], v...)
}
bp2buildFiles = CreateBazelFiles(nil, allTargets, ctx.mode)
})
injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
bp2buildFiles = append(bp2buildFiles, productConfig.bp2buildFiles...)
injectionFiles, err := createSoongInjectionDirFiles(ctx, res.metrics)
if err != nil {
fmt.Printf("%s\n", err.Error())
os.Exit(1)
}
bp2buildFiles = append(bp2buildFiles, additionalBp2buildFiles...)
injectionFiles = append(injectionFiles, productConfig.injectionFiles...)
writeFiles(ctx, bp2buildDir, bp2buildFiles)
// Delete files under the bp2build root which weren't just written. An
// alternative would have been to delete the whole directory and write these
@ -109,26 +119,6 @@ func Codegen(ctx *CodegenContext) *CodegenMetrics {
return &res.metrics
}
// Wrapper function that will be responsible for all files in soong_injection directory
// This includes
// 1. config value(s) that are hardcoded in Soong
// 2. product_config variables
func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
var ret []BazelFile
productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx, metrics)
if err != nil {
return nil, nil, err
}
ret = append(ret, productConfigInjectionFiles...)
injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics)
if err != nil {
return nil, nil, err
}
ret = append(injectionFiles, ret...)
return ret, productConfigBp2BuildDirFiles, nil
}
// Get the output directory and create it if it doesn't exist.
func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
dirPath := outputDir.Join(ctx, dir)

View file

@ -12,14 +12,19 @@ import (
"android/soong/android/soongconfig"
"android/soong/starlark_import"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"go.starlark.net/starlark"
)
func CreateProductConfigFiles(
type createProductConfigFilesResult struct {
injectionFiles []BazelFile
bp2buildFiles []BazelFile
bp2buildTargets map[string]BazelTargets
}
func createProductConfigFiles(
ctx *CodegenContext,
metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
metrics CodegenMetrics) (createProductConfigFilesResult, error) {
cfg := &ctx.config
targetProduct := "unknown"
if cfg.HasDeviceProduct() {
@ -32,29 +37,22 @@ func CreateProductConfigFiles(
targetBuildVariant = "userdebug"
}
var res createProductConfigFilesResult
productVariablesFileName := cfg.ProductVariablesFileName
if !strings.HasPrefix(productVariablesFileName, "/") {
productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName)
}
productVariablesBytes, err := os.ReadFile(productVariablesFileName)
if err != nil {
return nil, nil, err
return res, err
}
productVariables := android.ProductVariables{}
err = json.Unmarshal(productVariablesBytes, &productVariables)
if err != nil {
return nil, nil, err
return res, err
}
// Visit all modules to determine the list of ndk libraries
// This list will be used to add additional flags for cc stub generation
ndkLibsStringFormatted := []string{}
ctx.Context().VisitAllModules(func(m blueprint.Module) {
if ctx.Context().ModuleType(m) == "ndk_library" {
ndkLibsStringFormatted = append(ndkLibsStringFormatted, fmt.Sprintf(`"%s"`, m.Name())) // name will be `"libc.ndk"`
}
})
// TODO(b/249685973): the name is product_config_platforms because product_config
// was already used for other files. Deduplicate them.
currentProductFolder := fmt.Sprintf("product_config_platforms/products/%s-%s", targetProduct, targetBuildVariant)
@ -64,25 +62,36 @@ func CreateProductConfigFiles(
"{VARIANT}", targetBuildVariant,
"{PRODUCT_FOLDER}", currentProductFolder)
platformMappingContent, err := platformMappingContent(
productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"),
&productVariables,
ctx.Config().Bp2buildSoongConfigDefinitions,
metrics.convertedModulePathMap)
if err != nil {
return nil, nil, err
}
productsForTestingMap, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
if err != nil {
return nil, nil, err
return res, err
}
productsForTesting := android.SortedKeys(productsForTestingMap)
for i := range productsForTesting {
productsForTesting[i] = fmt.Sprintf(" \"@//build/bazel/tests/products:%s\",", productsForTesting[i])
}
injectionDirFiles := []BazelFile{
productLabelsToVariables := make(map[string]*android.ProductVariables)
productLabelsToVariables[productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}")] = &productVariables
for product, productVariablesStarlark := range productsForTestingMap {
productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
if err != nil {
return res, err
}
productLabelsToVariables["@//build/bazel/tests/products:"+product] = &productVariables
}
res.bp2buildTargets = createTargets(productLabelsToVariables)
platformMappingContent, err := platformMappingContent(
productLabelsToVariables,
ctx.Config().Bp2buildSoongConfigDefinitions,
metrics.convertedModulePathMap)
if err != nil {
return res, err
}
res.injectionFiles = []BazelFile{
newFile(
currentProductFolder,
"soong.variables.bzl",
@ -164,30 +173,21 @@ build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_lin
productReplacer.Replace(`
build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
`)),
newFile(
"cc_toolchain",
"ndk_libs.bzl",
fmt.Sprintf("ndk_libs = [%v]", strings.Join(ndkLibsStringFormatted, ", ")),
),
}
bp2buildDirFiles := []BazelFile{
res.bp2buildFiles = []BazelFile{
newFile(
"",
"platform_mappings",
platformMappingContent),
}
return injectionDirFiles, bp2buildDirFiles, nil
return res, nil
}
func platformMappingContent(
mainProductLabel string,
mainProductVariables *android.ProductVariables,
productLabelToVariables map[string]*android.ProductVariables,
soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
convertedModulePathMap map[string]string) (string, error) {
productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
if err != nil {
return "", err
}
var result strings.Builder
mergedConvertedModulePathMap := make(map[string]string)
@ -203,13 +203,8 @@ func platformMappingContent(
}
result.WriteString("platforms:\n")
platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
for product, productVariablesStarlark := range productsForTesting {
productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
if err != nil {
return "", err
}
platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
for productLabel, productVariables := range productLabelToVariables {
platformMappingSingleProduct(productLabel, productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
}
return result.String(), nil
}
@ -248,7 +243,7 @@ func platformMappingSingleProduct(
defaultAppCertificateFilegroup := "//build/bazel/utils:empty_filegroup"
if proptools.String(productVariables.DefaultAppCertificate) != "" {
defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":android_certificate_directory"
defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":generated_android_certificate_directory"
}
for _, suffix := range bazelPlatformSuffixes {
@ -419,3 +414,33 @@ func starlarkMapToProductVariables(in map[string]starlark.Value) (android.Produc
return result, nil
}
func createTargets(productLabelsToVariables map[string]*android.ProductVariables) map[string]BazelTargets {
res := make(map[string]BazelTargets)
var allDefaultAppCertificateDirs []string
for _, productVariables := range productLabelsToVariables {
if proptools.String(productVariables.DefaultAppCertificate) != "" {
d := filepath.Dir(proptools.String(productVariables.DefaultAppCertificate))
if !android.InList(d, allDefaultAppCertificateDirs) {
allDefaultAppCertificateDirs = append(allDefaultAppCertificateDirs, d)
}
}
}
for _, dir := range allDefaultAppCertificateDirs {
content := fmt.Sprintf(ruleTargetTemplate, "filegroup", "generated_android_certificate_directory", propsToAttributes(map[string]string{
"srcs": `glob([
"*.pk8",
"*.pem",
"*.avbpubkey",
])`,
"visibility": `["//visibility:public"]`,
}))
res[dir] = append(res[dir], BazelTarget{
name: "generated_android_certificate_directory",
packageName: dir,
content: content,
ruleClass: "filegroup",
})
}
return res
}

View file

@ -15,6 +15,7 @@ import (
rust_config "android/soong/rust/config"
"android/soong/starlark_fmt"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@ -24,16 +25,28 @@ type BazelFile struct {
Contents string
}
// PRIVATE: Use CreateSoongInjectionDirFiles instead
func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) ([]BazelFile, error) {
// createSoongInjectionDirFiles returns most of the files to write to the soong_injection directory.
// Some other files also come from CreateProductConfigFiles
func createSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) {
cfg := ctx.Config()
var files []BazelFile
files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
files = append(files, newFile("android", "constants.bzl", android.BazelCcToolchainVars(cfg)))
// Visit all modules to determine the list of ndk libraries
// This list will be used to add additional flags for cc stub generation
ndkLibsStringFormatted := []string{}
ctx.Context().VisitAllModules(func(m blueprint.Module) {
if ctx.Context().ModuleType(m) == "ndk_library" {
ndkLibsStringFormatted = append(ndkLibsStringFormatted, fmt.Sprintf(`"%s"`, m.Name())) // name will be `"libc.ndk"`
}
})
files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
files = append(files, newFile("cc_toolchain", "config_constants.bzl", cc_config.BazelCcToolchainVars(cfg)))
files = append(files, newFile("cc_toolchain", "sanitizer_constants.bzl", cc.BazelCcSanitizerToolchainVars(cfg)))
files = append(files, newFile("cc_toolchain", "ndk_libs.bzl", fmt.Sprintf("ndk_libs = [%v]", strings.Join(ndkLibsStringFormatted, ", "))))
files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))

View file

@ -83,7 +83,8 @@ func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
files, err := soongInjectionFiles(testConfig, CreateCodegenMetrics())
codegenCtx := NewCodegenContext(testConfig, android.NewTestContext(testConfig).Context, Bp2Build, "")
files, err := createSoongInjectionDirFiles(codegenCtx, CreateCodegenMetrics())
if err != nil {
t.Error(err)
}
@ -104,6 +105,10 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
dir: "cc_toolchain",
basename: "config_constants.bzl",
},
{
dir: "cc_toolchain",
basename: "ndk_libs.bzl",
},
{
dir: "cc_toolchain",
basename: "sanitizer_constants.bzl",
@ -182,15 +187,45 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
},
}
if len(files) != len(expectedFilePaths) {
t.Errorf("Expected %d file, got %d", len(expectedFilePaths), len(files))
less := func(a bazelFilepath, b bazelFilepath) bool {
return a.dir+"/"+a.basename < b.dir+"/"+b.basename
}
for i := range files {
actualFile, expectedFile := files[i], expectedFilePaths[i]
fileToFilepath := func(a BazelFile) bazelFilepath {
return bazelFilepath{basename: a.Basename, dir: a.Dir}
}
if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename {
t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
sort.Slice(expectedFilePaths, func(i, j int) bool {
return less(expectedFilePaths[i], expectedFilePaths[j])
})
sort.Slice(files, func(i, j int) bool {
return less(fileToFilepath(files[i]), fileToFilepath(files[j]))
})
i := 0
j := 0
for i < len(expectedFilePaths) && j < len(files) {
expectedFile, actualFile := expectedFilePaths[i], files[j]
if actualFile.Dir == expectedFile.dir && actualFile.Basename == expectedFile.basename {
i++
j++
} else if less(expectedFile, fileToFilepath(actualFile)) {
t.Errorf("Did not find expected file %s/%s", expectedFile.dir, expectedFile.basename)
i++
} else {
t.Errorf("Found unexpected file %s/%s", actualFile.Dir, actualFile.Basename)
j++
}
}
for i < len(expectedFilePaths) {
expectedFile := expectedFilePaths[i]
t.Errorf("Did not find expected file %s/%s", expectedFile.dir, expectedFile.basename)
i++
}
for j < len(files) {
actualFile := files[j]
t.Errorf("Found unexpected file %s/%s", actualFile.Dir, actualFile.Basename)
j++
}
}