blob: 43dccf6357da58a3580cf9ae4caf778eb757bbb3 [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",
Jihoon Kang601939d2024-08-27 17:27:52 +000096
97 // jacocoagent is implicitly added as a dependency in coverage builds, and is not installed
98 // on the device.
99 "jacocoagent",
Jihoon Kang224ea082024-08-12 22:38:16 +0000100}
101
102// Returns true when the dependency is globally allowlisted for inter-container dependency
103var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool {
104 return InList(dep.Name(), globallyAllowlistedDependencies)
105}
106
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000107// Labels of exception functions, which are used to determine special dependencies that allow
108// otherwise restricted inter-container dependencies
109type exceptionHandleFuncLabel int
110
111const (
112 checkStubs exceptionHandleFuncLabel = iota
Jihoon Kang224ea082024-08-12 22:38:16 +0000113 checkApexModule
114 checkInCommonApexes
115 checkApexIsNonUpdatable
116 checkNotDynamicDepTag
117 checkNotStaticOrDynamicDepTag
118 checkGlobalAllowlistedDep
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000119)
120
Jihoon Kang224ea082024-08-12 22:38:16 +0000121// Map of [exceptionHandleFuncLabel] to the [exceptionHandleFunc]
Jihoon Kang17a61d72024-08-12 22:26:52 +0000122var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
Jihoon Kang224ea082024-08-12 22:38:16 +0000123 checkStubs: depIsStubsModule,
124 checkApexModule: depIsApexModule,
125 checkInCommonApexes: belongsToCommonApexes,
126 checkApexIsNonUpdatable: belongsToNonUpdatableApex,
127 checkNotDynamicDepTag: depIsNotDynamicDepTag,
128 checkNotStaticOrDynamicDepTag: depIsNotStaticOrDynamicDepTag,
129 checkGlobalAllowlistedDep: depIsGloballyAllowlisted,
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000130}
131
Jihoon Kang17a61d72024-08-12 22:26:52 +0000132// ----------------------------------------------------------------------------
133// Start of the definitions of container determination functions.
134//
135// Similar to the above section, below defines the functions used to determine
136// the container of each modules.
137// ----------------------------------------------------------------------------
138
139type containerBoundaryFunc func(mctx ModuleContext) bool
140
141var vendorContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
142 m, ok := mctx.Module().(ImageInterface)
143 return mctx.Module().InstallInVendor() || (ok && m.VendorVariantNeeded(mctx))
144}
145
146var systemContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
147 module := mctx.Module()
148
149 return !module.InstallInTestcases() &&
150 !module.InstallInData() &&
151 !module.InstallInRamdisk() &&
152 !module.InstallInVendorRamdisk() &&
153 !module.InstallInDebugRamdisk() &&
154 !module.InstallInRecovery() &&
155 !module.InstallInVendor() &&
156 !module.InstallInOdm() &&
157 !module.InstallInProduct() &&
158 determineModuleKind(module.base(), mctx.blueprintBaseModuleContext()) == platformModule
159}
160
161var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
162 m, ok := mctx.Module().(ImageInterface)
163 return mctx.Module().InstallInProduct() || (ok && m.ProductVariantNeeded(mctx))
164}
165
166var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
167 _, ok := ModuleProvider(mctx, AllApexInfoProvider)
168 return ok
169}
170
171var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
172 props := mctx.Module().GetProperties()
173 for _, prop := range props {
174 val := reflect.ValueOf(prop).Elem()
175 if val.Kind() == reflect.Struct {
176 testSuites := val.FieldByName("Test_suites")
177 if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
178 return true
179 }
180 }
181 }
182 return false
183}
184
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000185type unstableInfo struct {
186 // Determines if the module contains the private APIs of the platform.
187 ContainsPlatformPrivateApis bool
188}
189
190var unstableInfoProvider = blueprint.NewProvider[unstableInfo]()
191
192func determineUnstableModule(mctx ModuleContext) bool {
193 module := mctx.Module()
194 unstableModule := module.Name() == "framework-minus-apex"
195 if installable, ok := module.(InstallableModule); ok {
196 for _, staticDepTag := range installable.StaticDependencyTags() {
197 mctx.VisitDirectDepsWithTag(staticDepTag, func(dep Module) {
198 if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok {
199 unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis
200 }
201 })
202 }
203 }
204 return unstableModule
205}
206
207var unstableContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
208 return determineUnstableModule(mctx)
209}
210
Jihoon Kang17a61d72024-08-12 22:26:52 +0000211// Map of [*container] to the [containerBoundaryFunc]
212var containerBoundaryFunctionsTable = map[*container]containerBoundaryFunc{
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000213 VendorContainer: vendorContainerBoundaryFunc,
214 SystemContainer: systemContainerBoundaryFunc,
215 ProductContainer: productContainerBoundaryFunc,
216 ApexContainer: apexContainerBoundaryFunc,
217 CtsContainer: ctsContainerBoundaryFunc,
218 UnstableContainer: unstableContainerBoundaryFunc,
Jihoon Kang17a61d72024-08-12 22:26:52 +0000219}
220
221// ----------------------------------------------------------------------------
222// End of the definitions of container determination functions.
223// ----------------------------------------------------------------------------
224
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000225type InstallableModule interface {
Jihoon Kang224ea082024-08-12 22:38:16 +0000226 ContainersInfo() ContainersInfo
227 StaticDependencyTags() []blueprint.DependencyTag
228 DynamicDependencyTags() []blueprint.DependencyTag
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000229}
230
231type restriction struct {
232 // container of the dependency
233 dependency *container
234
235 // Error message to be emitted to the user when the dependency meets this restriction
236 errorMessage string
237
238 // List of labels of allowed exception functions that allows bypassing this restriction.
239 // If any of the functions mapped to each labels returns true, this dependency would be
240 // considered allowed and an error will not be thrown.
241 allowedExceptions []exceptionHandleFuncLabel
242}
243type container struct {
244 // The name of the container i.e. partition, api domain
245 name string
246
247 // Map of dependency restricted containers.
248 restricted []restriction
249}
250
251var (
252 VendorContainer = &container{
253 name: VendorVariation,
254 restricted: nil,
255 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000256
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000257 SystemContainer = &container{
258 name: "system",
259 restricted: []restriction{
260 {
261 dependency: VendorContainer,
262 errorMessage: "Module belonging to the system partition other than HALs is " +
263 "not allowed to depend on the vendor partition module, in order to support " +
264 "independent development/update cycles and to support the Generic System " +
265 "Image. Try depending on HALs, VNDK or AIDL instead.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000266 allowedExceptions: []exceptionHandleFuncLabel{
267 checkStubs,
268 checkNotDynamicDepTag,
269 checkGlobalAllowlistedDep,
270 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000271 },
272 },
273 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000274
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000275 ProductContainer = &container{
276 name: ProductVariation,
277 restricted: []restriction{
278 {
279 dependency: VendorContainer,
280 errorMessage: "Module belonging to the product partition is not allowed to " +
281 "depend on the vendor partition module, as this may lead to security " +
282 "vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000283 allowedExceptions: []exceptionHandleFuncLabel{
284 checkStubs,
285 checkNotDynamicDepTag,
286 checkGlobalAllowlistedDep,
287 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000288 },
289 },
290 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000291
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000292 ApexContainer = initializeApexContainer()
Jihoon Kang17a61d72024-08-12 22:26:52 +0000293
294 CtsContainer = &container{
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000295 name: "cts",
296 restricted: []restriction{
297 {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000298 dependency: UnstableContainer,
299 errorMessage: "CTS module should not depend on the modules that contain the " +
300 "platform implementation details, including \"framework\". Depending on these " +
301 "modules may lead to disclosure of implementation details and regression " +
302 "due to API changes across platform versions. Try depending on the stubs instead " +
303 "and ensure that the module sets an appropriate 'sdk_version'.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000304 allowedExceptions: []exceptionHandleFuncLabel{
305 checkStubs,
306 checkNotStaticOrDynamicDepTag,
307 checkGlobalAllowlistedDep,
308 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000309 },
310 },
311 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000312
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000313 // Container signifying that the module contains unstable platform private APIs
314 UnstableContainer = &container{
315 name: "unstable",
316 restricted: nil,
317 }
318
Jihoon Kang17a61d72024-08-12 22:26:52 +0000319 allContainers = []*container{
320 VendorContainer,
321 SystemContainer,
322 ProductContainer,
323 ApexContainer,
324 CtsContainer,
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000325 UnstableContainer,
Jihoon Kang17a61d72024-08-12 22:26:52 +0000326 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000327)
328
329func initializeApexContainer() *container {
330 apexContainer := &container{
331 name: "apex",
332 restricted: []restriction{
333 {
334 dependency: SystemContainer,
335 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
336 "modules belonging to the system partition. Either statically depend on the " +
337 "module or convert the depending module to java_sdk_library and depend on " +
338 "the stubs.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000339 allowedExceptions: []exceptionHandleFuncLabel{
340 checkStubs,
341 checkApexModule,
342 checkInCommonApexes,
343 checkApexIsNonUpdatable,
344 checkNotStaticOrDynamicDepTag,
345 checkGlobalAllowlistedDep,
346 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000347 },
348 },
349 }
350
351 apexContainer.restricted = append(apexContainer.restricted, restriction{
352 dependency: apexContainer,
353 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
354 "modules belonging to other Apex(es). Either include the depending " +
355 "module in the Apex or convert the depending module to java_sdk_library " +
356 "and depend on its stubs.",
Jihoon Kang224ea082024-08-12 22:38:16 +0000357 allowedExceptions: []exceptionHandleFuncLabel{
358 checkStubs,
359 checkInCommonApexes,
360 checkNotStaticOrDynamicDepTag,
361 checkGlobalAllowlistedDep,
362 },
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000363 })
364
365 return apexContainer
366}
367
368type ContainersInfo struct {
369 belongingContainers []*container
370
371 belongingApexes []ApexInfo
372}
373
374func (c *ContainersInfo) BelongingContainers() []*container {
375 return c.belongingContainers
376}
377
Jihoon Kang17a61d72024-08-12 22:26:52 +0000378func (c *ContainersInfo) ApexNames() (ret []string) {
379 for _, apex := range c.belongingApexes {
380 ret = append(ret, apex.InApexModules...)
381 }
382 slices.Sort(ret)
383 return ret
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000384}
385
Jihoon Kang17a61d72024-08-12 22:26:52 +0000386// Returns true if any of the apex the module belongs to is updatable.
387func (c *ContainersInfo) UpdatableApex() bool {
388 for _, apex := range c.belongingApexes {
389 if apex.Updatable {
390 return true
391 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000392 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000393 return false
394}
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000395
Jihoon Kang17a61d72024-08-12 22:26:52 +0000396var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
397
398func generateContainerInfo(ctx ModuleContext) ContainersInfo {
399 var containers []*container
400
401 for _, cnt := range allContainers {
402 if containerBoundaryFunctionsTable[cnt](ctx) {
403 containers = append(containers, cnt)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000404 }
405 }
406
407 var belongingApexes []ApexInfo
408 if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
409 belongingApexes = apexInfo.ApexInfos
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000410 }
411
412 return ContainersInfo{
413 belongingContainers: containers,
414 belongingApexes: belongingApexes,
415 }
416}
417
Jihoon Kang224ea082024-08-12 22:38:16 +0000418func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) {
419 if ctx.Module() == module {
420 return module.ContainersInfo(), true
421 }
422
423 return OtherModuleProvider(ctx, module, ContainersInfoProvider)
424}
425
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000426func setContainerInfo(ctx ModuleContext) {
Jihoon Kang0f3b1a72024-08-12 22:47:01 +0000427 // Required to determine the unstable container. This provider is set here instead of the
428 // unstableContainerBoundaryFunc in order to prevent setting the provider multiple times.
429 SetProvider(ctx, unstableInfoProvider, unstableInfo{
430 ContainsPlatformPrivateApis: determineUnstableModule(ctx),
431 })
432
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000433 if _, ok := ctx.Module().(InstallableModule); ok {
434 containersInfo := generateContainerInfo(ctx)
Jihoon Kang224ea082024-08-12 22:38:16 +0000435 ctx.Module().base().containersInfo = containersInfo
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000436 SetProvider(ctx, ContainersInfoProvider, containersInfo)
437 }
438}