xref: /aosp_15_r20/build/soong/android/container.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2024 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage android
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"reflect"
20*333d2b36SAndroid Build Coastguard Worker	"slices"
21*333d2b36SAndroid Build Coastguard Worker	"strings"
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint"
24*333d2b36SAndroid Build Coastguard Worker)
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Worker// ----------------------------------------------------------------------------
27*333d2b36SAndroid Build Coastguard Worker// Start of the definitions of exception functions and the lookup table.
28*333d2b36SAndroid Build Coastguard Worker//
29*333d2b36SAndroid Build Coastguard Worker// Functions cannot be used as a value passed in providers, because functions are not
30*333d2b36SAndroid Build Coastguard Worker// hashable. As a workaround, the [exceptionHandleFuncLabel] enum values are passed using providers,
31*333d2b36SAndroid Build Coastguard Worker// and the corresponding functions are called from [exceptionHandleFunctionsTable] map.
32*333d2b36SAndroid Build Coastguard Worker// ----------------------------------------------------------------------------
33*333d2b36SAndroid Build Coastguard Worker
34*333d2b36SAndroid Build Coastguard Workertype exceptionHandleFunc func(ModuleContext, Module, Module) bool
35*333d2b36SAndroid Build Coastguard Worker
36*333d2b36SAndroid Build Coastguard Workertype StubsAvailableModule interface {
37*333d2b36SAndroid Build Coastguard Worker	IsStubsModule() bool
38*333d2b36SAndroid Build Coastguard Worker}
39*333d2b36SAndroid Build Coastguard Worker
40*333d2b36SAndroid Build Coastguard Worker// Returns true if the dependency module is a stubs module
41*333d2b36SAndroid Build Coastguard Workervar depIsStubsModule exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
42*333d2b36SAndroid Build Coastguard Worker	if stubsModule, ok := dep.(StubsAvailableModule); ok {
43*333d2b36SAndroid Build Coastguard Worker		return stubsModule.IsStubsModule()
44*333d2b36SAndroid Build Coastguard Worker	}
45*333d2b36SAndroid Build Coastguard Worker	return false
46*333d2b36SAndroid Build Coastguard Worker}
47*333d2b36SAndroid Build Coastguard Worker
48*333d2b36SAndroid Build Coastguard Worker// Returns true if the dependency module belongs to any of the apexes.
49*333d2b36SAndroid Build Coastguard Workervar depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _, dep Module) bool {
50*333d2b36SAndroid Build Coastguard Worker	depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
51*333d2b36SAndroid Build Coastguard Worker	return InList(ApexContainer, depContainersInfo.belongingContainers)
52*333d2b36SAndroid Build Coastguard Worker}
53*333d2b36SAndroid Build Coastguard Worker
54*333d2b36SAndroid Build Coastguard Worker// Returns true if the module and the dependent module belongs to common apexes.
55*333d2b36SAndroid Build Coastguard Workervar belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m, dep Module) bool {
56*333d2b36SAndroid Build Coastguard Worker	mContainersInfo, _ := getContainerModuleInfo(mctx, m)
57*333d2b36SAndroid Build Coastguard Worker	depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
58*333d2b36SAndroid Build Coastguard Worker
59*333d2b36SAndroid Build Coastguard Worker	return HasIntersection(mContainersInfo.ApexNames(), depContainersInfo.ApexNames())
60*333d2b36SAndroid Build Coastguard Worker}
61*333d2b36SAndroid Build Coastguard Worker
62*333d2b36SAndroid Build Coastguard Worker// Returns true when all apexes that the module belongs to are non updatable.
63*333d2b36SAndroid Build Coastguard Worker// For an apex module to be allowed to depend on a non-apex partition module,
64*333d2b36SAndroid Build Coastguard Worker// all apexes that the module belong to must be non updatable.
65*333d2b36SAndroid Build Coastguard Workervar belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m, _ Module) bool {
66*333d2b36SAndroid Build Coastguard Worker	mContainersInfo, _ := getContainerModuleInfo(mctx, m)
67*333d2b36SAndroid Build Coastguard Worker
68*333d2b36SAndroid Build Coastguard Worker	return !mContainersInfo.UpdatableApex()
69*333d2b36SAndroid Build Coastguard Worker}
70*333d2b36SAndroid Build Coastguard Worker
71*333d2b36SAndroid Build Coastguard Worker// Returns true if the dependency is added via dependency tags that are not used to tag dynamic
72*333d2b36SAndroid Build Coastguard Worker// dependency tags.
73*333d2b36SAndroid Build Coastguard Workervar depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
74*333d2b36SAndroid Build Coastguard Worker	mInstallable, _ := m.(InstallableModule)
75*333d2b36SAndroid Build Coastguard Worker	depTag := ctx.OtherModuleDependencyTag(dep)
76*333d2b36SAndroid Build Coastguard Worker	return !InList(depTag, mInstallable.DynamicDependencyTags())
77*333d2b36SAndroid Build Coastguard Worker}
78*333d2b36SAndroid Build Coastguard Worker
79*333d2b36SAndroid Build Coastguard Worker// Returns true if the dependency is added via dependency tags that are not used to tag static
80*333d2b36SAndroid Build Coastguard Worker// or dynamic dependency tags. These dependencies do not affect the module in compile time or in
81*333d2b36SAndroid Build Coastguard Worker// runtime, thus are not significant enough to raise an error.
82*333d2b36SAndroid Build Coastguard Workervar depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
83*333d2b36SAndroid Build Coastguard Worker	mInstallable, _ := m.(InstallableModule)
84*333d2b36SAndroid Build Coastguard Worker	depTag := ctx.OtherModuleDependencyTag(dep)
85*333d2b36SAndroid Build Coastguard Worker	return !InList(depTag, append(mInstallable.StaticDependencyTags(), mInstallable.DynamicDependencyTags()...))
86*333d2b36SAndroid Build Coastguard Worker}
87*333d2b36SAndroid Build Coastguard Worker
88*333d2b36SAndroid Build Coastguard Workervar globallyAllowlistedDependencies = []string{
89*333d2b36SAndroid Build Coastguard Worker	// Modules that provide annotations used within the platform and apexes.
90*333d2b36SAndroid Build Coastguard Worker	"aconfig-annotations-lib",
91*333d2b36SAndroid Build Coastguard Worker	"framework-annotations-lib",
92*333d2b36SAndroid Build Coastguard Worker	"unsupportedappusage",
93*333d2b36SAndroid Build Coastguard Worker
94*333d2b36SAndroid Build Coastguard Worker	// TODO(b/363016634): Remove from the allowlist when the module is converted
95*333d2b36SAndroid Build Coastguard Worker	// to java_sdk_library and the java_aconfig_library modules depend on the stub.
96*333d2b36SAndroid Build Coastguard Worker	"aconfig_storage_stub",
97*333d2b36SAndroid Build Coastguard Worker
98*333d2b36SAndroid Build Coastguard Worker	// framework-res provides core resources essential for building apps and system UI.
99*333d2b36SAndroid Build Coastguard Worker	// This module is implicitly added as a dependency for java modules even when the
100*333d2b36SAndroid Build Coastguard Worker	// dependency specifies sdk_version.
101*333d2b36SAndroid Build Coastguard Worker	"framework-res",
102*333d2b36SAndroid Build Coastguard Worker
103*333d2b36SAndroid Build Coastguard Worker	// jacocoagent is implicitly added as a dependency in coverage builds, and is not installed
104*333d2b36SAndroid Build Coastguard Worker	// on the device.
105*333d2b36SAndroid Build Coastguard Worker	"jacocoagent",
106*333d2b36SAndroid Build Coastguard Worker}
107*333d2b36SAndroid Build Coastguard Worker
108*333d2b36SAndroid Build Coastguard Worker// Returns true when the dependency is globally allowlisted for inter-container dependency
109*333d2b36SAndroid Build Coastguard Workervar depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
110*333d2b36SAndroid Build Coastguard Worker	return InList(dep.Name(), globallyAllowlistedDependencies)
111*333d2b36SAndroid Build Coastguard Worker}
112*333d2b36SAndroid Build Coastguard Worker
113*333d2b36SAndroid Build Coastguard Worker// Labels of exception functions, which are used to determine special dependencies that allow
114*333d2b36SAndroid Build Coastguard Worker// otherwise restricted inter-container dependencies
115*333d2b36SAndroid Build Coastguard Workertype exceptionHandleFuncLabel int
116*333d2b36SAndroid Build Coastguard Worker
117*333d2b36SAndroid Build Coastguard Workerconst (
118*333d2b36SAndroid Build Coastguard Worker	checkStubs exceptionHandleFuncLabel = iota
119*333d2b36SAndroid Build Coastguard Worker	checkApexModule
120*333d2b36SAndroid Build Coastguard Worker	checkInCommonApexes
121*333d2b36SAndroid Build Coastguard Worker	checkApexIsNonUpdatable
122*333d2b36SAndroid Build Coastguard Worker	checkNotDynamicDepTag
123*333d2b36SAndroid Build Coastguard Worker	checkNotStaticOrDynamicDepTag
124*333d2b36SAndroid Build Coastguard Worker	checkGlobalAllowlistedDep
125*333d2b36SAndroid Build Coastguard Worker)
126*333d2b36SAndroid Build Coastguard Worker
127*333d2b36SAndroid Build Coastguard Worker// Map of [exceptionHandleFuncLabel] to the [exceptionHandleFunc]
128*333d2b36SAndroid Build Coastguard Workervar exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
129*333d2b36SAndroid Build Coastguard Worker	checkStubs:                    depIsStubsModule,
130*333d2b36SAndroid Build Coastguard Worker	checkApexModule:               depIsApexModule,
131*333d2b36SAndroid Build Coastguard Worker	checkInCommonApexes:           belongsToCommonApexes,
132*333d2b36SAndroid Build Coastguard Worker	checkApexIsNonUpdatable:       belongsToNonUpdatableApex,
133*333d2b36SAndroid Build Coastguard Worker	checkNotDynamicDepTag:         depIsNotDynamicDepTag,
134*333d2b36SAndroid Build Coastguard Worker	checkNotStaticOrDynamicDepTag: depIsNotStaticOrDynamicDepTag,
135*333d2b36SAndroid Build Coastguard Worker	checkGlobalAllowlistedDep:     depIsGloballyAllowlisted,
136*333d2b36SAndroid Build Coastguard Worker}
137*333d2b36SAndroid Build Coastguard Worker
138*333d2b36SAndroid Build Coastguard Worker// ----------------------------------------------------------------------------
139*333d2b36SAndroid Build Coastguard Worker// Start of the definitions of container determination functions.
140*333d2b36SAndroid Build Coastguard Worker//
141*333d2b36SAndroid Build Coastguard Worker// Similar to the above section, below defines the functions used to determine
142*333d2b36SAndroid Build Coastguard Worker// the container of each modules.
143*333d2b36SAndroid Build Coastguard Worker// ----------------------------------------------------------------------------
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Workertype containerBoundaryFunc func(mctx ModuleContext) bool
146*333d2b36SAndroid Build Coastguard Worker
147*333d2b36SAndroid Build Coastguard Workervar vendorContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
148*333d2b36SAndroid Build Coastguard Worker	m, ok := mctx.Module().(ImageInterface)
149*333d2b36SAndroid Build Coastguard Worker	return mctx.Module().InstallInVendor() || (ok && m.VendorVariantNeeded(mctx))
150*333d2b36SAndroid Build Coastguard Worker}
151*333d2b36SAndroid Build Coastguard Worker
152*333d2b36SAndroid Build Coastguard Workervar systemContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
153*333d2b36SAndroid Build Coastguard Worker	module := mctx.Module()
154*333d2b36SAndroid Build Coastguard Worker
155*333d2b36SAndroid Build Coastguard Worker	return !module.InstallInTestcases() &&
156*333d2b36SAndroid Build Coastguard Worker		!module.InstallInData() &&
157*333d2b36SAndroid Build Coastguard Worker		!module.InstallInRamdisk() &&
158*333d2b36SAndroid Build Coastguard Worker		!module.InstallInVendorRamdisk() &&
159*333d2b36SAndroid Build Coastguard Worker		!module.InstallInDebugRamdisk() &&
160*333d2b36SAndroid Build Coastguard Worker		!module.InstallInRecovery() &&
161*333d2b36SAndroid Build Coastguard Worker		!module.InstallInVendor() &&
162*333d2b36SAndroid Build Coastguard Worker		!module.InstallInOdm() &&
163*333d2b36SAndroid Build Coastguard Worker		!module.InstallInProduct() &&
164*333d2b36SAndroid Build Coastguard Worker		determineModuleKind(module.base(), mctx.blueprintBaseModuleContext()) == platformModule
165*333d2b36SAndroid Build Coastguard Worker}
166*333d2b36SAndroid Build Coastguard Worker
167*333d2b36SAndroid Build Coastguard Workervar productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
168*333d2b36SAndroid Build Coastguard Worker	m, ok := mctx.Module().(ImageInterface)
169*333d2b36SAndroid Build Coastguard Worker	return mctx.Module().InstallInProduct() || (ok && m.ProductVariantNeeded(mctx))
170*333d2b36SAndroid Build Coastguard Worker}
171*333d2b36SAndroid Build Coastguard Worker
172*333d2b36SAndroid Build Coastguard Workervar apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
173*333d2b36SAndroid Build Coastguard Worker	_, ok := ModuleProvider(mctx, AllApexInfoProvider)
174*333d2b36SAndroid Build Coastguard Worker	return ok
175*333d2b36SAndroid Build Coastguard Worker}
176*333d2b36SAndroid Build Coastguard Worker
177*333d2b36SAndroid Build Coastguard Workervar ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
178*333d2b36SAndroid Build Coastguard Worker	props := mctx.Module().GetProperties()
179*333d2b36SAndroid Build Coastguard Worker	for _, prop := range props {
180*333d2b36SAndroid Build Coastguard Worker		val := reflect.ValueOf(prop).Elem()
181*333d2b36SAndroid Build Coastguard Worker		if val.Kind() == reflect.Struct {
182*333d2b36SAndroid Build Coastguard Worker			testSuites := val.FieldByName("Test_suites")
183*333d2b36SAndroid Build Coastguard Worker			if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
184*333d2b36SAndroid Build Coastguard Worker				return true
185*333d2b36SAndroid Build Coastguard Worker			}
186*333d2b36SAndroid Build Coastguard Worker		}
187*333d2b36SAndroid Build Coastguard Worker	}
188*333d2b36SAndroid Build Coastguard Worker	return false
189*333d2b36SAndroid Build Coastguard Worker}
190*333d2b36SAndroid Build Coastguard Worker
191*333d2b36SAndroid Build Coastguard Workertype unstableInfo struct {
192*333d2b36SAndroid Build Coastguard Worker	// Determines if the module contains the private APIs of the platform.
193*333d2b36SAndroid Build Coastguard Worker	ContainsPlatformPrivateApis bool
194*333d2b36SAndroid Build Coastguard Worker}
195*333d2b36SAndroid Build Coastguard Worker
196*333d2b36SAndroid Build Coastguard Workervar unstableInfoProvider = blueprint.NewProvider[unstableInfo]()
197*333d2b36SAndroid Build Coastguard Worker
198*333d2b36SAndroid Build Coastguard Workerfunc determineUnstableModule(mctx ModuleContext) bool {
199*333d2b36SAndroid Build Coastguard Worker	module := mctx.Module()
200*333d2b36SAndroid Build Coastguard Worker	unstableModule := module.Name() == "framework-minus-apex"
201*333d2b36SAndroid Build Coastguard Worker	if installable, ok := module.(InstallableModule); ok {
202*333d2b36SAndroid Build Coastguard Worker		for _, staticDepTag := range installable.StaticDependencyTags() {
203*333d2b36SAndroid Build Coastguard Worker			mctx.VisitDirectDepsWithTag(staticDepTag, func(dep Module) {
204*333d2b36SAndroid Build Coastguard Worker				if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok {
205*333d2b36SAndroid Build Coastguard Worker					unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis
206*333d2b36SAndroid Build Coastguard Worker				}
207*333d2b36SAndroid Build Coastguard Worker			})
208*333d2b36SAndroid Build Coastguard Worker		}
209*333d2b36SAndroid Build Coastguard Worker	}
210*333d2b36SAndroid Build Coastguard Worker	return unstableModule
211*333d2b36SAndroid Build Coastguard Worker}
212*333d2b36SAndroid Build Coastguard Worker
213*333d2b36SAndroid Build Coastguard Workervar unstableContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
214*333d2b36SAndroid Build Coastguard Worker	return determineUnstableModule(mctx)
215*333d2b36SAndroid Build Coastguard Worker}
216*333d2b36SAndroid Build Coastguard Worker
217*333d2b36SAndroid Build Coastguard Worker// Map of [*container] to the [containerBoundaryFunc]
218*333d2b36SAndroid Build Coastguard Workervar containerBoundaryFunctionsTable = map[*container]containerBoundaryFunc{
219*333d2b36SAndroid Build Coastguard Worker	VendorContainer:   vendorContainerBoundaryFunc,
220*333d2b36SAndroid Build Coastguard Worker	SystemContainer:   systemContainerBoundaryFunc,
221*333d2b36SAndroid Build Coastguard Worker	ProductContainer:  productContainerBoundaryFunc,
222*333d2b36SAndroid Build Coastguard Worker	ApexContainer:     apexContainerBoundaryFunc,
223*333d2b36SAndroid Build Coastguard Worker	CtsContainer:      ctsContainerBoundaryFunc,
224*333d2b36SAndroid Build Coastguard Worker	UnstableContainer: unstableContainerBoundaryFunc,
225*333d2b36SAndroid Build Coastguard Worker}
226*333d2b36SAndroid Build Coastguard Worker
227*333d2b36SAndroid Build Coastguard Worker// ----------------------------------------------------------------------------
228*333d2b36SAndroid Build Coastguard Worker// End of the definitions of container determination functions.
229*333d2b36SAndroid Build Coastguard Worker// ----------------------------------------------------------------------------
230*333d2b36SAndroid Build Coastguard Worker
231*333d2b36SAndroid Build Coastguard Workertype InstallableModule interface {
232*333d2b36SAndroid Build Coastguard Worker	StaticDependencyTags() []blueprint.DependencyTag
233*333d2b36SAndroid Build Coastguard Worker	DynamicDependencyTags() []blueprint.DependencyTag
234*333d2b36SAndroid Build Coastguard Worker}
235*333d2b36SAndroid Build Coastguard Worker
236*333d2b36SAndroid Build Coastguard Workertype restriction struct {
237*333d2b36SAndroid Build Coastguard Worker	// container of the dependency
238*333d2b36SAndroid Build Coastguard Worker	dependency *container
239*333d2b36SAndroid Build Coastguard Worker
240*333d2b36SAndroid Build Coastguard Worker	// Error message to be emitted to the user when the dependency meets this restriction
241*333d2b36SAndroid Build Coastguard Worker	errorMessage string
242*333d2b36SAndroid Build Coastguard Worker
243*333d2b36SAndroid Build Coastguard Worker	// List of labels of allowed exception functions that allows bypassing this restriction.
244*333d2b36SAndroid Build Coastguard Worker	// If any of the functions mapped to each labels returns true, this dependency would be
245*333d2b36SAndroid Build Coastguard Worker	// considered allowed and an error will not be thrown.
246*333d2b36SAndroid Build Coastguard Worker	allowedExceptions []exceptionHandleFuncLabel
247*333d2b36SAndroid Build Coastguard Worker}
248*333d2b36SAndroid Build Coastguard Workertype container struct {
249*333d2b36SAndroid Build Coastguard Worker	// The name of the container i.e. partition, api domain
250*333d2b36SAndroid Build Coastguard Worker	name string
251*333d2b36SAndroid Build Coastguard Worker
252*333d2b36SAndroid Build Coastguard Worker	// Map of dependency restricted containers.
253*333d2b36SAndroid Build Coastguard Worker	restricted []restriction
254*333d2b36SAndroid Build Coastguard Worker}
255*333d2b36SAndroid Build Coastguard Worker
256*333d2b36SAndroid Build Coastguard Workervar (
257*333d2b36SAndroid Build Coastguard Worker	VendorContainer = &container{
258*333d2b36SAndroid Build Coastguard Worker		name:       VendorVariation,
259*333d2b36SAndroid Build Coastguard Worker		restricted: nil,
260*333d2b36SAndroid Build Coastguard Worker	}
261*333d2b36SAndroid Build Coastguard Worker
262*333d2b36SAndroid Build Coastguard Worker	SystemContainer = &container{
263*333d2b36SAndroid Build Coastguard Worker		name: "system",
264*333d2b36SAndroid Build Coastguard Worker		restricted: []restriction{
265*333d2b36SAndroid Build Coastguard Worker			{
266*333d2b36SAndroid Build Coastguard Worker				dependency: VendorContainer,
267*333d2b36SAndroid Build Coastguard Worker				errorMessage: "Module belonging to the system partition other than HALs is " +
268*333d2b36SAndroid Build Coastguard Worker					"not allowed to depend on the vendor partition module, in order to support " +
269*333d2b36SAndroid Build Coastguard Worker					"independent development/update cycles and to support the Generic System " +
270*333d2b36SAndroid Build Coastguard Worker					"Image. Try depending on HALs, VNDK or AIDL instead.",
271*333d2b36SAndroid Build Coastguard Worker				allowedExceptions: []exceptionHandleFuncLabel{
272*333d2b36SAndroid Build Coastguard Worker					checkStubs,
273*333d2b36SAndroid Build Coastguard Worker					checkNotDynamicDepTag,
274*333d2b36SAndroid Build Coastguard Worker					checkGlobalAllowlistedDep,
275*333d2b36SAndroid Build Coastguard Worker				},
276*333d2b36SAndroid Build Coastguard Worker			},
277*333d2b36SAndroid Build Coastguard Worker		},
278*333d2b36SAndroid Build Coastguard Worker	}
279*333d2b36SAndroid Build Coastguard Worker
280*333d2b36SAndroid Build Coastguard Worker	ProductContainer = &container{
281*333d2b36SAndroid Build Coastguard Worker		name: ProductVariation,
282*333d2b36SAndroid Build Coastguard Worker		restricted: []restriction{
283*333d2b36SAndroid Build Coastguard Worker			{
284*333d2b36SAndroid Build Coastguard Worker				dependency: VendorContainer,
285*333d2b36SAndroid Build Coastguard Worker				errorMessage: "Module belonging to the product partition is not allowed to " +
286*333d2b36SAndroid Build Coastguard Worker					"depend on the vendor partition module, as this may lead to security " +
287*333d2b36SAndroid Build Coastguard Worker					"vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
288*333d2b36SAndroid Build Coastguard Worker				allowedExceptions: []exceptionHandleFuncLabel{
289*333d2b36SAndroid Build Coastguard Worker					checkStubs,
290*333d2b36SAndroid Build Coastguard Worker					checkNotDynamicDepTag,
291*333d2b36SAndroid Build Coastguard Worker					checkGlobalAllowlistedDep,
292*333d2b36SAndroid Build Coastguard Worker				},
293*333d2b36SAndroid Build Coastguard Worker			},
294*333d2b36SAndroid Build Coastguard Worker		},
295*333d2b36SAndroid Build Coastguard Worker	}
296*333d2b36SAndroid Build Coastguard Worker
297*333d2b36SAndroid Build Coastguard Worker	ApexContainer = initializeApexContainer()
298*333d2b36SAndroid Build Coastguard Worker
299*333d2b36SAndroid Build Coastguard Worker	CtsContainer = &container{
300*333d2b36SAndroid Build Coastguard Worker		name: "cts",
301*333d2b36SAndroid Build Coastguard Worker		restricted: []restriction{
302*333d2b36SAndroid Build Coastguard Worker			{
303*333d2b36SAndroid Build Coastguard Worker				dependency: UnstableContainer,
304*333d2b36SAndroid Build Coastguard Worker				errorMessage: "CTS module should not depend on the modules that contain the " +
305*333d2b36SAndroid Build Coastguard Worker					"platform implementation details, including \"framework\". Depending on these " +
306*333d2b36SAndroid Build Coastguard Worker					"modules may lead to disclosure of implementation details and regression " +
307*333d2b36SAndroid Build Coastguard Worker					"due to API changes across platform versions. Try depending on the stubs instead " +
308*333d2b36SAndroid Build Coastguard Worker					"and ensure that the module sets an appropriate 'sdk_version'.",
309*333d2b36SAndroid Build Coastguard Worker				allowedExceptions: []exceptionHandleFuncLabel{
310*333d2b36SAndroid Build Coastguard Worker					checkStubs,
311*333d2b36SAndroid Build Coastguard Worker					checkNotStaticOrDynamicDepTag,
312*333d2b36SAndroid Build Coastguard Worker					checkGlobalAllowlistedDep,
313*333d2b36SAndroid Build Coastguard Worker				},
314*333d2b36SAndroid Build Coastguard Worker			},
315*333d2b36SAndroid Build Coastguard Worker		},
316*333d2b36SAndroid Build Coastguard Worker	}
317*333d2b36SAndroid Build Coastguard Worker
318*333d2b36SAndroid Build Coastguard Worker	// Container signifying that the module contains unstable platform private APIs
319*333d2b36SAndroid Build Coastguard Worker	UnstableContainer = &container{
320*333d2b36SAndroid Build Coastguard Worker		name:       "unstable",
321*333d2b36SAndroid Build Coastguard Worker		restricted: nil,
322*333d2b36SAndroid Build Coastguard Worker	}
323*333d2b36SAndroid Build Coastguard Worker
324*333d2b36SAndroid Build Coastguard Worker	allContainers = []*container{
325*333d2b36SAndroid Build Coastguard Worker		VendorContainer,
326*333d2b36SAndroid Build Coastguard Worker		SystemContainer,
327*333d2b36SAndroid Build Coastguard Worker		ProductContainer,
328*333d2b36SAndroid Build Coastguard Worker		ApexContainer,
329*333d2b36SAndroid Build Coastguard Worker		CtsContainer,
330*333d2b36SAndroid Build Coastguard Worker		UnstableContainer,
331*333d2b36SAndroid Build Coastguard Worker	}
332*333d2b36SAndroid Build Coastguard Worker)
333*333d2b36SAndroid Build Coastguard Worker
334*333d2b36SAndroid Build Coastguard Workerfunc initializeApexContainer() *container {
335*333d2b36SAndroid Build Coastguard Worker	apexContainer := &container{
336*333d2b36SAndroid Build Coastguard Worker		name: "apex",
337*333d2b36SAndroid Build Coastguard Worker		restricted: []restriction{
338*333d2b36SAndroid Build Coastguard Worker			{
339*333d2b36SAndroid Build Coastguard Worker				dependency: SystemContainer,
340*333d2b36SAndroid Build Coastguard Worker				errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
341*333d2b36SAndroid Build Coastguard Worker					"modules belonging to the system partition. Either statically depend on the " +
342*333d2b36SAndroid Build Coastguard Worker					"module or convert the depending module to java_sdk_library and depend on " +
343*333d2b36SAndroid Build Coastguard Worker					"the stubs.",
344*333d2b36SAndroid Build Coastguard Worker				allowedExceptions: []exceptionHandleFuncLabel{
345*333d2b36SAndroid Build Coastguard Worker					checkStubs,
346*333d2b36SAndroid Build Coastguard Worker					checkApexModule,
347*333d2b36SAndroid Build Coastguard Worker					checkInCommonApexes,
348*333d2b36SAndroid Build Coastguard Worker					checkApexIsNonUpdatable,
349*333d2b36SAndroid Build Coastguard Worker					checkNotStaticOrDynamicDepTag,
350*333d2b36SAndroid Build Coastguard Worker					checkGlobalAllowlistedDep,
351*333d2b36SAndroid Build Coastguard Worker				},
352*333d2b36SAndroid Build Coastguard Worker			},
353*333d2b36SAndroid Build Coastguard Worker		},
354*333d2b36SAndroid Build Coastguard Worker	}
355*333d2b36SAndroid Build Coastguard Worker
356*333d2b36SAndroid Build Coastguard Worker	apexContainer.restricted = append(apexContainer.restricted, restriction{
357*333d2b36SAndroid Build Coastguard Worker		dependency: apexContainer,
358*333d2b36SAndroid Build Coastguard Worker		errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
359*333d2b36SAndroid Build Coastguard Worker			"modules belonging to other Apex(es). Either include the depending " +
360*333d2b36SAndroid Build Coastguard Worker			"module in the Apex or convert the depending module to java_sdk_library " +
361*333d2b36SAndroid Build Coastguard Worker			"and depend on its stubs.",
362*333d2b36SAndroid Build Coastguard Worker		allowedExceptions: []exceptionHandleFuncLabel{
363*333d2b36SAndroid Build Coastguard Worker			checkStubs,
364*333d2b36SAndroid Build Coastguard Worker			checkInCommonApexes,
365*333d2b36SAndroid Build Coastguard Worker			checkNotStaticOrDynamicDepTag,
366*333d2b36SAndroid Build Coastguard Worker			checkGlobalAllowlistedDep,
367*333d2b36SAndroid Build Coastguard Worker		},
368*333d2b36SAndroid Build Coastguard Worker	})
369*333d2b36SAndroid Build Coastguard Worker
370*333d2b36SAndroid Build Coastguard Worker	return apexContainer
371*333d2b36SAndroid Build Coastguard Worker}
372*333d2b36SAndroid Build Coastguard Worker
373*333d2b36SAndroid Build Coastguard Workertype ContainersInfo struct {
374*333d2b36SAndroid Build Coastguard Worker	belongingContainers []*container
375*333d2b36SAndroid Build Coastguard Worker
376*333d2b36SAndroid Build Coastguard Worker	belongingApexes []ApexInfo
377*333d2b36SAndroid Build Coastguard Worker}
378*333d2b36SAndroid Build Coastguard Worker
379*333d2b36SAndroid Build Coastguard Workerfunc (c *ContainersInfo) BelongingContainers() []*container {
380*333d2b36SAndroid Build Coastguard Worker	return c.belongingContainers
381*333d2b36SAndroid Build Coastguard Worker}
382*333d2b36SAndroid Build Coastguard Worker
383*333d2b36SAndroid Build Coastguard Workerfunc (c *ContainersInfo) ApexNames() (ret []string) {
384*333d2b36SAndroid Build Coastguard Worker	for _, apex := range c.belongingApexes {
385*333d2b36SAndroid Build Coastguard Worker		ret = append(ret, apex.InApexVariants...)
386*333d2b36SAndroid Build Coastguard Worker	}
387*333d2b36SAndroid Build Coastguard Worker	slices.Sort(ret)
388*333d2b36SAndroid Build Coastguard Worker	return ret
389*333d2b36SAndroid Build Coastguard Worker}
390*333d2b36SAndroid Build Coastguard Worker
391*333d2b36SAndroid Build Coastguard Worker// Returns true if any of the apex the module belongs to is updatable.
392*333d2b36SAndroid Build Coastguard Workerfunc (c *ContainersInfo) UpdatableApex() bool {
393*333d2b36SAndroid Build Coastguard Worker	for _, apex := range c.belongingApexes {
394*333d2b36SAndroid Build Coastguard Worker		if apex.Updatable {
395*333d2b36SAndroid Build Coastguard Worker			return true
396*333d2b36SAndroid Build Coastguard Worker		}
397*333d2b36SAndroid Build Coastguard Worker	}
398*333d2b36SAndroid Build Coastguard Worker	return false
399*333d2b36SAndroid Build Coastguard Worker}
400*333d2b36SAndroid Build Coastguard Worker
401*333d2b36SAndroid Build Coastguard Workervar ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
402*333d2b36SAndroid Build Coastguard Worker
403*333d2b36SAndroid Build Coastguard Workerfunc satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m, dep Module) bool {
404*333d2b36SAndroid Build Coastguard Worker	for _, label := range allowedExceptionLabels {
405*333d2b36SAndroid Build Coastguard Worker		if exceptionHandleFunctionsTable[label](ctx, m, dep) {
406*333d2b36SAndroid Build Coastguard Worker			return true
407*333d2b36SAndroid Build Coastguard Worker		}
408*333d2b36SAndroid Build Coastguard Worker	}
409*333d2b36SAndroid Build Coastguard Worker	return false
410*333d2b36SAndroid Build Coastguard Worker}
411*333d2b36SAndroid Build Coastguard Worker
412*333d2b36SAndroid Build Coastguard Workerfunc (c *ContainersInfo) GetViolations(mctx ModuleContext, m, dep Module, depInfo ContainersInfo) []string {
413*333d2b36SAndroid Build Coastguard Worker	var violations []string
414*333d2b36SAndroid Build Coastguard Worker
415*333d2b36SAndroid Build Coastguard Worker	// Any containers that the module belongs to but the dependency does not belong to must be examined.
416*333d2b36SAndroid Build Coastguard Worker	_, containersUniqueToModule, _ := ListSetDifference(c.belongingContainers, depInfo.belongingContainers)
417*333d2b36SAndroid Build Coastguard Worker
418*333d2b36SAndroid Build Coastguard Worker	// Apex container should be examined even if both the module and the dependency belong to
419*333d2b36SAndroid Build Coastguard Worker	// the apex container to check that the two modules belong to the same apex.
420*333d2b36SAndroid Build Coastguard Worker	if InList(ApexContainer, c.belongingContainers) && !InList(ApexContainer, containersUniqueToModule) {
421*333d2b36SAndroid Build Coastguard Worker		containersUniqueToModule = append(containersUniqueToModule, ApexContainer)
422*333d2b36SAndroid Build Coastguard Worker	}
423*333d2b36SAndroid Build Coastguard Worker
424*333d2b36SAndroid Build Coastguard Worker	for _, containerUniqueToModule := range containersUniqueToModule {
425*333d2b36SAndroid Build Coastguard Worker		for _, restriction := range containerUniqueToModule.restricted {
426*333d2b36SAndroid Build Coastguard Worker			if InList(restriction.dependency, depInfo.belongingContainers) {
427*333d2b36SAndroid Build Coastguard Worker				if !satisfyAllowedExceptions(mctx, restriction.allowedExceptions, m, dep) {
428*333d2b36SAndroid Build Coastguard Worker					violations = append(violations, restriction.errorMessage)
429*333d2b36SAndroid Build Coastguard Worker				}
430*333d2b36SAndroid Build Coastguard Worker			}
431*333d2b36SAndroid Build Coastguard Worker		}
432*333d2b36SAndroid Build Coastguard Worker	}
433*333d2b36SAndroid Build Coastguard Worker
434*333d2b36SAndroid Build Coastguard Worker	return violations
435*333d2b36SAndroid Build Coastguard Worker}
436*333d2b36SAndroid Build Coastguard Worker
437*333d2b36SAndroid Build Coastguard Workerfunc generateContainerInfo(ctx ModuleContext) ContainersInfo {
438*333d2b36SAndroid Build Coastguard Worker	var containers []*container
439*333d2b36SAndroid Build Coastguard Worker
440*333d2b36SAndroid Build Coastguard Worker	for _, cnt := range allContainers {
441*333d2b36SAndroid Build Coastguard Worker		if containerBoundaryFunctionsTable[cnt](ctx) {
442*333d2b36SAndroid Build Coastguard Worker			containers = append(containers, cnt)
443*333d2b36SAndroid Build Coastguard Worker		}
444*333d2b36SAndroid Build Coastguard Worker	}
445*333d2b36SAndroid Build Coastguard Worker
446*333d2b36SAndroid Build Coastguard Worker	var belongingApexes []ApexInfo
447*333d2b36SAndroid Build Coastguard Worker	if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
448*333d2b36SAndroid Build Coastguard Worker		belongingApexes = apexInfo.ApexInfos
449*333d2b36SAndroid Build Coastguard Worker	}
450*333d2b36SAndroid Build Coastguard Worker
451*333d2b36SAndroid Build Coastguard Worker	return ContainersInfo{
452*333d2b36SAndroid Build Coastguard Worker		belongingContainers: containers,
453*333d2b36SAndroid Build Coastguard Worker		belongingApexes:     belongingApexes,
454*333d2b36SAndroid Build Coastguard Worker	}
455*333d2b36SAndroid Build Coastguard Worker}
456*333d2b36SAndroid Build Coastguard Worker
457*333d2b36SAndroid Build Coastguard Workerfunc getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
458*333d2b36SAndroid Build Coastguard Worker	if ctx.Module() == module {
459*333d2b36SAndroid Build Coastguard Worker		return ctx.getContainersInfo(), true
460*333d2b36SAndroid Build Coastguard Worker	}
461*333d2b36SAndroid Build Coastguard Worker
462*333d2b36SAndroid Build Coastguard Worker	return OtherModuleProvider(ctx, module, ContainersInfoProvider)
463*333d2b36SAndroid Build Coastguard Worker}
464*333d2b36SAndroid Build Coastguard Worker
465*333d2b36SAndroid Build Coastguard Workerfunc setContainerInfo(ctx ModuleContext) {
466*333d2b36SAndroid Build Coastguard Worker	// Required to determine the unstable container. This provider is set here instead of the
467*333d2b36SAndroid Build Coastguard Worker	// unstableContainerBoundaryFunc in order to prevent setting the provider multiple times.
468*333d2b36SAndroid Build Coastguard Worker	SetProvider(ctx, unstableInfoProvider, unstableInfo{
469*333d2b36SAndroid Build Coastguard Worker		ContainsPlatformPrivateApis: determineUnstableModule(ctx),
470*333d2b36SAndroid Build Coastguard Worker	})
471*333d2b36SAndroid Build Coastguard Worker
472*333d2b36SAndroid Build Coastguard Worker	if _, ok := ctx.Module().(InstallableModule); ok {
473*333d2b36SAndroid Build Coastguard Worker		containersInfo := generateContainerInfo(ctx)
474*333d2b36SAndroid Build Coastguard Worker		ctx.setContainersInfo(containersInfo)
475*333d2b36SAndroid Build Coastguard Worker		SetProvider(ctx, ContainersInfoProvider, containersInfo)
476*333d2b36SAndroid Build Coastguard Worker	}
477*333d2b36SAndroid Build Coastguard Worker}
478*333d2b36SAndroid Build Coastguard Worker
479*333d2b36SAndroid Build Coastguard Workerfunc checkContainerViolations(ctx ModuleContext) {
480*333d2b36SAndroid Build Coastguard Worker	if _, ok := ctx.Module().(InstallableModule); ok {
481*333d2b36SAndroid Build Coastguard Worker		containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
482*333d2b36SAndroid Build Coastguard Worker		ctx.VisitDirectDeps(func(dep Module) {
483*333d2b36SAndroid Build Coastguard Worker			if !dep.Enabled(ctx) {
484*333d2b36SAndroid Build Coastguard Worker				return
485*333d2b36SAndroid Build Coastguard Worker			}
486*333d2b36SAndroid Build Coastguard Worker
487*333d2b36SAndroid Build Coastguard Worker			// Pre-existing violating dependencies are tracked in containerDependencyViolationAllowlist.
488*333d2b36SAndroid Build Coastguard Worker			// If this dependency is allowlisted, do not check for violation.
489*333d2b36SAndroid Build Coastguard Worker			// If not, check if this dependency matches any restricted dependency and
490*333d2b36SAndroid Build Coastguard Worker			// satisfies any exception functions, which allows bypassing the
491*333d2b36SAndroid Build Coastguard Worker			// restriction. If all of the exceptions are not satisfied, throw an error.
492*333d2b36SAndroid Build Coastguard Worker			if depContainersInfo, ok := getContainerModuleInfo(ctx, dep); ok {
493*333d2b36SAndroid Build Coastguard Worker				if allowedViolations, ok := ContainerDependencyViolationAllowlist[ctx.ModuleName()]; ok && InList(dep.Name(), allowedViolations) {
494*333d2b36SAndroid Build Coastguard Worker					return
495*333d2b36SAndroid Build Coastguard Worker				} else {
496*333d2b36SAndroid Build Coastguard Worker					violations := containersInfo.GetViolations(ctx, ctx.Module(), dep, depContainersInfo)
497*333d2b36SAndroid Build Coastguard Worker					if len(violations) > 0 {
498*333d2b36SAndroid Build Coastguard Worker						errorMessage := fmt.Sprintf("%s cannot depend on %s. ", ctx.ModuleName(), dep.Name())
499*333d2b36SAndroid Build Coastguard Worker						errorMessage += strings.Join(violations, " ")
500*333d2b36SAndroid Build Coastguard Worker						ctx.ModuleErrorf(errorMessage)
501*333d2b36SAndroid Build Coastguard Worker					}
502*333d2b36SAndroid Build Coastguard Worker				}
503*333d2b36SAndroid Build Coastguard Worker			}
504*333d2b36SAndroid Build Coastguard Worker		})
505*333d2b36SAndroid Build Coastguard Worker	}
506*333d2b36SAndroid Build Coastguard Worker}
507