blob: c4fdd9c91ee4cacd8b536a421ee6e58361f2cf40 [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
24type StubsAvailableModule interface {
25 IsStubsModule() bool
26}
27
28// Returns true if the dependency module is a stubs module
29var depIsStubsModule = func(_ ModuleContext, _, dep Module) bool {
30 if stubsModule, ok := dep.(StubsAvailableModule); ok {
31 return stubsModule.IsStubsModule()
32 }
33 return false
34}
35
36// Labels of exception functions, which are used to determine special dependencies that allow
37// otherwise restricted inter-container dependencies
38type exceptionHandleFuncLabel int
39
40const (
41 checkStubs exceptionHandleFuncLabel = iota
42)
43
44// Functions cannot be used as a value passed in providers, because functions are not
45// hashable. As a workaround, the exceptionHandleFunc enum values are passed using providers,
46// and the corresponding functions are called from this map.
47var exceptionHandleFunctionsTable = map[exceptionHandleFuncLabel]func(ModuleContext, Module, Module) bool{
48 checkStubs: depIsStubsModule,
49}
50
51type InstallableModule interface {
52 EnforceApiContainerChecks() bool
53}
54
55type restriction struct {
56 // container of the dependency
57 dependency *container
58
59 // Error message to be emitted to the user when the dependency meets this restriction
60 errorMessage string
61
62 // List of labels of allowed exception functions that allows bypassing this restriction.
63 // If any of the functions mapped to each labels returns true, this dependency would be
64 // considered allowed and an error will not be thrown.
65 allowedExceptions []exceptionHandleFuncLabel
66}
67type container struct {
68 // The name of the container i.e. partition, api domain
69 name string
70
71 // Map of dependency restricted containers.
72 restricted []restriction
73}
74
75var (
76 VendorContainer = &container{
77 name: VendorVariation,
78 restricted: nil,
79 }
80 SystemContainer = &container{
81 name: "system",
82 restricted: []restriction{
83 {
84 dependency: VendorContainer,
85 errorMessage: "Module belonging to the system partition other than HALs is " +
86 "not allowed to depend on the vendor partition module, in order to support " +
87 "independent development/update cycles and to support the Generic System " +
88 "Image. Try depending on HALs, VNDK or AIDL instead.",
89 allowedExceptions: []exceptionHandleFuncLabel{},
90 },
91 },
92 }
93 ProductContainer = &container{
94 name: ProductVariation,
95 restricted: []restriction{
96 {
97 dependency: VendorContainer,
98 errorMessage: "Module belonging to the product partition is not allowed to " +
99 "depend on the vendor partition module, as this may lead to security " +
100 "vulnerabilities. Try depending on the HALs or utilize AIDL instead.",
101 allowedExceptions: []exceptionHandleFuncLabel{},
102 },
103 },
104 }
105 ApexContainer = initializeApexContainer()
106 CtsContainer = &container{
107 name: "cts",
108 restricted: []restriction{
109 {
110 dependency: SystemContainer,
111 errorMessage: "CTS module should not depend on the modules belonging to the " +
112 "system partition, including \"framework\". Depending on the system " +
113 "partition may lead to disclosure of implementation details and regression " +
114 "due to API changes across platform versions. Try depending on the stubs instead.",
115 allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
116 },
117 },
118 }
119)
120
121func initializeApexContainer() *container {
122 apexContainer := &container{
123 name: "apex",
124 restricted: []restriction{
125 {
126 dependency: SystemContainer,
127 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
128 "modules belonging to the system partition. Either statically depend on the " +
129 "module or convert the depending module to java_sdk_library and depend on " +
130 "the stubs.",
131 allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
132 },
133 },
134 }
135
136 apexContainer.restricted = append(apexContainer.restricted, restriction{
137 dependency: apexContainer,
138 errorMessage: "Module belonging to Apex(es) is not allowed to depend on the " +
139 "modules belonging to other Apex(es). Either include the depending " +
140 "module in the Apex or convert the depending module to java_sdk_library " +
141 "and depend on its stubs.",
142 allowedExceptions: []exceptionHandleFuncLabel{checkStubs},
143 })
144
145 return apexContainer
146}
147
148type ContainersInfo struct {
149 belongingContainers []*container
150
151 belongingApexes []ApexInfo
152}
153
154func (c *ContainersInfo) BelongingContainers() []*container {
155 return c.belongingContainers
156}
157
158var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]()
159
160// Determines if the module can be installed in the system partition or not.
161// Logic is identical to that of modulePartition(...) defined in paths.go
162func installInSystemPartition(ctx ModuleContext) bool {
163 module := ctx.Module()
164 return !module.InstallInTestcases() &&
165 !module.InstallInData() &&
166 !module.InstallInRamdisk() &&
167 !module.InstallInVendorRamdisk() &&
168 !module.InstallInDebugRamdisk() &&
169 !module.InstallInRecovery() &&
170 !module.InstallInVendor() &&
171 !module.InstallInOdm() &&
172 !module.InstallInProduct() &&
173 determineModuleKind(module.base(), ctx.blueprintBaseModuleContext()) == platformModule
174}
175
176func generateContainerInfo(ctx ModuleContext) ContainersInfo {
177 inSystem := installInSystemPartition(ctx)
178 inProduct := ctx.Module().InstallInProduct()
179 inVendor := ctx.Module().InstallInVendor()
180 inCts := false
181 inApex := false
182
183 if m, ok := ctx.Module().(ImageInterface); ok {
184 inProduct = inProduct || m.ProductVariantNeeded(ctx)
185 inVendor = inVendor || m.VendorVariantNeeded(ctx)
186 }
187
188 props := ctx.Module().GetProperties()
189 for _, prop := range props {
190 val := reflect.ValueOf(prop).Elem()
191 if val.Kind() == reflect.Struct {
192 testSuites := val.FieldByName("Test_suites")
193 if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") {
194 inCts = true
195 }
196 }
197 }
198
199 var belongingApexes []ApexInfo
200 if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
201 belongingApexes = apexInfo.ApexInfos
202 inApex = true
203 }
204
205 containers := []*container{}
206 if inSystem {
207 containers = append(containers, SystemContainer)
208 }
209 if inProduct {
210 containers = append(containers, ProductContainer)
211 }
212 if inVendor {
213 containers = append(containers, VendorContainer)
214 }
215 if inCts {
216 containers = append(containers, CtsContainer)
217 }
218 if inApex {
219 containers = append(containers, ApexContainer)
220 }
221
222 return ContainersInfo{
223 belongingContainers: containers,
224 belongingApexes: belongingApexes,
225 }
226}
227
228func setContainerInfo(ctx ModuleContext) {
229 if _, ok := ctx.Module().(InstallableModule); ok {
230 containersInfo := generateContainerInfo(ctx)
231 SetProvider(ctx, ContainersInfoProvider, containersInfo)
232 }
233}