blob: 722b241c1022165b02781ff70205e67b657f673b [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 (
18 "reflect"
19 "slices"
20
21 "github.com/google/blueprint"
22)
23
Jihoon Kang17a61d72024-08-12 22:26:52 +000024// ----------------------------------------------------------------------------
25// Start of the definitions of exception functions and the lookup table.
26//
27// Functions cannot be used as a value passed in providers, because functions are not
28// hashable. As a workaround, the [exceptionHandleFuncLabel] enum values are passed using providers,
29// and the corresponding functions are called from [exceptionHandleFunctionsTable] map.
30// ----------------------------------------------------------------------------
31
32type exceptionHandleFunc func(ModuleContext, Module, Module) bool
33
Jihoon Kangc3d4e112024-06-24 22:16:27 +000034type StubsAvailableModule interface {
35 IsStubsModule() bool
36}
37
38// Returns true if the dependency module is a stubs module
Jihoon Kang17a61d72024-08-12 22:26:52 +000039var depIsStubsModule exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
Jihoon Kangc3d4e112024-06-24 22:16:27 +000040 if stubsModule, ok := dep.(StubsAvailableModule); ok {
41 return stubsModule.IsStubsModule()
42 }
43 return false
44}
45
Jihoon Kang224ea082024-08-12 22:38:16 +000046// Returns true if the dependency module belongs to any of the apexes.
47var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _, dep Module) bool {
48 depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
49 return InList(ApexContainer, depContainersInfo.belongingContainers)
50}
51
52// Returns true if the module and the dependent module belongs to common apexes.
53var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m, dep Module) bool {
54 mContainersInfo, _ := getContainerModuleInfo(mctx, m)
55 depContainersInfo, _ := getContainerModuleInfo(mctx, dep)
56
57 return HasIntersection(mContainersInfo.ApexNames(), depContainersInfo.ApexNames())
58}
59
60// Returns true when all apexes that the module belongs to are non updatable.
61// For an apex module to be allowed to depend on a non-apex partition module,
62// all apexes that the module belong to must be non updatable.
63var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m, _ Module) bool {
64 mContainersInfo, _ := getContainerModuleInfo(mctx, m)
65
66 return !mContainersInfo.UpdatableApex()
67}
68
69// Returns true if the dependency is added via dependency tags that are not used to tag dynamic
70// dependency tags.
71var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
72 mInstallable, _ := m.(InstallableModule)
73 depTag := ctx.OtherModuleDependencyTag(dep)
74 return !InList(depTag, mInstallable.DynamicDependencyTags())
75}
76
77// Returns true if the dependency is added via dependency tags that are not used to tag static
78// or dynamic dependency tags. These dependencies do not affect the module in compile time or in
79// runtime, thus are not significant enough to raise an error.
80var depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool {
81 mInstallable, _ := m.(InstallableModule)
82 depTag := ctx.OtherModuleDependencyTag(dep)
83 return !InList(depTag, append(mInstallable.StaticDependencyTags(), mInstallable.DynamicDependencyTags()...))
84}
85
86var globallyAllowlistedDependencies = []string{
87 // Modules that provide annotations used within the platform and apexes.
88 "aconfig-annotations-lib",
89 "framework-annotations-lib",
90 "unsupportedappusage",
91
Jihoon Kangbf65d1b2024-08-29 18:49:00 +000092 // TODO(b/363016634): Remove from the allowlist when the module is converted
93 // to java_sdk_library and the java_aconfig_library modules depend on the stub.
94 "aconfig_storage_reader_java",
95
Jihoon Kang224ea082024-08-12 22:38:16 +000096 // framework-res provides core resources essential for building apps and system UI.
97 // This module is implicitly added as a dependency for java modules even when the
98 // dependency specifies sdk_version.
99 "framework-res",
Jihoon Kang601939d2024-08-27 17:27:52 +0000100
101 // jacocoagent is implicitly added as a dependency in coverage builds, and is not installed
102 // on the device.
103 "jacocoagent",
Jihoon Kang224ea082024-08-12 22:38:16 +0000104}
105
106// Returns true when the dependency is globally allowlisted for inter-container dependency
107var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
108 return InList(dep.Name(), globallyAllowlistedDependencies)
109}
110
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000111// Labels of exception functions, which are used to determine special dependencies that allow
112// otherwise restricted inter-container dependencies
113type exceptionHandleFuncLabel int
114
115const (
116 checkStubs exceptionHandleFuncLabel = iota
Jihoon Kang224ea082024-08-12 22:38:16 +0000117 checkApexModule
118 checkInCommonApexes
119 checkApexIsNonUpdatable
120 checkNotDynamicDepTag
121 checkNotStaticOrDynamicDepTag
122 checkGlobalAllowlistedDep
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000123)
124
Jihoon Kang224ea082024-08-12 22:38:16 +0000125// Map of [exceptionHandleFuncLabel] to the [exceptionHandleFunc]
Jihoon Kang17a61d72024-08-12 22:26:52 +0000126var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
Jihoon Kang224ea082024-08-12 22:38:16 +0000127 checkStubs: depIsStubsModule,
128 checkApexModule: depIsApexModule,
129 checkInCommonApexes: belongsToCommonApexes,
130 checkApexIsNonUpdatable: belongsToNonUpdatableApex,
131 checkNotDynamicDepTag: depIsNotDynamicDepTag,
132 checkNotStaticOrDynamicDepTag: depIsNotStaticOrDynamicDepTag,
133 checkGlobalAllowlistedDep: depIsGloballyAllowlisted,
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000134}
135
Jihoon Kang17a61d72024-08-12 22:26:52 +0000136// ----------------------------------------------------------------------------
137// Start of the definitions of container determination functions.
138//
139// Similar to the above section, below defines the functions used to determine
140// the container of each modules.
141// ----------------------------------------------------------------------------
142
143type containerBoundaryFunc func(mctx ModuleContext) bool
144
145var vendorContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
146 m, ok := mctx.Module().(ImageInterface)
147 return mctx.Module().InstallInVendor() || (ok && m.VendorVariantNeeded(mctx))
148}
149
150var systemContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
151 module := mctx.Module()
152
153 return !module.InstallInTestcases() &&
154 !module.InstallInData() &&
155 !module.InstallInRamdisk() &&
156 !module.InstallInVendorRamdisk() &&
157 !module.InstallInDebugRamdisk() &&
158 !module.InstallInRecovery() &&
159 !module.InstallInVendor() &&
160 !module.InstallInOdm() &&
161 !module.InstallInProduct() &&
162 determineModuleKind(module.base(), mctx.blueprintBaseModuleContext()) == platformModule
163}
164
165var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
166 m, ok := mctx.Module().(ImageInterface)
167 return mctx.Module().InstallInProduct() || (ok && m.ProductVariantNeeded(mctx))
168}
169
170var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
171 _, ok := ModuleProvider(mctx, AllApexInfoProvider)
172 return ok
173}
174
175var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
176 props := mctx.Module().GetProperties()
177 for _, prop := range props {
178 val := reflect.ValueOf(prop).Elem()
179 if val.Kind() == reflect.Struct {
180 testSuites := val.FieldByName("Test_suites")
181 if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
182 return true
183 }
184 }
185 }
186 return false
187}
188
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000189type unstableInfo struct {
190 // Determines if the module contains the private APIs of the platform.
191 ContainsPlatformPrivateApis bool
192}
193
194var unstableInfoProvider = blueprint.NewProvider[unstableInfo]()
195
196func determineUnstableModule(mctx ModuleContext) bool {
197 module := mctx.Module()
198 unstableModule := module.Name() == "framework-minus-apex"
199 if installable, ok := module.(InstallableModule); ok {
200 for _, staticDepTag := range installable.StaticDependencyTags() {
201 mctx.VisitDirectDepsWithTag(staticDepTag, func(dep Module) {
202 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 {
383 ret = append(ret, apex.InApexModules...)
384 }
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
401func generateContainerInfo(ctx ModuleContext) ContainersInfo {
402 var containers []*container
403
404 for _, cnt := range allContainers {
405 if containerBoundaryFunctionsTable[cnt](ctx) {
406 containers = append(containers, cnt)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000407 }
408 }
409
410 var belongingApexes []ApexInfo
411 if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
412 belongingApexes = apexInfo.ApexInfos
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000413 }
414
415 return ContainersInfo{
416 belongingContainers: containers,
417 belongingApexes: belongingApexes,
418 }
419}
420
Jihoon Kang224ea082024-08-12 22:38:16 +0000421func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
422 if ctx.Module() == module {
Yu Liu9a993132024-08-27 23:21:06 +0000423 return ctx.getContainersInfo(), true
Jihoon Kang224ea082024-08-12 22:38:16 +0000424 }
425
426 return OtherModuleProvider(ctx, module, ContainersInfoProvider)
427}
428
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000429func setContainerInfo(ctx ModuleContext) {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000430 // Required to determine the unstable container. This provider is set here instead of the
431 // unstableContainerBoundaryFunc in order to prevent setting the provider multiple times.
432 SetProvider(ctx, unstableInfoProvider, unstableInfo{
433 ContainsPlatformPrivateApis: determineUnstableModule(ctx),
434 })
435
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000436 if _, ok := ctx.Module().(InstallableModule); ok {
437 containersInfo := generateContainerInfo(ctx)
Yu Liu9a993132024-08-27 23:21:06 +0000438 ctx.setContainersInfo(containersInfo)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000439 SetProvider(ctx, ContainersInfoProvider, containersInfo)
440 }
441}