blob: f01c076066144947e3992029683281c1de25bcfd [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
92 // framework-res provides core resources essential for building apps and system UI.
93 // This module is implicitly added as a dependency for java modules even when the
94 // dependency specifies sdk_version.
95 "framework-res",
96}
97
98// Returns true when the dependency is globally allowlisted for inter-container dependency
99var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
100 return InList(dep.Name(), globallyAllowlistedDependencies)
101}
102
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000103// Labels of exception functions, which are used to determine special dependencies that allow
104// otherwise restricted inter-container dependencies
105type exceptionHandleFuncLabel int
106
107const (
108 checkStubs exceptionHandleFuncLabel = iota
Jihoon Kang224ea082024-08-12 22:38:16 +0000109 checkApexModule
110 checkInCommonApexes
111 checkApexIsNonUpdatable
112 checkNotDynamicDepTag
113 checkNotStaticOrDynamicDepTag
114 checkGlobalAllowlistedDep
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000115)
116
Jihoon Kang224ea082024-08-12 22:38:16 +0000117// Map of [exceptionHandleFuncLabel] to the [exceptionHandleFunc]
Jihoon Kang17a61d72024-08-12 22:26:52 +0000118var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
Jihoon Kang224ea082024-08-12 22:38:16 +0000119 checkStubs: depIsStubsModule,
120 checkApexModule: depIsApexModule,
121 checkInCommonApexes: belongsToCommonApexes,
122 checkApexIsNonUpdatable: belongsToNonUpdatableApex,
123 checkNotDynamicDepTag: depIsNotDynamicDepTag,
124 checkNotStaticOrDynamicDepTag: depIsNotStaticOrDynamicDepTag,
125 checkGlobalAllowlistedDep: depIsGloballyAllowlisted,
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000126}
127
Jihoon Kang17a61d72024-08-12 22:26:52 +0000128// ----------------------------------------------------------------------------
129// Start of the definitions of container determination functions.
130//
131// Similar to the above section, below defines the functions used to determine
132// the container of each modules.
133// ----------------------------------------------------------------------------
134
135type containerBoundaryFunc func(mctx ModuleContext) bool
136
137var vendorContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
138 m, ok := mctx.Module().(ImageInterface)
139 return mctx.Module().InstallInVendor() || (ok && m.VendorVariantNeeded(mctx))
140}
141
142var systemContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
143 module := mctx.Module()
144
145 return !module.InstallInTestcases() &&
146 !module.InstallInData() &&
147 !module.InstallInRamdisk() &&
148 !module.InstallInVendorRamdisk() &&
149 !module.InstallInDebugRamdisk() &&
150 !module.InstallInRecovery() &&
151 !module.InstallInVendor() &&
152 !module.InstallInOdm() &&
153 !module.InstallInProduct() &&
154 determineModuleKind(module.base(), mctx.blueprintBaseModuleContext()) == platformModule
155}
156
157var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
158 m, ok := mctx.Module().(ImageInterface)
159 return mctx.Module().InstallInProduct() || (ok && m.ProductVariantNeeded(mctx))
160}
161
162var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
163 _, ok := ModuleProvider(mctx, AllApexInfoProvider)
164 return ok
165}
166
167var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
168 props := mctx.Module().GetProperties()
169 for _, prop := range props {
170 val := reflect.ValueOf(prop).Elem()
171 if val.Kind() == reflect.Struct {
172 testSuites := val.FieldByName("Test_suites")
173 if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
174 return true
175 }
176 }
177 }
178 return false
179}
180
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000181type unstableInfo struct {
182 // Determines if the module contains the private APIs of the platform.
183 ContainsPlatformPrivateApis bool
184}
185
186var unstableInfoProvider = blueprint.NewProvider[unstableInfo]()
187
188func determineUnstableModule(mctx ModuleContext) bool {
189 module := mctx.Module()
190 unstableModule := module.Name() == "framework-minus-apex"
191 if installable, ok := module.(InstallableModule); ok {
192 for _, staticDepTag := range installable.StaticDependencyTags() {
193 mctx.VisitDirectDepsWithTag(staticDepTag, func(dep Module) {
194 if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok {
195 unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis
196 }
197 })
198 }
199 }
200 return unstableModule
201}
202
203var unstableContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
204 return determineUnstableModule(mctx)
205}
206
Jihoon Kang17a61d72024-08-12 22:26:52 +0000207// Map of [*container] to the [containerBoundaryFunc]
208var containerBoundaryFunctionsTable = map[*container]containerBoundaryFunc{
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000209 VendorContainer: vendorContainerBoundaryFunc,
210 SystemContainer: systemContainerBoundaryFunc,
211 ProductContainer: productContainerBoundaryFunc,
212 ApexContainer: apexContainerBoundaryFunc,
213 CtsContainer: ctsContainerBoundaryFunc,
214 UnstableContainer: unstableContainerBoundaryFunc,
Jihoon Kang17a61d72024-08-12 22:26:52 +0000215}
216
217// ----------------------------------------------------------------------------
218// End of the definitions of container determination functions.
219// ----------------------------------------------------------------------------
220
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000221type InstallableModule interface {
Jihoon Kang224ea082024-08-12 22:38:16 +0000222 StaticDependencyTags() []blueprint.DependencyTag
223 DynamicDependencyTags() []blueprint.DependencyTag
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000224}
225
226type restriction struct {
227 // container of the dependency
228 dependency *container
229
230 // Error message to be emitted to the user when the dependency meets this restriction
231 errorMessage string
232
233 // List of labels of allowed exception functions that allows bypassing this restriction.
234 // If any of the functions mapped to each labels returns true, this dependency would be
235 // considered allowed and an error will not be thrown.
236 allowedExceptions []exceptionHandleFuncLabel
237}
238type container struct {
239 // The name of the container i.e. partition, api domain
240 name string
241
242 // Map of dependency restricted containers.
243 restricted []restriction
244}
245
246var (
247 VendorContainer = &container{
248 name: VendorVariation,
249 restricted: nil,
250 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000251
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000252 SystemContainer = &container{
253 name: "system",
254 restricted: []restriction{
255 {
256 dependency: VendorContainer,
257 errorMessage: "Module belonging to the system partition other than HALs is " +
258 "not allowed to depend on the vendor partition module, in order to support " +
259 "independent development/update cycles and to support the Generic System " +
260 "Image. Try depending on HALs, VNDK or AIDL instead.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000261 allowedExceptions: []exceptionHandleFuncLabel{
262 checkStubs,
263 checkNotDynamicDepTag,
264 checkGlobalAllowlistedDep,
265 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000266 },
267 },
268 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000269
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000270 ProductContainer = &container{
271 name: ProductVariation,
272 restricted: []restriction{
273 {
274 dependency: VendorContainer,
275 errorMessage: "Module belonging to the product partition is not allowed to " +
276 "depend on the vendor partition module, as this may lead to security " +
277 "vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000278 allowedExceptions: []exceptionHandleFuncLabel{
279 checkStubs,
280 checkNotDynamicDepTag,
281 checkGlobalAllowlistedDep,
282 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000283 },
284 },
285 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000286
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000287 ApexContainer = initializeApexContainer()
Jihoon Kang17a61d72024-08-12 22:26:52 +0000288
289 CtsContainer = &container{
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000290 name: "cts",
291 restricted: []restriction{
292 {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000293 dependency: UnstableContainer,
294 errorMessage: "CTS module should not depend on the modules that contain the " +
295 "platform implementation details, including \"framework\". Depending on these " +
296 "modules may lead to disclosure of implementation details and regression " +
297 "due to API changes across platform versions. Try depending on the stubs instead " +
298 "and ensure that the module sets an appropriate 'sdk_version'.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000299 allowedExceptions: []exceptionHandleFuncLabel{
300 checkStubs,
301 checkNotStaticOrDynamicDepTag,
302 checkGlobalAllowlistedDep,
303 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000304 },
305 },
306 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000307
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000308 // Container signifying that the module contains unstable platform private APIs
309 UnstableContainer = &container{
310 name: "unstable",
311 restricted: nil,
312 }
313
Jihoon Kang17a61d72024-08-12 22:26:52 +0000314 allContainers = []*container{
315 VendorContainer,
316 SystemContainer,
317 ProductContainer,
318 ApexContainer,
319 CtsContainer,
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000320 UnstableContainer,
Jihoon Kang17a61d72024-08-12 22:26:52 +0000321 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000322)
323
324func initializeApexContainer() *container {
325 apexContainer := &container{
326 name: "apex",
327 restricted: []restriction{
328 {
329 dependency: SystemContainer,
330 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
331 "modules belonging to the system partition. Either statically depend on the " +
332 "module or convert the depending module to java_sdk_library and depend on " +
333 "the stubs.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000334 allowedExceptions: []exceptionHandleFuncLabel{
335 checkStubs,
336 checkApexModule,
337 checkInCommonApexes,
338 checkApexIsNonUpdatable,
339 checkNotStaticOrDynamicDepTag,
340 checkGlobalAllowlistedDep,
341 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000342 },
343 },
344 }
345
346 apexContainer.restricted = append(apexContainer.restricted, restriction{
347 dependency: apexContainer,
348 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
349 "modules belonging to other Apex(es). Either include the depending " +
350 "module in the Apex or convert the depending module to java_sdk_library " +
351 "and depend on its stubs.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000352 allowedExceptions: []exceptionHandleFuncLabel{
353 checkStubs,
354 checkInCommonApexes,
355 checkNotStaticOrDynamicDepTag,
356 checkGlobalAllowlistedDep,
357 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000358 })
359
360 return apexContainer
361}
362
363type ContainersInfo struct {
364 belongingContainers []*container
365
366 belongingApexes []ApexInfo
367}
368
369func (c *ContainersInfo) BelongingContainers() []*container {
370 return c.belongingContainers
371}
372
Jihoon Kang17a61d72024-08-12 22:26:52 +0000373func (c *ContainersInfo) ApexNames() (ret []string) {
374 for _, apex := range c.belongingApexes {
375 ret = append(ret, apex.InApexModules...)
376 }
377 slices.Sort(ret)
378 return ret
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000379}
380
Jihoon Kang17a61d72024-08-12 22:26:52 +0000381// Returns true if any of the apex the module belongs to is updatable.
382func (c *ContainersInfo) UpdatableApex() bool {
383 for _, apex := range c.belongingApexes {
384 if apex.Updatable {
385 return true
386 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000387 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000388 return false
389}
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000390
Jihoon Kang17a61d72024-08-12 22:26:52 +0000391var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
392
393func generateContainerInfo(ctx ModuleContext) ContainersInfo {
394 var containers []*container
395
396 for _, cnt := range allContainers {
397 if containerBoundaryFunctionsTable[cnt](ctx) {
398 containers = append(containers, cnt)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000399 }
400 }
401
402 var belongingApexes []ApexInfo
403 if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
404 belongingApexes = apexInfo.ApexInfos
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000405 }
406
407 return ContainersInfo{
408 belongingContainers: containers,
409 belongingApexes: belongingApexes,
410 }
411}
412
Jihoon Kang224ea082024-08-12 22:38:16 +0000413func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
414 if ctx.Module() == module {
Yu Liu9a993132024-08-27 23:21:06 +0000415 return ctx.getContainersInfo(), true
Jihoon Kang224ea082024-08-12 22:38:16 +0000416 }
417
418 return OtherModuleProvider(ctx, module, ContainersInfoProvider)
419}
420
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000421func setContainerInfo(ctx ModuleContext) {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000422 // Required to determine the unstable container. This provider is set here instead of the
423 // unstableContainerBoundaryFunc in order to prevent setting the provider multiple times.
424 SetProvider(ctx, unstableInfoProvider, unstableInfo{
425 ContainsPlatformPrivateApis: determineUnstableModule(ctx),
426 })
427
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000428 if _, ok := ctx.Module().(InstallableModule); ok {
429 containersInfo := generateContainerInfo(ctx)
Yu Liu9a993132024-08-27 23:21:06 +0000430 ctx.setContainersInfo(containersInfo)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000431 SetProvider(ctx, ContainersInfoProvider, containersInfo)
432 }
433}