Validate aconfig libs are built with the correct modes.
Bug: 323071835
Test: Unit tests and manual tests.
Change-Id: I32de90826c7c8bb4d8495608e959d554820ab9a2
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")
}
}