blob: 05897dd6c638e3c494ac74e19ac6620411ac28d4 [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
46// Labels of exception functions, which are used to determine special dependencies that allow
47// otherwise restricted inter-container dependencies
48type exceptionHandleFuncLabel int
49
50const (
51 checkStubs exceptionHandleFuncLabel = iota
52)
53
Jihoon Kang17a61d72024-08-12 22:26:52 +000054var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]exceptionHandleFunc{
Jihoon Kangc3d4e112024-06-24 22:16:27 +000055 checkStubs: depIsStubsModule,
56}
57
Jihoon Kang17a61d72024-08-12 22:26:52 +000058// ----------------------------------------------------------------------------
59// Start of the definitions of container determination functions.
60//
61// Similar to the above section, below defines the functions used to determine
62// the container of each modules.
63// ----------------------------------------------------------------------------
64
65type containerBoundaryFunc func(mctx ModuleContext) bool
66
67var vendorContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
68 m, ok := mctx.Module().(ImageInterface)
69 return mctx.Module().InstallInVendor() || (ok && m.VendorVariantNeeded(mctx))
70}
71
72var systemContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
73 module := mctx.Module()
74
75 return !module.InstallInTestcases() &&
76 !module.InstallInData() &&
77 !module.InstallInRamdisk() &&
78 !module.InstallInVendorRamdisk() &&
79 !module.InstallInDebugRamdisk() &&
80 !module.InstallInRecovery() &&
81 !module.InstallInVendor() &&
82 !module.InstallInOdm() &&
83 !module.InstallInProduct() &&
84 determineModuleKind(module.base(), mctx.blueprintBaseModuleContext()) == platformModule
85}
86
87var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
88 m, ok := mctx.Module().(ImageInterface)
89 return mctx.Module().InstallInProduct() || (ok && m.ProductVariantNeeded(mctx))
90}
91
92var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
93 _, ok := ModuleProvider(mctx, AllApexInfoProvider)
94 return ok
95}
96
97var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool {
98 props := mctx.Module().GetProperties()
99 for _, prop := range props {
100 val := reflect.ValueOf(prop).Elem()
101 if val.Kind() == reflect.Struct {
102 testSuites := val.FieldByName("Test_suites")
103 if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
104 return true
105 }
106 }
107 }
108 return false
109}
110
111// Map of [*container] to the [containerBoundaryFunc]
112var containerBoundaryFunctionsTable = map[*container]containerBoundaryFunc{
113 VendorContainer: vendorContainerBoundaryFunc,
114 SystemContainer: systemContainerBoundaryFunc,
115 ProductContainer: productContainerBoundaryFunc,
116 ApexContainer: apexContainerBoundaryFunc,
117 CtsContainer: ctsContainerBoundaryFunc,
118}
119
120// ----------------------------------------------------------------------------
121// End of the definitions of container determination functions.
122// ----------------------------------------------------------------------------
123
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000124type InstallableModule interface {
125 EnforceApiContainerChecks() bool
126}
127
128type restriction struct {
129 // container of the dependency
130 dependency *container
131
132 // Error message to be emitted to the user when the dependency meets this restriction
133 errorMessage string
134
135 // List of labels of allowed exception functions that allows bypassing this restriction.
136 // If any of the functions mapped to each labels returns true, this dependency would be
137 // considered allowed and an error will not be thrown.
138 allowedExceptions []exceptionHandleFuncLabel
139}
140type container struct {
141 // The name of the container i.e. partition, api domain
142 name string
143
144 // Map of dependency restricted containers.
145 restricted []restriction
146}
147
148var (
149 VendorContainer = &container{
150 name: VendorVariation,
151 restricted: nil,
152 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000153
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000154 SystemContainer = &container{
155 name: "system",
156 restricted: []restriction{
157 {
158 dependency: VendorContainer,
159 errorMessage: "Module belonging to the system partition other than HALs is " +
160 "not allowed to depend on the vendor partition module, in order to support " +
161 "independent development/update cycles and to support the Generic System " +
162 "Image. Try depending on HALs, VNDK or AIDL instead.",
163 allowedExceptions: []exceptionHandleFuncLabel{},
164 },
165 },
166 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000167
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000168 ProductContainer = &container{
169 name: ProductVariation,
170 restricted: []restriction{
171 {
172 dependency: VendorContainer,
173 errorMessage: "Module belonging to the product partition is not allowed to " +
174 "depend on the vendor partition module, as this may lead to security " +
175 "vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
176 allowedExceptions: []exceptionHandleFuncLabel{},
177 },
178 },
179 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000180
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000181 ApexContainer = initializeApexContainer()
Jihoon Kang17a61d72024-08-12 22:26:52 +0000182
183 CtsContainer = &container{
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000184 name: "cts",
185 restricted: []restriction{
186 {
187 dependency: SystemContainer,
188 errorMessage: "CTS module should not depend on the modules belonging to the " +
189 "system partition, including \"framework\". Depending on the system " +
190 "partition may lead to disclosure of implementation details and regression " +
191 "due to API changes across platform versions. Try depending on the stubs instead.",
192 allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
193 },
194 },
195 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000196
197 allContainers = []*container{
198 VendorContainer,
199 SystemContainer,
200 ProductContainer,
201 ApexContainer,
202 CtsContainer,
203 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000204)
205
206func initializeApexContainer() *container {
207 apexContainer := &container{
208 name: "apex",
209 restricted: []restriction{
210 {
211 dependency: SystemContainer,
212 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
213 "modules belonging to the system partition. Either statically depend on the " +
214 "module or convert the depending module to java_sdk_library and depend on " +
215 "the stubs.",
216 allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
217 },
218 },
219 }
220
221 apexContainer.restricted = append(apexContainer.restricted, restriction{
222 dependency: apexContainer,
223 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
224 "modules belonging to other Apex(es). Either include the depending " +
225 "module in the Apex or convert the depending module to java_sdk_library " +
226 "and depend on its stubs.",
227 allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
228 })
229
230 return apexContainer
231}
232
233type ContainersInfo struct {
234 belongingContainers []*container
235
236 belongingApexes []ApexInfo
237}
238
239func (c *ContainersInfo) BelongingContainers() []*container {
240 return c.belongingContainers
241}
242
Jihoon Kang17a61d72024-08-12 22:26:52 +0000243func (c *ContainersInfo) ApexNames() (ret []string) {
244 for _, apex := range c.belongingApexes {
245 ret = append(ret, apex.InApexModules...)
246 }
247 slices.Sort(ret)
248 return ret
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000249}
250
Jihoon Kang17a61d72024-08-12 22:26:52 +0000251// Returns true if any of the apex the module belongs to is updatable.
252func (c *ContainersInfo) UpdatableApex() bool {
253 for _, apex := range c.belongingApexes {
254 if apex.Updatable {
255 return true
256 }
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000257 }
Jihoon Kang17a61d72024-08-12 22:26:52 +0000258 return false
259}
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000260
Jihoon Kang17a61d72024-08-12 22:26:52 +0000261var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
262
263func generateContainerInfo(ctx ModuleContext) ContainersInfo {
264 var containers []*container
265
266 for _, cnt := range allContainers {
267 if containerBoundaryFunctionsTable[cnt](ctx) {
268 containers = append(containers, cnt)
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000269 }
270 }
271
272 var belongingApexes []ApexInfo
273 if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
274 belongingApexes = apexInfo.ApexInfos
Jihoon Kangc3d4e112024-06-24 22:16:27 +0000275 }
276
277 return ContainersInfo{
278 belongingContainers: containers,
279 belongingApexes: belongingApexes,
280 }
281}
282
283func setContainerInfo(ctx ModuleContext) {
284 if _, ok := ctx.Module().(InstallableModule); ok {
285 containersInfo := generateContainerInfo(ctx)
286 SetProvider(ctx, ContainersInfoProvider, containersInfo)
287 }
288}