blob: a5aab79bb7250ae68ea906d22c5a45970022980e [file] [log] [blame]
Jihoon Kangc3d4e112024-06-24 22:16:27 +00001// Copyright 2024 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
Jihoon Kang85bc1932024-07-01 17:04:46 +000018 "fmt"
Jihoon Kangc3d4e112024-06-24 22:16:27 +000019 "reflect"
20 "slices"
Jihoon Kang85bc1932024-07-01 17:04:46 +000021 "strings"
Jihoon Kangc3d4e112024-06-24 22:16:27 +000022
23 "github.com/google/blueprint"
24)
25
Jihoon Kang17a61d72024-08-12 22:26:52 +000026// ----------------------------------------------------------------------------
27// Start of the definitions of exception functions and the lookup table.
28//
29// Functions cannot be used as a value passed in providers, because functions are not
30// hashable. As a workaround, the [exceptionHandleFuncLabel] enum values are passed using providers,
31// and the corresponding functions are called from [exceptionHandleFunctionsTable] map.
32// ----------------------------------------------------------------------------
33
Yu Liu97880e12025-01-07 19:03:34 +000034type exceptionHandleFunc func(ModuleContext, Module, ModuleProxy) bool
Jihoon Kang17a61d72024-08-12 22:26:52 +000035
Jihoon Kangc3d4e112024-06-24 22:16:27 +000036type StubsAvailableModule interface {
37 IsStubsModule() bool
38}
39
40// Returns true if the dependency module is a stubs module
Yu Liu97880e12025-01-07 19:03:34 +000041var depIsStubsModule exceptionHandleFunc = func(mctx ModuleContext, _ Module, dep ModuleProxy) bool {
42 return OtherModuleProviderOrDefault(mctx, dep, CommonModuleInfoKey).IsStubsModule
Jihoon Kangc3d4e112024-06-24 22:16:27 +000043}
44
Jihoon Kang224ea082024-08-12 22:38:16 +000045// Returns true if the dependency module belongs to any of the apexes.
Yu Liu97880e12025-01-07 19:03:34 +000046var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _ Module, dep ModuleProxy) bool {
Jihoon Kang224ea082024-08-12 22:38:16 +000047 depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
48 return InList(ApexContainer, depContainersInfo.belongingContainers)
49}
50
51// Returns true if the module and the dependent module belongs to common apexes.
Yu Liu97880e12025-01-07 19:03:34 +000052var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m Module, dep ModuleProxy) bool {
Jihoon Kang224ea082024-08-12 22:38:16 +000053 mContainersInfo, _ := getContainerModuleInfo(mctx, m)
54 depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
55
56 return HasIntersection(mContainersInfo.ApexNames(), depContainersInfo.ApexNames())
57}
58
59// Returns true when all apexes that the module belongs to are non updatable.
60// For an apex module to be allowed to depend on a non-apex partition module,
61// all apexes that the module belong to must be non updatable.
Yu Liu97880e12025-01-07 19:03:34 +000062var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m Module, _ ModuleProxy) bool {
Jihoon Kang224ea082024-08-12 22:38:16 +000063 mContainersInfo, _ := getContainerModuleInfo(mctx, m)
64
65 return !mContainersInfo.UpdatableApex()
66}
67
68// Returns true if the dependency is added via dependency tags that are not used to tag dynamic
69// dependency tags.
Yu Liu97880e12025-01-07 19:03:34 +000070var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m Module, dep ModuleProxy) bool {
Jihoon Kang224ea082024-08-12 22:38:16 +000071 mInstallable, _ := m.(InstallableModule)
72 depTag := ctx.OtherModuleDependencyTag(dep)
73 return !InList(depTag, mInstallable.DynamicDependencyTags())
74}
75
76// Returns true if the dependency is added via dependency tags that are not used to tag static
77// or dynamic dependency tags. These dependencies do not affect the module in compile time or in
78// runtime, thus are not significant enough to raise an error.
Yu Liu97880e12025-01-07 19:03:34 +000079var depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m Module, dep ModuleProxy) bool {
Jihoon Kang224ea082024-08-12 22:38:16 +000080 mInstallable, _ := m.(InstallableModule)
81 depTag := ctx.OtherModuleDependencyTag(dep)
82 return !InList(depTag, append(mInstallable.StaticDependencyTags(), mInstallable.DynamicDependencyTags()...))
83}
84
85var globallyAllowlistedDependencies = []string{
86 // Modules that provide annotations used within the platform and apexes.
87 "aconfig-annotations-lib",
88 "framework-annotations-lib",
89 "unsupportedappusage",
90
Jihoon Kangbf65d1b2024-08-29 18:49:00 +000091 // TODO(b/363016634): Remove from the allowlist when the module is converted
92 // to java_sdk_library and the java_aconfig_library modules depend on the stub.
zhidouaed2e742024-11-20 03:55:07 +000093 "aconfig_storage_stub",
Jihoon Kangbf65d1b2024-08-29 18:49:00 +000094
Jihoon Kang224ea082024-08-12 22:38:16 +000095 // framework-res provides core resources essential for building apps and system UI.
96 // This module is implicitly added as a dependency for java modules even when the
97 // dependency specifies sdk_version.
98 "framework-res",
Jihoon Kang601939d2024-08-27 17:27:52 +000099
100 // jacocoagent is implicitly added as a dependency in coverage builds, and is not installed
101 // on the device.
102 "jacocoagent",
Jihoon Kang224ea082024-08-12 22:38:16 +0000103}
104
105// Returns true when the dependency is globally allowlisted for inter-container dependency
Yu Liu97880e12025-01-07 19:03:34 +0000106var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _ Module, dep ModuleProxy) bool {
Jihoon Kang224ea082024-08-12 22:38:16 +0000107 return InList(dep.Name(), globallyAllowlistedDependencies)
108}
109
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000110// Labels of exception functions, which are used to determine special dependencies that allow
111// otherwise restricted inter-container dependencies
112type exceptionHandleFuncLabel int
113
114const (
115 checkStubs exceptionHandleFuncLabel = iota
Jihoon Kang224ea082024-08-12 22:38:16 +0000116 checkApexModule
117 checkInCommonApexes
118 checkApexIsNonUpdatable
119 checkNotDynamicDepTag
120 checkNotStaticOrDynamicDepTag
121 checkGlobalAllowlistedDep
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000122)
123
Jihoon Kang224ea082024-08-12 22:38:16 +0000124// Map of [exceptionHandleFuncLabel] to the [exceptionHandleFunc]
Jihoon Kang17a61d72024-08-12 22:26:52 +0000125var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
Jihoon Kang224ea082024-08-12 22:38:16 +0000126 checkStubs: depIsStubsModule,
127 checkApexModule: depIsApexModule,
128 checkInCommonApexes: belongsToCommonApexes,
129 checkApexIsNonUpdatable: belongsToNonUpdatableApex,
130 checkNotDynamicDepTag: depIsNotDynamicDepTag,
131 checkNotStaticOrDynamicDepTag: depIsNotStaticOrDynamicDepTag,
132 checkGlobalAllowlistedDep: depIsGloballyAllowlisted,
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000133}
134
Jihoon Kang17a61d72024-08-12 22:26:52 +0000135// ----------------------------------------------------------------------------
136// Start of the definitions of container determination functions.
137//
138// Similar to the above section, below defines the functions used to determine
139// the container of each modules.
140// ----------------------------------------------------------------------------
141
142type containerBoundaryFunc func(mctx ModuleContext) bool
143
144var vendorContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
145 m, ok := mctx.Module().(ImageInterface)
146 return mctx.Module().InstallInVendor() || (ok && m.VendorVariantNeeded(mctx))
147}
148
149var systemContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
150 module := mctx.Module()
151
152 return !module.InstallInTestcases() &&
153 !module.InstallInData() &&
154 !module.InstallInRamdisk() &&
155 !module.InstallInVendorRamdisk() &&
156 !module.InstallInDebugRamdisk() &&
157 !module.InstallInRecovery() &&
158 !module.InstallInVendor() &&
159 !module.InstallInOdm() &&
160 !module.InstallInProduct() &&
161 determineModuleKind(module.base(), mctx.blueprintBaseModuleContext()) == platformModule
162}
163
164var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
165 m, ok := mctx.Module().(ImageInterface)
166 return mctx.Module().InstallInProduct() || (ok && m.ProductVariantNeeded(mctx))
167}
168
169var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
Colin Cross1cea5302024-12-03 16:40:08 -0800170 // TODO(b/394955484): a module can't determine the apexes it belongs to any more
171 return false
Jihoon Kang17a61d72024-08-12 22:26:52 +0000172}
173
174var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
175 props := mctx.Module().GetProperties()
176 for _, prop := range props {
177 val := reflect.ValueOf(prop).Elem()
178 if val.Kind() == reflect.Struct {
179 testSuites := val.FieldByName("Test_suites")
180 if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
181 return true
182 }
183 }
184 }
185 return false
186}
187
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000188type unstableInfo struct {
189 // Determines if the module contains the private APIs of the platform.
190 ContainsPlatformPrivateApis bool
191}
192
193var unstableInfoProvider = blueprint.NewProvider[unstableInfo]()
194
195func determineUnstableModule(mctx ModuleContext) bool {
196 module := mctx.Module()
Makoto Onuki31db53a2024-12-06 16:40:47 -0800197
Makoto Onukif3d66a32025-01-02 12:50:54 -0800198 unstableModule := module.Name() == "framework-minus-apex"
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000199 if installable, ok := module.(InstallableModule); ok {
200 for _, staticDepTag := range installable.StaticDependencyTags() {
Yu Liu9b19cd52025-01-23 23:01:45 +0000201 mctx.VisitDirectDepsProxyWithTag(staticDepTag, func(dep ModuleProxy) {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000202 if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok {
203 unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis
204 }
205 })
206 }
207 }
208 return unstableModule
209}
210
211var unstableContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
212 return determineUnstableModule(mctx)
213}
214
Jihoon Kang17a61d72024-08-12 22:26:52 +0000215// Map of [*container] to the [containerBoundaryFunc]
216var containerBoundaryFunctionsTable = map[*container]containerBoundaryFunc{
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000217 VendorContainer: vendorContainerBoundaryFunc,
218 SystemContainer: systemContainerBoundaryFunc,
219 ProductContainer: productContainerBoundaryFunc,
220 ApexContainer: apexContainerBoundaryFunc,
221 CtsContainer: ctsContainerBoundaryFunc,
222 UnstableContainer: unstableContainerBoundaryFunc,
Jihoon Kang17a61d72024-08-12 22:26:52 +0000223}
224
225// ----------------------------------------------------------------------------
226// End of the definitions of container determination functions.
227// ----------------------------------------------------------------------------
228
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000229type InstallableModule interface {
Jihoon Kang224ea082024-08-12 22:38:16 +0000230 StaticDependencyTags() []blueprint.DependencyTag
231 DynamicDependencyTags() []blueprint.DependencyTag
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000232}
233
234type restriction struct {
235 // container of the dependency
236 dependency *container
237
238 // Error message to be emitted to the user when the dependency meets this restriction
239 errorMessage string
240
241 // List of labels of allowed exception functions that allows bypassing this restriction.
242 // If any of the functions mapped to each labels returns true, this dependency would be
243 // considered allowed and an error will not be thrown.
244 allowedExceptions []exceptionHandleFuncLabel
245}
246type container struct {
247 // The name of the container i.e. partition, api domain
248 name string
249
250 // Map of dependency restricted containers.
251 restricted []restriction
252}
253
254var (
255 VendorContainer = &container{
256 name: VendorVariation,
257 restricted: nil,
258 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000259
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000260 SystemContainer = &container{
261 name: "system",
262 restricted: []restriction{
263 {
264 dependency: VendorContainer,
265 errorMessage: "Module belonging to the system partition other than HALs is " +
266 "not allowed to depend on the vendor partition module, in order to support " +
267 "independent development/update cycles and to support the Generic System " +
268 "Image. Try depending on HALs, VNDK or AIDL instead.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000269 allowedExceptions: []exceptionHandleFuncLabel{
270 checkStubs,
271 checkNotDynamicDepTag,
272 checkGlobalAllowlistedDep,
273 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000274 },
275 },
276 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000277
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000278 ProductContainer = &container{
279 name: ProductVariation,
280 restricted: []restriction{
281 {
282 dependency: VendorContainer,
283 errorMessage: "Module belonging to the product partition is not allowed to " +
284 "depend on the vendor partition module, as this may lead to security " +
285 "vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000286 allowedExceptions: []exceptionHandleFuncLabel{
287 checkStubs,
288 checkNotDynamicDepTag,
289 checkGlobalAllowlistedDep,
290 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000291 },
292 },
293 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000294
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000295 ApexContainer = initializeApexContainer()
Jihoon Kang17a61d72024-08-12 22:26:52 +0000296
297 CtsContainer = &container{
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000298 name: "cts",
299 restricted: []restriction{
300 {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000301 dependency: UnstableContainer,
302 errorMessage: "CTS module should not depend on the modules that contain the " +
303 "platform implementation details, including \"framework\". Depending on these " +
304 "modules may lead to disclosure of implementation details and regression " +
305 "due to API changes across platform versions. Try depending on the stubs instead " +
306 "and ensure that the module sets an appropriate 'sdk_version'.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000307 allowedExceptions: []exceptionHandleFuncLabel{
308 checkStubs,
309 checkNotStaticOrDynamicDepTag,
310 checkGlobalAllowlistedDep,
311 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000312 },
313 },
314 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000315
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000316 // Container signifying that the module contains unstable platform private APIs
317 UnstableContainer = &container{
318 name: "unstable",
319 restricted: nil,
320 }
321
Jihoon Kang17a61d72024-08-12 22:26:52 +0000322 allContainers = []*container{
323 VendorContainer,
324 SystemContainer,
325 ProductContainer,
326 ApexContainer,
327 CtsContainer,
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000328 UnstableContainer,
Jihoon Kang17a61d72024-08-12 22:26:52 +0000329 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000330)
331
332func initializeApexContainer() *container {
333 apexContainer := &container{
334 name: "apex",
335 restricted: []restriction{
336 {
337 dependency: SystemContainer,
338 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
339 "modules belonging to the system partition. Either statically depend on the " +
340 "module or convert the depending module to java_sdk_library and depend on " +
341 "the stubs.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000342 allowedExceptions: []exceptionHandleFuncLabel{
343 checkStubs,
344 checkApexModule,
345 checkInCommonApexes,
346 checkApexIsNonUpdatable,
347 checkNotStaticOrDynamicDepTag,
348 checkGlobalAllowlistedDep,
349 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000350 },
351 },
352 }
353
354 apexContainer.restricted = append(apexContainer.restricted, restriction{
355 dependency: apexContainer,
356 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
357 "modules belonging to other Apex(es). Either include the depending " +
358 "module in the Apex or convert the depending module to java_sdk_library " +
359 "and depend on its stubs.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000360 allowedExceptions: []exceptionHandleFuncLabel{
361 checkStubs,
362 checkInCommonApexes,
363 checkNotStaticOrDynamicDepTag,
364 checkGlobalAllowlistedDep,
365 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000366 })
367
368 return apexContainer
369}
370
371type ContainersInfo struct {
372 belongingContainers []*container
373
374 belongingApexes []ApexInfo
375}
376
377func (c *ContainersInfo) BelongingContainers() []*container {
378 return c.belongingContainers
379}
380
Jihoon Kang17a61d72024-08-12 22:26:52 +0000381func (c *ContainersInfo) ApexNames() (ret []string) {
382 for _, apex := range c.belongingApexes {
Colin Cross1cea5302024-12-03 16:40:08 -0800383 ret = append(ret, apex.BaseApexName)
Jihoon Kang17a61d72024-08-12 22:26:52 +0000384 }
385 slices.Sort(ret)
386 return ret
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000387}
388
Jihoon Kang17a61d72024-08-12 22:26:52 +0000389// Returns true if any of the apex the module belongs to is updatable.
390func (c *ContainersInfo) UpdatableApex() bool {
391 for _, apex := range c.belongingApexes {
392 if apex.Updatable {
393 return true
394 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000395 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000396 return false
397}
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000398
Jihoon Kang17a61d72024-08-12 22:26:52 +0000399var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
400
Yu Liu97880e12025-01-07 19:03:34 +0000401func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m Module, dep ModuleProxy) bool {
Jihoon Kang85bc1932024-07-01 17:04:46 +0000402 for _, label := range allowedExceptionLabels {
403 if exceptionHandleFunctionsTable[label](ctx, m, dep) {
404 return true
405 }
406 }
407 return false
408}
409
Yu Liu97880e12025-01-07 19:03:34 +0000410func (c *ContainersInfo) GetViolations(mctx ModuleContext, m Module, dep ModuleProxy, depInfo ContainersInfo) []string {
Jihoon Kang85bc1932024-07-01 17:04:46 +0000411 var violations []string
412
413 // Any containers that the module belongs to but the dependency does not belong to must be examined.
414 _, containersUniqueToModule, _ := ListSetDifference(c.belongingContainers, depInfo.belongingContainers)
415
416 // Apex container should be examined even if both the module and the dependency belong to
417 // the apex container to check that the two modules belong to the same apex.
418 if InList(ApexContainer, c.belongingContainers) && !InList(ApexContainer, containersUniqueToModule) {
419 containersUniqueToModule = append(containersUniqueToModule, ApexContainer)
420 }
421
422 for _, containerUniqueToModule := range containersUniqueToModule {
423 for _, restriction := range containerUniqueToModule.restricted {
424 if InList(restriction.dependency, depInfo.belongingContainers) {
425 if !satisfyAllowedExceptions(mctx, restriction.allowedExceptions, m, dep) {
426 violations = append(violations, restriction.errorMessage)
427 }
428 }
429 }
430 }
431
432 return violations
433}
434
Jihoon Kang17a61d72024-08-12 22:26:52 +0000435func generateContainerInfo(ctx ModuleContext) ContainersInfo {
436 var containers []*container
437
438 for _, cnt := range allContainers {
439 if containerBoundaryFunctionsTable[cnt](ctx) {
440 containers = append(containers, cnt)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000441 }
442 }
443
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000444 return ContainersInfo{
445 belongingContainers: containers,
Colin Cross1cea5302024-12-03 16:40:08 -0800446 // TODO(b/394955484): a module can't determine the apexes it belongs to any more
447 belongingApexes: nil,
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000448 }
449}
450
Jihoon Kang224ea082024-08-12 22:38:16 +0000451func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
Yu Liue472c1d2025-02-26 20:13:04 +0000452 if EqualModules(ctx.Module(), module) {
Yu Liu9a993132024-08-27 23:21:06 +0000453 return ctx.getContainersInfo(), true
Jihoon Kang224ea082024-08-12 22:38:16 +0000454 }
455
456 return OtherModuleProvider(ctx, module, ContainersInfoProvider)
457}
458
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000459func setContainerInfo(ctx ModuleContext) {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000460 // Required to determine the unstable container. This provider is set here instead of the
461 // unstableContainerBoundaryFunc in order to prevent setting the provider multiple times.
462 SetProvider(ctx, unstableInfoProvider, unstableInfo{
463 ContainsPlatformPrivateApis: determineUnstableModule(ctx),
464 })
465
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000466 if _, ok := ctx.Module().(InstallableModule); ok {
467 containersInfo := generateContainerInfo(ctx)
Yu Liu9a993132024-08-27 23:21:06 +0000468 ctx.setContainersInfo(containersInfo)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000469 SetProvider(ctx, ContainersInfoProvider, containersInfo)
470 }
471}
Jihoon Kang85bc1932024-07-01 17:04:46 +0000472
473func checkContainerViolations(ctx ModuleContext) {
474 if _, ok := ctx.Module().(InstallableModule); ok {
475 containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module())
Yu Liu97880e12025-01-07 19:03:34 +0000476 ctx.VisitDirectDepsProxy(func(dep ModuleProxy) {
477 if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).Enabled {
Jihoon Kang85bc1932024-07-01 17:04:46 +0000478 return
479 }
480
481 // Pre-existing violating dependencies are tracked in containerDependencyViolationAllowlist.
482 // If this dependency is allowlisted, do not check for violation.
483 // If not, check if this dependency matches any restricted dependency and
484 // satisfies any exception functions, which allows bypassing the
485 // restriction. If all of the exceptions are not satisfied, throw an error.
486 if depContainersInfo, ok := getContainerModuleInfo(ctx, dep); ok {
487 if allowedViolations, ok := ContainerDependencyViolationAllowlist[ctx.ModuleName()]; ok && InList(dep.Name(), allowedViolations) {
488 return
489 } else {
490 violations := containersInfo.GetViolations(ctx, ctx.Module(), dep, depContainersInfo)
491 if len(violations) > 0 {
492 errorMessage := fmt.Sprintf("%s cannot depend on %s. ", ctx.ModuleName(), dep.Name())
493 errorMessage += strings.Join(violations, " ")
494 ctx.ModuleErrorf(errorMessage)
495 }
496 }
497 }
498 })
499 }
500}