diff --git a/apex/Android.bp b/apex/Android.bp index abae9e261..17fdfc36a 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -37,6 +37,7 @@ bootstrap_go_package { "apex_test.go", "bootclasspath_fragment_test.go", "classpath_element_test.go", + "container_test.go", "dexpreopt_bootjars_test.go", "platform_bootclasspath_test.go", "systemserver_classpath_fragment_test.go", diff --git a/apex/container_test.go b/apex/container_test.go new file mode 100644 index 000000000..39311741d --- /dev/null +++ b/apex/container_test.go @@ -0,0 +1,329 @@ +// 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 ( + "android/soong/android" + "android/soong/java" + "fmt" + "testing" +) + +var checkContainerMatch = func(t *testing.T, name string, container string, expected bool, actual bool) { + errorMessage := fmt.Sprintf("module %s container %s value differ", name, container) + android.AssertBoolEquals(t, errorMessage, expected, actual) +} + +func TestApexDepsContainers(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForApexTest, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.FixtureWithLastReleaseApis("mybootclasspathlib"), + ).RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: [ + "mybootclasspathfragment", + ], + updatable: true, + min_sdk_version: "30", + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: [ + "mybootclasspathlib", + ], + apex_available: [ + "myapex", + ], + hidden_api: { + split_packages: ["*"], + }, + } + java_sdk_library { + name: "mybootclasspathlib", + srcs: [ + "mybootclasspathlib.java", + ], + apex_available: [ + "myapex", + ], + compile_dex: true, + static_libs: [ + "foo", + "baz", + ], + libs: [ + "bar", + ], + min_sdk_version: "30", + } + java_library { + name: "foo", + srcs:[ + "A.java", + ], + apex_available: [ + "myapex", + ], + min_sdk_version: "30", + } + java_library { + name: "bar", + srcs:[ + "A.java", + ], + min_sdk_version: "30", + } + java_library { + name: "baz", + srcs:[ + "A.java", + ], + apex_available: [ + "//apex_available:platform", + "myapex", + ], + min_sdk_version: "30", + } + `) + testcases := []struct { + moduleName string + variant string + isSystemContainer bool + isApexContainer bool + }{ + { + moduleName: "mybootclasspathlib", + variant: "android_common_myapex", + isSystemContainer: true, + isApexContainer: true, + }, + { + moduleName: "mybootclasspathlib.impl", + variant: "android_common_apex30", + isSystemContainer: true, + isApexContainer: true, + }, + { + moduleName: "mybootclasspathlib.stubs", + variant: "android_common", + isSystemContainer: true, + isApexContainer: false, + }, + { + moduleName: "foo", + variant: "android_common_apex30", + isSystemContainer: true, + isApexContainer: true, + }, + { + moduleName: "bar", + variant: "android_common", + isSystemContainer: true, + isApexContainer: false, + }, + { + moduleName: "baz", + variant: "android_common_apex30", + isSystemContainer: true, + isApexContainer: true, + }, + } + + for _, c := range testcases { + m := result.ModuleForTests(c.moduleName, c.variant) + containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider) + belongingContainers := containers.BelongingContainers() + checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers)) + checkContainerMatch(t, c.moduleName, "apex", c.isApexContainer, android.InList(android.ApexContainer, belongingContainers)) + } +} + +func TestNonUpdatableApexDepsContainers(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForApexTest, + java.PrepareForTestWithJavaSdkLibraryFiles, + java.FixtureWithLastReleaseApis("mybootclasspathlib"), + ).RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + bootclasspath_fragments: [ + "mybootclasspathfragment", + ], + updatable: false, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + bootclasspath_fragment { + name: "mybootclasspathfragment", + contents: [ + "mybootclasspathlib", + ], + apex_available: [ + "myapex", + ], + hidden_api: { + split_packages: ["*"], + }, + } + java_sdk_library { + name: "mybootclasspathlib", + srcs: [ + "mybootclasspathlib.java", + ], + apex_available: [ + "myapex", + ], + compile_dex: true, + static_libs: [ + "foo", + ], + libs: [ + "bar", + ], + } + java_library { + name: "foo", + srcs:[ + "A.java", + ], + apex_available: [ + "myapex", + ], + } + java_library { + name: "bar", + srcs:[ + "A.java", + ], + } + `) + testcases := []struct { + moduleName string + variant string + isSystemContainer bool + isApexContainer bool + }{ + { + moduleName: "mybootclasspathlib", + variant: "android_common_myapex", + isSystemContainer: true, + isApexContainer: true, + }, + { + moduleName: "mybootclasspathlib.impl", + variant: "android_common_apex10000", + isSystemContainer: true, + isApexContainer: true, + }, + { + moduleName: "mybootclasspathlib.stubs", + variant: "android_common", + isSystemContainer: true, + isApexContainer: false, + }, + { + moduleName: "foo", + variant: "android_common_apex10000", + isSystemContainer: true, + isApexContainer: true, + }, + { + moduleName: "bar", + variant: "android_common", + isSystemContainer: true, + isApexContainer: false, + }, + } + + for _, c := range testcases { + m := result.ModuleForTests(c.moduleName, c.variant) + containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider) + belongingContainers := containers.BelongingContainers() + checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers)) + checkContainerMatch(t, c.moduleName, "apex", c.isApexContainer, android.InList(android.ApexContainer, belongingContainers)) + } +} + +func TestUpdatableAndNonUpdatableApexesIdenticalMinSdkVersion(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForApexTest, + java.PrepareForTestWithJavaSdkLibraryFiles, + android.FixtureMergeMockFs(android.MockFS{ + "system/sepolicy/apex/myapex_non_updatable-file_contexts": nil, + "system/sepolicy/apex/myapex_updatable-file_contexts": nil, + }), + ).RunTestWithBp(t, ` + apex { + name: "myapex_non_updatable", + key: "myapex_non_updatable.key", + java_libs: [ + "foo", + ], + updatable: false, + min_sdk_version: "30", + } + apex_key { + name: "myapex_non_updatable.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + apex { + name: "myapex_updatable", + key: "myapex_updatable.key", + java_libs: [ + "foo", + ], + updatable: true, + min_sdk_version: "30", + } + apex_key { + name: "myapex_updatable.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + java_library { + name: "foo", + srcs:[ + "A.java", + ], + apex_available: [ + "myapex_non_updatable", + "myapex_updatable", + ], + min_sdk_version: "30", + sdk_version: "current", + } + `) + + fooApexVariant := result.ModuleForTests("foo", "android_common_apex30") + containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), fooApexVariant.Module(), android.ContainersInfoProvider) + belongingContainers := containers.BelongingContainers() + checkContainerMatch(t, "foo", "system", true, android.InList(android.SystemContainer, belongingContainers)) + checkContainerMatch(t, "foo", "apex", true, android.InList(android.ApexContainer, belongingContainers)) +} diff --git a/java/Android.bp b/java/Android.bp index 54b36ab60..a941754db 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -87,6 +87,7 @@ bootstrap_go_package { "app_set_test.go", "app_test.go", "code_metadata_test.go", + "container_test.go", "bootclasspath_fragment_test.go", "device_host_converter_test.go", "dex_test.go", diff --git a/java/base.go b/java/base.go index ee8df3e76..ad79e986d 100644 --- a/java/base.go +++ b/java/base.go @@ -552,6 +552,18 @@ type Module struct { aconfigCacheFiles android.Paths } +var _ android.InstallableModule = (*Module)(nil) + +// To satisfy the InstallableModule interface +func (j *Module) EnforceApiContainerChecks() bool { + return true +} + +// Overrides android.ModuleBase.InstallInProduct() +func (j *Module) InstallInProduct() bool { + return j.ProductSpecific() +} + func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { sdkVersion := j.SdkVersion(ctx) if sdkVersion.Stable() { diff --git a/java/container_test.go b/java/container_test.go new file mode 100644 index 000000000..344185553 --- /dev/null +++ b/java/container_test.go @@ -0,0 +1,129 @@ +// 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 java + +import ( + "android/soong/android" + "fmt" + "testing" +) + +var checkContainerMatch = func(t *testing.T, name string, container string, expected bool, actual bool) { + errorMessage := fmt.Sprintf("module %s container %s value differ", name, container) + android.AssertBoolEquals(t, errorMessage, expected, actual) +} + +func TestJavaContainersModuleProperties(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + ).RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["A.java"], + } + java_library { + name: "foo_vendor", + srcs: ["A.java"], + vendor: true, + sdk_version: "current", + } + java_library { + name: "foo_soc_specific", + srcs: ["A.java"], + soc_specific: true, + sdk_version: "current", + } + java_library { + name: "foo_product_specific", + srcs: ["A.java"], + product_specific: true, + sdk_version: "current", + } + java_test { + name: "foo_cts_test", + srcs: ["A.java"], + test_suites: [ + "cts", + ], + } + java_test { + name: "foo_non_cts_test", + srcs: ["A.java"], + test_suites: [ + "general-tests", + ], + } + `) + + testcases := []struct { + moduleName string + isSystemContainer bool + isVendorContainer bool + isProductContainer bool + isCts bool + }{ + { + moduleName: "foo", + isSystemContainer: true, + isVendorContainer: false, + isProductContainer: false, + isCts: false, + }, + { + moduleName: "foo_vendor", + isSystemContainer: false, + isVendorContainer: true, + isProductContainer: false, + isCts: false, + }, + { + moduleName: "foo_soc_specific", + isSystemContainer: false, + isVendorContainer: true, + isProductContainer: false, + isCts: false, + }, + { + moduleName: "foo_product_specific", + isSystemContainer: false, + isVendorContainer: false, + isProductContainer: true, + isCts: false, + }, + { + moduleName: "foo_cts_test", + isSystemContainer: false, + isVendorContainer: false, + isProductContainer: false, + isCts: true, + }, + { + moduleName: "foo_non_cts_test", + isSystemContainer: false, + isVendorContainer: false, + isProductContainer: false, + isCts: false, + }, + } + + for _, c := range testcases { + m := result.ModuleForTests(c.moduleName, "android_common") + containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider) + belongingContainers := containers.BelongingContainers() + checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers)) + checkContainerMatch(t, c.moduleName, "vendor", c.isVendorContainer, android.InList(android.VendorContainer, belongingContainers)) + checkContainerMatch(t, c.moduleName, "product", c.isProductContainer, android.InList(android.ProductContainer, belongingContainers)) + } +}