Validate aconfig libs are built with the correct modes.
Bug: 323071835
Test: Unit tests and manual tests.
Change-Id: I32de90826c7c8bb4d8495608e959d554820ab9a2
diff --git a/aconfig/codegen/aconfig_declarations_group.go b/aconfig/codegen/aconfig_declarations_group.go
index 203b6be..1c91bee 100644
--- a/aconfig/codegen/aconfig_declarations_group.go
+++ b/aconfig/codegen/aconfig_declarations_group.go
@@ -15,9 +15,10 @@
package codegen
import (
- "android/soong/aconfig"
- "android/soong/android"
"fmt"
+ "maps"
+
+ "android/soong/android"
"github.com/google/blueprint"
)
@@ -43,6 +44,7 @@
aconfigDeclarationNames []string
intermediateCacheOutputPaths android.Paths
javaSrcjars android.Paths
+ modeInfos map[string]android.ModeInfo
}
type AconfigDeclarationsGroupProperties struct {
@@ -76,9 +78,10 @@
}
func (adg *AconfigDeclarationsGroup) VisitDeps(ctx android.ModuleContext) {
+ adg.modeInfos = make(map[string]android.ModeInfo)
ctx.VisitDirectDeps(func(dep android.Module) {
tag := ctx.OtherModuleDependencyTag(dep)
- if provider, ok := android.OtherModuleProvider(ctx, dep, aconfig.CodegenInfoProvider); ok {
+ if provider, ok := android.OtherModuleProvider(ctx, dep, android.CodegenInfoProvider); ok {
// aconfig declaration names and cache files are collected for all aconfig library dependencies
adg.aconfigDeclarationNames = append(adg.aconfigDeclarationNames, provider.AconfigDeclarations...)
@@ -88,8 +91,14 @@
case aconfigDeclarationsGroupTag:
// Will retrieve outputs from another language codegen modules when support is added
adg.javaSrcjars = append(adg.javaSrcjars, provider.Srcjars...)
+ maps.Copy(adg.modeInfos, provider.ModeInfos)
case javaAconfigLibraryTag:
adg.javaSrcjars = append(adg.javaSrcjars, provider.Srcjars...)
+ maps.Copy(adg.modeInfos, provider.ModeInfos)
+ case ccAconfigLibraryTag:
+ maps.Copy(adg.modeInfos, provider.ModeInfos)
+ case rustAconfigLibraryTag:
+ maps.Copy(adg.modeInfos, provider.ModeInfos)
}
}
})
@@ -100,10 +109,11 @@
adg.aconfigDeclarationNames = android.FirstUniqueStrings(adg.aconfigDeclarationNames)
adg.intermediateCacheOutputPaths = android.FirstUniquePaths(adg.intermediateCacheOutputPaths)
- android.SetProvider(ctx, aconfig.CodegenInfoProvider, aconfig.CodegenInfo{
+ android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
AconfigDeclarations: adg.aconfigDeclarationNames,
IntermediateCacheOutputPaths: adg.intermediateCacheOutputPaths,
Srcjars: adg.javaSrcjars,
+ ModeInfos: adg.modeInfos,
})
}
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
index 50cd4de..80e4926 100644
--- a/aconfig/codegen/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -146,4 +146,12 @@
"mode": mode,
},
})
+
+ android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
+ ModeInfos: map[string]android.ModeInfo{
+ ctx.ModuleName(): {
+ Container: declarations.Container,
+ Mode: mode,
+ }},
+ })
}
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index 3d15ac9..1378dfe 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -17,7 +17,6 @@
import (
"fmt"
- "android/soong/aconfig"
"android/soong/android"
"android/soong/java"
@@ -119,10 +118,15 @@
module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "")
}
- android.SetProvider(ctx, aconfig.CodegenInfoProvider, aconfig.CodegenInfo{
+ android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
AconfigDeclarations: []string{declarationsModules[0].Name()},
IntermediateCacheOutputPaths: android.Paths{declarations.IntermediateCacheOutputPath},
Srcjars: android.Paths{srcJarPath},
+ ModeInfos: map[string]android.ModeInfo{
+ ctx.ModuleName(): {
+ Container: declarations.Container,
+ Mode: mode,
+ }},
})
return srcJarPath
diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
index 2ab54b6..3f7495b 100644
--- a/aconfig/codegen/rust_aconfig_library.go
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -85,6 +85,15 @@
},
})
a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
+
+ android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
+ ModeInfos: map[string]android.ModeInfo{
+ ctx.ModuleName(): {
+ Container: declarations.Container,
+ Mode: mode,
+ }},
+ })
+
return generatedSource
}
diff --git a/aconfig/init.go b/aconfig/init.go
index e64429f..4625128 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -20,20 +20,6 @@
"github.com/google/blueprint"
)
-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 android.Paths
-
- // Paths to the srcjar files generated from the java_aconfig_library modules
- Srcjars android.Paths
-}
-
-var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]()
-
var (
pctx = android.NewPackageContext("android/soong/aconfig")
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index 74c1a5e..fcc57e1 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -17,6 +17,7 @@
import (
"fmt"
"io"
+ "maps"
"reflect"
"github.com/google/blueprint"
@@ -50,6 +51,35 @@
var AconfigTransitiveDeclarationsInfoProvider = blueprint.NewProvider[AconfigTransitiveDeclarationsInfo]()
+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)
+ }
+ }
+}
+
// 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) {
@@ -90,13 +120,40 @@
type aconfigPropagatingDeclarationsInfo struct {
AconfigFiles map[string]Paths
+ ModeInfos map[string]ModeInfo
}
var aconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
+func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) {
+ if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
+ 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)
+ }
+ }
+ }
+ }
+}
+
func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
mergedAconfigFiles := make(map[string]Paths)
+ mergedModeInfos := make(map[string]ModeInfo)
+
ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
+ if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
+ maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
+ }
+
// 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)
@@ -105,6 +162,7 @@
for container, v := range dep.AconfigFiles {
mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
}
+ propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos)
}
if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
for container, v := range dep.AconfigFiles {
@@ -120,6 +178,7 @@
SetProvider(ctx, aconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
AconfigFiles: mergedAconfigFiles,
+ ModeInfos: mergedModeInfos,
})
}
}
diff --git a/android/config.go b/android/config.go
index 936d1d3..951aed1 100644
--- a/android/config.go
+++ b/android/config.go
@@ -18,7 +18,6 @@
// product variables necessary for soong_build's operation.
import (
- "android/soong/shared"
"encoding/json"
"fmt"
"os"
@@ -30,6 +29,8 @@
"sync"
"unicode"
+ "android/soong/shared"
+
"github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/pathtools"
@@ -1932,6 +1933,10 @@
return c.config.productVariables.GenerateAidlNdkPlatformBackend
}
+func (c *deviceConfig) AconfigContainerValidation() string {
+ return c.config.productVariables.AconfigContainerValidation
+}
+
func (c *config) IgnorePrefer32OnDevice() bool {
return c.productVariables.IgnorePrefer32OnDevice
}
diff --git a/android/deptag.go b/android/deptag.go
index a15443b..c7ba4d3 100644
--- a/android/deptag.go
+++ b/android/deptag.go
@@ -43,3 +43,15 @@
}
return false
}
+
+type PropagateAconfigValidationDependencyTag interface {
+ PropagateAconfigValidation() bool
+}
+
+type AlwaysPropagateAconfigValidationDependencyTag struct{}
+
+func (p AlwaysPropagateAconfigValidationDependencyTag) PropagateAconfigValidation() bool {
+ return true
+}
+
+var _ PropagateAconfigValidationDependencyTag = AlwaysPropagateAconfigValidationDependencyTag{}
diff --git a/android/module.go b/android/module.go
index b615ff5..000476c 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,7 +15,6 @@
package android
import (
- "android/soong/bazel"
"crypto/md5"
"encoding/hex"
"encoding/json"
@@ -27,6 +26,8 @@
"sort"
"strings"
+ "android/soong/bazel"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -2087,6 +2088,7 @@
// caused by prebuilt_ prefix, or fully qualified module names.
type sourceOrOutputDependencyTag struct {
blueprint.BaseDependencyTag
+ AlwaysPropagateAconfigValidationDependencyTag
// The name of the module.
moduleName string
diff --git a/android/variable.go b/android/variable.go
index be3c80d..73f5bfd 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -500,6 +500,8 @@
HiddenapiExportableStubs *bool `json:",omitempty"`
ExportRuntimeApis *bool `json:",omitempty"`
+
+ AconfigContainerValidation string `json:",omitempty"`
}
type PartitionQualifiedVariablesType struct {
diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go
new file mode 100644
index 0000000..be98d45
--- /dev/null
+++ b/apex/aconfig_test.go
@@ -0,0 +1,550 @@
+// Copyright 2024 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 apex
+
+import (
+ "testing"
+
+ "android/soong/aconfig/codegen"
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/genrule"
+ "android/soong/java"
+ "android/soong/rust"
+ "github.com/google/blueprint/proptools"
+)
+
+var withAconfigValidationError = android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.AconfigContainerValidation = "error"
+ variables.BuildId = proptools.StringPtr("TEST.BUILD_ID")
+})
+
+func TestValidationAcrossContainersExportedPass(t *testing.T) {
+ testCases := []struct {
+ name string
+ bp string
+ }{
+ {
+ name: "Java lib passes for exported containers cross",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ java_libs: [
+ "my_java_library_foo",
+ ],
+ updatable: false,
+ }
+ java_library {
+ name: "my_java_library_foo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: ["my_java_aconfig_library_foo"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["foo.aconfig"],
+ exportable: true,
+ }
+ java_aconfig_library {
+ name: "my_java_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ mode: "exported",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ },
+ {
+ name: "Android app passes for exported containers cross",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ apps: [
+ "my_android_app_foo",
+ ],
+ updatable: false,
+ }
+ android_app {
+ name: "my_android_app_foo",
+ srcs: ["foo/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ stl: "none",
+ static_libs: ["my_java_library_bar"],
+ apex_available: [ "myapex" ],
+ }
+ java_library {
+ name: "my_java_library_bar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: ["my_java_aconfig_library_bar"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_bar",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["bar.aconfig"],
+ exportable: true,
+ }
+ java_aconfig_library {
+ name: "my_java_aconfig_library_bar",
+ aconfig_declarations: "my_aconfig_declarations_bar",
+ mode: "exported",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ },
+ {
+ name: "Cc lib passes for exported containers cross",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ native_shared_libs: [
+ "my_cc_library_bar",
+ ],
+ binaries: [
+ "my_cc_binary_baz",
+ ],
+ updatable: false,
+ }
+ cc_library {
+ name: "my_cc_library_bar",
+ srcs: ["foo/bar/MyClass.cc"],
+ static_libs: [
+ "my_cc_aconfig_library_bar",
+ "my_cc_aconfig_library_baz",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ cc_binary {
+ name: "my_cc_binary_baz",
+ srcs: ["foo/bar/MyClass.cc"],
+ static_libs: ["my_cc_aconfig_library_baz"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ cc_library {
+ name: "server_configurable_flags",
+ srcs: ["server_configurable_flags.cc"],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_bar",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["bar.aconfig"],
+ exportable: true,
+ }
+ cc_aconfig_library {
+ name: "my_cc_aconfig_library_bar",
+ aconfig_declarations: "my_aconfig_declarations_bar",
+ apex_available: [
+ "myapex",
+ ],
+ mode: "exported",
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_baz",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["baz.aconfig"],
+ exportable: true,
+ }
+ cc_aconfig_library {
+ name: "my_cc_aconfig_library_baz",
+ aconfig_declarations: "my_aconfig_declarations_baz",
+ apex_available: [
+ "myapex",
+ ],
+ mode: "exported",
+ }`,
+ },
+ }
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ cc.PrepareForTestWithCcBuildComponents,
+ rust.PrepareForTestWithRustDefaultModules,
+ codegen.PrepareForTestWithAconfigBuildComponents,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ withAconfigValidationError,
+ ).
+ RunTestWithBp(t, test.bp)
+ })
+ }
+}
+
+func TestValidationAcrossContainersNotExportedFail(t *testing.T) {
+ testCases := []struct {
+ name string
+ expectedError string
+ bp string
+ }{
+ {
+ name: "Java lib fails for non-exported containers cross",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ java_libs: [
+ "my_java_library_foo",
+ ],
+ updatable: false,
+ }
+ java_library {
+ name: "my_java_library_foo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: ["my_java_aconfig_library_foo"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["foo.aconfig"],
+ }
+ java_aconfig_library {
+ name: "my_java_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ expectedError: `.*my_java_library_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
+ },
+ {
+ name: "Android app fails for non-exported containers cross",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ apps: [
+ "my_android_app_foo",
+ ],
+ updatable: false,
+ }
+ android_app {
+ name: "my_android_app_foo",
+ srcs: ["foo/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ stl: "none",
+ static_libs: ["my_java_library_foo"],
+ apex_available: [ "myapex" ],
+ }
+ java_library {
+ name: "my_java_library_foo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: ["my_java_aconfig_library_foo"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["bar.aconfig"],
+ }
+ java_aconfig_library {
+ name: "my_java_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
+ },
+ {
+ name: "Cc lib fails for non-exported containers cross",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ native_shared_libs: [
+ "my_cc_library_foo",
+ ],
+ updatable: false,
+ }
+ cc_library {
+ name: "my_cc_library_foo",
+ srcs: ["foo/bar/MyClass.cc"],
+ shared_libs: [
+ "my_cc_aconfig_library_foo",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ cc_library {
+ name: "server_configurable_flags",
+ srcs: ["server_configurable_flags.cc"],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["foo.aconfig"],
+ }
+ cc_aconfig_library {
+ name: "my_cc_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ expectedError: `.*my_cc_library_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`,
+ },
+ {
+ name: "Cc binary fails for non-exported containers cross",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ binaries: [
+ "my_cc_binary_foo",
+ ],
+ updatable: false,
+ }
+ cc_library {
+ name: "my_cc_library_foo",
+ srcs: ["foo/bar/MyClass.cc"],
+ static_libs: [
+ "my_cc_aconfig_library_foo",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ cc_binary {
+ name: "my_cc_binary_foo",
+ srcs: ["foo/bar/MyClass.cc"],
+ static_libs: ["my_cc_library_foo"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ cc_library {
+ name: "server_configurable_flags",
+ srcs: ["server_configurable_flags.cc"],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["foo.aconfig"],
+ }
+ cc_aconfig_library {
+ name: "my_cc_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ expectedError: `.*my_cc_binary_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`,
+ },
+ {
+ name: "Aconfig validation propagate along sourceOrOutputDependencyTag",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ apps: [
+ "my_android_app_foo",
+ ],
+ updatable: false,
+ }
+ android_app {
+ name: "my_android_app_foo",
+ srcs: ["foo/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ stl: "none",
+ static_libs: ["my_java_library_foo"],
+ apex_available: [ "myapex" ],
+ }
+ java_library {
+ name: "my_java_library_foo",
+ srcs: [":my_genrule_foo"],
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [
+ "myapex",
+ ],
+ }
+ aconfig_declarations_group {
+ name: "my_aconfig_declarations_group_foo",
+ java_aconfig_libraries: [
+ "my_java_aconfig_library_foo",
+ ],
+ }
+ filegroup {
+ name: "my_filegroup_foo_srcjars",
+ srcs: [
+ ":my_aconfig_declarations_group_foo{.srcjars}",
+ ],
+ }
+ genrule {
+ name: "my_genrule_foo",
+ srcs: [":my_filegroup_foo_srcjars"],
+ cmd: "cp $(in) $(out)",
+ out: ["my_genrule_foo.srcjar"],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["bar.aconfig"],
+ }
+ java_aconfig_library {
+ name: "my_java_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
+ },
+ }
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ errorHandler := android.FixtureExpectsNoErrors
+ if test.expectedError != "" {
+ errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError)
+ }
+ android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ cc.PrepareForTestWithCcBuildComponents,
+ rust.PrepareForTestWithRustDefaultModules,
+ codegen.PrepareForTestWithAconfigBuildComponents,
+ genrule.PrepareForIntegrationTestWithGenrule,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ withAconfigValidationError,
+ ).
+ ExtendWithErrorHandler(errorHandler).
+ RunTestWithBp(t, test.bp)
+ })
+ }
+}
+
+func TestValidationNotPropagateAcrossShared(t *testing.T) {
+ testCases := []struct {
+ name string
+ bp string
+ }{
+ {
+ name: "Java shared lib not propagate aconfig validation",
+ bp: apex_default_bp + `
+ apex {
+ name: "myapex",
+ manifest: ":myapex.manifest",
+ androidManifest: ":myapex.androidmanifest",
+ key: "myapex.key",
+ java_libs: [
+ "my_java_library_bar",
+ ],
+ updatable: false,
+ }
+ java_library {
+ name: "my_java_library_bar",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ libs: ["my_java_library_foo"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ java_library {
+ name: "my_java_library_foo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ static_libs: ["my_java_aconfig_library_foo"],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ aconfig_declarations {
+ name: "my_aconfig_declarations_foo",
+ package: "com.example.package",
+ container: "otherapex",
+ srcs: ["foo.aconfig"],
+ }
+ java_aconfig_library {
+ name: "my_java_aconfig_library_foo",
+ aconfig_declarations: "my_aconfig_declarations_foo",
+ apex_available: [
+ "myapex",
+ ],
+ }`,
+ },
+ }
+ for _, test := range testCases {
+ t.Run(test.name, func(t *testing.T) {
+ android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ cc.PrepareForTestWithCcBuildComponents,
+ rust.PrepareForTestWithRustDefaultModules,
+ codegen.PrepareForTestWithAconfigBuildComponents,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ withAconfigValidationError,
+ ).
+ RunTestWithBp(t, test.bp)
+ })
+ }
+}
diff --git a/apex/apex.go b/apex/apex.go
index 9d7af18..d0b3986 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2321,9 +2321,15 @@
}
func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) {
- dep, _ := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider)
- if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
- vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
+ if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider); ok {
+ if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
+ vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
+ }
+ }
+
+ validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
+ if validationFlag == "error" || validationFlag == "warning" {
+ android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), module, validationFlag == "error")
}
}
diff --git a/cc/cc.go b/cc/cc.go
index 2770fb2..0fa3457 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -766,6 +766,12 @@
var _ android.InstallNeededDependencyTag = libraryDependencyTag{}
+func (d libraryDependencyTag) PropagateAconfigValidation() bool {
+ return d.static()
+}
+
+var _ android.PropagateAconfigValidationDependencyTag = libraryDependencyTag{}
+
// dependencyTag is used for tagging miscellaneous dependency types that don't fit into
// libraryDependencyTag. Each tag object is created globally and reused for multiple
// dependencies (although since the object contains no references, assigning a tag to a
diff --git a/java/base.go b/java/base.go
index f11e30d..c5f22d2 100644
--- a/java/base.go
+++ b/java/base.go
@@ -26,7 +26,6 @@
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
- "android/soong/aconfig"
"android/soong/android"
"android/soong/dexpreopt"
"android/soong/java/config"
@@ -2546,7 +2545,7 @@
default:
return RenameUseExclude, "srcfile"
}
- } else if _, ok := android.OtherModuleProvider(ctx, m, aconfig.CodegenInfoProvider); ok {
+ } else if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok {
return RenameUseInclude, "aconfig_declarations_group"
} else {
switch tag {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 6a66f45..aec40b3 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -21,7 +21,6 @@
"github.com/google/blueprint/proptools"
- "android/soong/aconfig"
"android/soong/android"
"android/soong/java/config"
)
@@ -414,7 +413,7 @@
case aconfigDeclarationTag:
if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey); ok {
deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPath)
- } else if dep, ok := android.OtherModuleProvider(ctx, module, aconfig.CodegenInfoProvider); ok {
+ } else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
} else {
ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+
diff --git a/java/java.go b/java/java.go
index 794020d..4b99672 100644
--- a/java/java.go
+++ b/java/java.go
@@ -24,7 +24,6 @@
"sort"
"strings"
- "android/soong/aconfig"
"android/soong/remoteexec"
"android/soong/testing"
@@ -346,6 +345,12 @@
return j.kytheFiles
}
+func (d dependencyTag) PropagateAconfigValidation() bool {
+ return d.static
+}
+
+var _ android.PropagateAconfigValidationDependencyTag = dependencyTag{}
+
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
@@ -355,6 +360,8 @@
// True if the dependency is a toolchain, for example an annotation processor.
toolchain bool
+
+ static bool
}
// installDependencyTag is a dependency tag that is annotated to cause the installed files of the
@@ -400,7 +407,7 @@
var (
dataNativeBinsTag = dependencyTag{name: "dataNativeBins"}
dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
- staticLibTag = dependencyTag{name: "staticlib"}
+ staticLibTag = dependencyTag{name: "staticlib", static: true}
libTag = dependencyTag{name: "javalib", runtimeLinked: true}
sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true}
java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true}
@@ -2172,7 +2179,7 @@
case aconfigDeclarationTag:
if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPath)
- } else if provider, ok := android.OtherModuleProvider(ctx, dep, aconfig.CodegenInfoProvider); ok {
+ } else if provider, ok := android.OtherModuleProvider(ctx, dep, android.CodegenInfoProvider); ok {
al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPaths...)
} else {
ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+