Merge changes I861a60e1,I01bf99fa,I9d16dfec into main am: 9678733731
am: fd440d75e5
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/3150116 Change-Id: I612cdbb3292da68820d7c2446fdba939112a28fc Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -42,6 +42,7 @@ bootstrap_go_package {
|
||||
"buildinfo_prop.go",
|
||||
"compliance_metadata.go",
|
||||
"config.go",
|
||||
"container.go",
|
||||
"test_config.go",
|
||||
"configurable_properties.go",
|
||||
"configured_jars.go",
|
||||
|
233
android/container.go
Normal file
233
android/container.go
Normal file
@@ -0,0 +1,233 @@
|
||||
// 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 android
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
type StubsAvailableModule interface {
|
||||
IsStubsModule() bool
|
||||
}
|
||||
|
||||
// Returns true if the dependency module is a stubs module
|
||||
var depIsStubsModule = func(_ ModuleContext, _, dep Module) bool {
|
||||
if stubsModule, ok := dep.(StubsAvailableModule); ok {
|
||||
return stubsModule.IsStubsModule()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Labels of exception functions, which are used to determine special dependencies that allow
|
||||
// otherwise restricted inter-container dependencies
|
||||
type exceptionHandleFuncLabel int
|
||||
|
||||
const (
|
||||
checkStubs exceptionHandleFuncLabel = iota
|
||||
)
|
||||
|
||||
// Functions cannot be used as a value passed in providers, because functions are not
|
||||
// hashable. As a workaround, the exceptionHandleFunc enum values are passed using providers,
|
||||
// and the corresponding functions are called from this map.
|
||||
var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]func(ModuleContext, Module, Module) bool{
|
||||
checkStubs: depIsStubsModule,
|
||||
}
|
||||
|
||||
type InstallableModule interface {
|
||||
EnforceApiContainerChecks() bool
|
||||
}
|
||||
|
||||
type restriction struct {
|
||||
// container of the dependency
|
||||
dependency *container
|
||||
|
||||
// Error message to be emitted to the user when the dependency meets this restriction
|
||||
errorMessage string
|
||||
|
||||
// List of labels of allowed exception functions that allows bypassing this restriction.
|
||||
// If any of the functions mapped to each labels returns true, this dependency would be
|
||||
// considered allowed and an error will not be thrown.
|
||||
allowedExceptions []exceptionHandleFuncLabel
|
||||
}
|
||||
type container struct {
|
||||
// The name of the container i.e. partition, api domain
|
||||
name string
|
||||
|
||||
// Map of dependency restricted containers.
|
||||
restricted []restriction
|
||||
}
|
||||
|
||||
var (
|
||||
VendorContainer = &container{
|
||||
name: VendorVariation,
|
||||
restricted: nil,
|
||||
}
|
||||
SystemContainer = &container{
|
||||
name: "system",
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: VendorContainer,
|
||||
errorMessage: "Module belonging to the system partition other than HALs is " +
|
||||
"not allowed to depend on the vendor partition module, in order to support " +
|
||||
"independent development/update cycles and to support the Generic System " +
|
||||
"Image. Try depending on HALs, VNDK or AIDL instead.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{},
|
||||
},
|
||||
},
|
||||
}
|
||||
ProductContainer = &container{
|
||||
name: ProductVariation,
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: VendorContainer,
|
||||
errorMessage: "Module belonging to the product partition is not allowed to " +
|
||||
"depend on the vendor partition module, as this may lead to security " +
|
||||
"vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{},
|
||||
},
|
||||
},
|
||||
}
|
||||
ApexContainer = initializeApexContainer()
|
||||
CtsContainer = &container{
|
||||
name: "cts",
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: SystemContainer,
|
||||
errorMessage: "CTS module should not depend on the modules belonging to the " +
|
||||
"system partition, including \"framework\". Depending on the system " +
|
||||
"partition may lead to disclosure of implementation details and regression " +
|
||||
"due to API changes across platform versions. Try depending on the stubs instead.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func initializeApexContainer() *container {
|
||||
apexContainer := &container{
|
||||
name: "apex",
|
||||
restricted: []restriction{
|
||||
{
|
||||
dependency: SystemContainer,
|
||||
errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
|
||||
"modules belonging to the system partition. Either statically depend on the " +
|
||||
"module or convert the depending module to java_sdk_library and depend on " +
|
||||
"the stubs.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
apexContainer.restricted = append(apexContainer.restricted, restriction{
|
||||
dependency: apexContainer,
|
||||
errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
|
||||
"modules belonging to other Apex(es). Either include the depending " +
|
||||
"module in the Apex or convert the depending module to java_sdk_library " +
|
||||
"and depend on its stubs.",
|
||||
allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
|
||||
})
|
||||
|
||||
return apexContainer
|
||||
}
|
||||
|
||||
type ContainersInfo struct {
|
||||
belongingContainers []*container
|
||||
|
||||
belongingApexes []ApexInfo
|
||||
}
|
||||
|
||||
func (c *ContainersInfo) BelongingContainers() []*container {
|
||||
return c.belongingContainers
|
||||
}
|
||||
|
||||
var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
|
||||
|
||||
// Determines if the module can be installed in the system partition or not.
|
||||
// Logic is identical to that of modulePartition(...) defined in paths.go
|
||||
func installInSystemPartition(ctx ModuleContext) bool {
|
||||
module := ctx.Module()
|
||||
return !module.InstallInTestcases() &&
|
||||
!module.InstallInData() &&
|
||||
!module.InstallInRamdisk() &&
|
||||
!module.InstallInVendorRamdisk() &&
|
||||
!module.InstallInDebugRamdisk() &&
|
||||
!module.InstallInRecovery() &&
|
||||
!module.InstallInVendor() &&
|
||||
!module.InstallInOdm() &&
|
||||
!module.InstallInProduct() &&
|
||||
determineModuleKind(module.base(), ctx.blueprintBaseModuleContext()) == platformModule
|
||||
}
|
||||
|
||||
func generateContainerInfo(ctx ModuleContext) ContainersInfo {
|
||||
inSystem := installInSystemPartition(ctx)
|
||||
inProduct := ctx.Module().InstallInProduct()
|
||||
inVendor := ctx.Module().InstallInVendor()
|
||||
inCts := false
|
||||
inApex := false
|
||||
|
||||
if m, ok := ctx.Module().(ImageInterface); ok {
|
||||
inProduct = inProduct || m.ProductVariantNeeded(ctx)
|
||||
inVendor = inVendor || m.VendorVariantNeeded(ctx)
|
||||
}
|
||||
|
||||
props := ctx.Module().GetProperties()
|
||||
for _, prop := range props {
|
||||
val := reflect.ValueOf(prop).Elem()
|
||||
if val.Kind() == reflect.Struct {
|
||||
testSuites := val.FieldByName("Test_suites")
|
||||
if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
|
||||
inCts = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var belongingApexes []ApexInfo
|
||||
if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
|
||||
belongingApexes = apexInfo.ApexInfos
|
||||
inApex = true
|
||||
}
|
||||
|
||||
containers := []*container{}
|
||||
if inSystem {
|
||||
containers = append(containers, SystemContainer)
|
||||
}
|
||||
if inProduct {
|
||||
containers = append(containers, ProductContainer)
|
||||
}
|
||||
if inVendor {
|
||||
containers = append(containers, VendorContainer)
|
||||
}
|
||||
if inCts {
|
||||
containers = append(containers, CtsContainer)
|
||||
}
|
||||
if inApex {
|
||||
containers = append(containers, ApexContainer)
|
||||
}
|
||||
|
||||
return ContainersInfo{
|
||||
belongingContainers: containers,
|
||||
belongingApexes: belongingApexes,
|
||||
}
|
||||
}
|
||||
|
||||
func setContainerInfo(ctx ModuleContext) {
|
||||
if _, ok := ctx.Module().(InstallableModule); ok {
|
||||
containersInfo := generateContainerInfo(ctx)
|
||||
SetProvider(ctx, ContainersInfoProvider, containersInfo)
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@ type ImageInterface interface {
|
||||
// VendorVariantNeeded should return true if the module needs a vendor variant (installed on the vendor image).
|
||||
VendorVariantNeeded(ctx BaseModuleContext) bool
|
||||
|
||||
// ProductVariantNeeded should return true if the module needs a product variant (unstalled on the product image).
|
||||
// ProductVariantNeeded should return true if the module needs a product variant (installed on the product image).
|
||||
ProductVariantNeeded(ctx BaseModuleContext) bool
|
||||
|
||||
// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
|
||||
|
@@ -1779,6 +1779,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
|
||||
variables: make(map[string]string),
|
||||
}
|
||||
|
||||
setContainerInfo(ctx)
|
||||
|
||||
m.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic")
|
||||
|
||||
dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx)
|
||||
|
@@ -201,6 +201,12 @@ func ListSetDifference[T comparable](l1, l2 []T) (bool, []T, []T) {
|
||||
return listsDiffer, diff1, diff2
|
||||
}
|
||||
|
||||
// Returns true if the two lists have common elements.
|
||||
func HasIntersection[T comparable](l1, l2 []T) bool {
|
||||
_, a, b := ListSetDifference(l1, l2)
|
||||
return len(a)+len(b) < len(setFromList(l1))+len(setFromList(l2))
|
||||
}
|
||||
|
||||
// Returns true if the given string s is prefixed with any string in the given prefix list.
|
||||
func HasAnyPrefix(s string, prefixList []string) bool {
|
||||
for _, prefix := range prefixList {
|
||||
|
@@ -818,3 +818,52 @@ func TestReverseSlice(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var hasIntersectionTestCases = []struct {
|
||||
name string
|
||||
l1 []string
|
||||
l2 []string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
l1: []string{"a", "b", "c"},
|
||||
l2: []string{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "both empty",
|
||||
l1: []string{},
|
||||
l2: []string{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "identical",
|
||||
l1: []string{"a", "b", "c"},
|
||||
l2: []string{"a", "b", "c"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "duplicates",
|
||||
l1: []string{"a", "a", "a"},
|
||||
l2: []string{"a", "b", "c"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "duplicates with no intersection",
|
||||
l1: []string{"d", "d", "d", "d"},
|
||||
l2: []string{"a", "b", "c"},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestHasIntersection(t *testing.T) {
|
||||
for _, testCase := range hasIntersectionTestCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
hasIntersection := HasIntersection(testCase.l1, testCase.l2)
|
||||
if !reflect.DeepEqual(hasIntersection, testCase.expected) {
|
||||
t.Errorf("expected %#v, got %#v", testCase.expected, hasIntersection)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -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",
|
||||
|
329
apex/container_test.go
Normal file
329
apex/container_test.go
Normal file
@@ -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))
|
||||
}
|
@@ -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",
|
||||
|
12
java/base.go
12
java/base.go
@@ -549,6 +549,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() {
|
||||
|
129
java/container_test.go
Normal file
129
java/container_test.go
Normal file
@@ -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))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user