blob: b90fe43d39525a39f3c5f6360baaac9ebc236f72 [file] [log] [blame]
Steven Moreland65b3fd92017-12-06 14:18:35 -08001// Copyright 2017 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 "path/filepath"
19 "reflect"
20 "strconv"
21 "strings"
22
23 "github.com/google/blueprint/proptools"
24)
25
26// "neverallow" rules for the build system.
27//
28// This allows things which aren't related to the build system and are enforced
29// for sanity, in progress code refactors, or policy to be expressed in a
30// straightforward away disjoint from implementations and tests which should
31// work regardless of these restrictions.
32//
33// A module is disallowed if all of the following are true:
34// - it is in one of the "in" paths
35// - it is not in one of the "notIn" paths
36// - it has all "with" properties matched
37// - - values are matched in their entirety
38// - - nil is interpreted as an empty string
39// - - nested properties are separated with a '.'
40// - - if the property is a list, any of the values in the list being matches
41// counts as a match
42// - it has none of the "without" properties matched (same rules as above)
43
44func registerNeverallowMutator(ctx RegisterMutatorsContext) {
45 ctx.BottomUp("neverallow", neverallowMutator).Parallel()
46}
47
Neil Fullerdf5f3562018-10-21 17:19:10 +010048var neverallows = createNeverAllows()
Steven Moreland65b3fd92017-12-06 14:18:35 -080049
Neil Fullerdf5f3562018-10-21 17:19:10 +010050func createNeverAllows() []*rule {
51 rules := []*rule{}
52 rules = append(rules, createTrebleRules()...)
53 rules = append(rules, createLibcoreRules()...)
Dongwon Kang50a299f2019-02-04 09:00:51 -080054 rules = append(rules, createMediaRules()...)
Colin Crossfd4f7432019-03-05 15:06:16 -080055 rules = append(rules, createJavaDeviceForHostRules()...)
Neil Fullerdf5f3562018-10-21 17:19:10 +010056 return rules
57}
Steven Moreland65b3fd92017-12-06 14:18:35 -080058
Neil Fullerdf5f3562018-10-21 17:19:10 +010059func createTrebleRules() []*rule {
60 return []*rule{
61 neverallow().
62 in("vendor", "device").
63 with("vndk.enabled", "true").
64 without("vendor", "true").
65 because("the VNDK can never contain a library that is device dependent."),
66 neverallow().
67 with("vndk.enabled", "true").
68 without("vendor", "true").
69 without("owner", "").
70 because("a VNDK module can never have an owner."),
Steven Moreland65b3fd92017-12-06 14:18:35 -080071
Neil Fullerdf5f3562018-10-21 17:19:10 +010072 // TODO(b/67974785): always enforce the manifest
73 neverallow().
Steven Morelanda1165d62019-06-05 18:27:35 -070074 without("name", "libhidltransport-impl-internal").
Neil Fullerdf5f3562018-10-21 17:19:10 +010075 with("product_variables.enforce_vintf_manifest.cflags", "*").
76 because("manifest enforcement should be independent of ."),
77
78 // TODO(b/67975799): vendor code should always use /vendor/bin/sh
79 neverallow().
80 without("name", "libc_bionic_ndk").
81 with("product_variables.treble_linker_namespaces.cflags", "*").
82 because("nothing should care if linker namespaces are enabled or not"),
83
84 // Example:
85 // *neverallow().with("Srcs", "main.cpp"))
86 }
87}
88
89func createLibcoreRules() []*rule {
90 var coreLibraryProjects = []string{
91 "libcore",
92 "external/apache-harmony",
93 "external/apache-xml",
94 "external/bouncycastle",
95 "external/conscrypt",
96 "external/icu",
97 "external/okhttp",
98 "external/wycheproof",
99 }
100
101 var coreModules = []string{
102 "core-all",
103 "core-oj",
104 "core-libart",
Neil Fullerdf5f3562018-10-21 17:19:10 +0100105 "okhttp",
106 "bouncycastle",
107 "conscrypt",
108 "apache-xml",
109 }
110
111 // Core library constraints. Prevent targets adding dependencies on core
112 // library internals, which could lead to compatibility issues with the ART
113 // mainline module. They should use core.platform.api.stubs instead.
114 rules := []*rule{
115 neverallow().
116 notIn(append(coreLibraryProjects, "development")...).
117 with("no_standard_libs", "true"),
118 }
119
120 for _, m := range coreModules {
121 r := neverallow().
122 notIn(coreLibraryProjects...).
123 with("libs", m).
124 because("Only core libraries projects can depend on " + m)
125 rules = append(rules, r)
126 }
127 return rules
Steven Moreland65b3fd92017-12-06 14:18:35 -0800128}
129
Dongwon Kang50a299f2019-02-04 09:00:51 -0800130func createMediaRules() []*rule {
131 return []*rule{
132 neverallow().
133 with("libs", "updatable-media").
134 because("updatable-media includes private APIs. Use updatable_media_stubs instead."),
135 }
136}
137
Colin Crossfd4f7432019-03-05 15:06:16 -0800138func createJavaDeviceForHostRules() []*rule {
139 javaDeviceForHostProjectsWhitelist := []string{
140 "external/robolectric-shadows",
141 "framework/layoutlib",
142 }
143
144 return []*rule{
145 neverallow().
146 notIn(javaDeviceForHostProjectsWhitelist...).
147 moduleType("java_device_for_host", "java_host_for_device").
148 because("java_device_for_host can only be used in whitelisted projects"),
149 }
150}
151
Steven Moreland65b3fd92017-12-06 14:18:35 -0800152func neverallowMutator(ctx BottomUpMutatorContext) {
153 m, ok := ctx.Module().(Module)
154 if !ok {
155 return
156 }
157
158 dir := ctx.ModuleDir() + "/"
159 properties := m.GetProperties()
160
161 for _, n := range neverallows {
162 if !n.appliesToPath(dir) {
163 continue
164 }
165
Colin Crossfd4f7432019-03-05 15:06:16 -0800166 if !n.appliesToModuleType(ctx.ModuleType()) {
167 continue
168 }
169
Steven Moreland65b3fd92017-12-06 14:18:35 -0800170 if !n.appliesToProperties(properties) {
171 continue
172 }
173
174 ctx.ModuleErrorf("violates " + n.String())
175 }
176}
177
178type ruleProperty struct {
179 fields []string // e.x.: Vndk.Enabled
180 value string // e.x.: true
181}
182
183type rule struct {
184 // User string for why this is a thing.
185 reason string
186
187 paths []string
188 unlessPaths []string
189
Colin Crossfd4f7432019-03-05 15:06:16 -0800190 moduleTypes []string
191 unlessModuleTypes []string
192
Steven Moreland65b3fd92017-12-06 14:18:35 -0800193 props []ruleProperty
194 unlessProps []ruleProperty
195}
196
197func neverallow() *rule {
198 return &rule{}
199}
Colin Crossfd4f7432019-03-05 15:06:16 -0800200
Steven Moreland65b3fd92017-12-06 14:18:35 -0800201func (r *rule) in(path ...string) *rule {
202 r.paths = append(r.paths, cleanPaths(path)...)
203 return r
204}
Colin Crossfd4f7432019-03-05 15:06:16 -0800205
Steven Moreland65b3fd92017-12-06 14:18:35 -0800206func (r *rule) notIn(path ...string) *rule {
207 r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...)
208 return r
209}
Colin Crossfd4f7432019-03-05 15:06:16 -0800210
211func (r *rule) moduleType(types ...string) *rule {
212 r.moduleTypes = append(r.moduleTypes, types...)
213 return r
214}
215
216func (r *rule) notModuleType(types ...string) *rule {
217 r.unlessModuleTypes = append(r.unlessModuleTypes, types...)
218 return r
219}
220
Steven Moreland65b3fd92017-12-06 14:18:35 -0800221func (r *rule) with(properties, value string) *rule {
222 r.props = append(r.props, ruleProperty{
223 fields: fieldNamesForProperties(properties),
224 value: value,
225 })
226 return r
227}
Colin Crossfd4f7432019-03-05 15:06:16 -0800228
Steven Moreland65b3fd92017-12-06 14:18:35 -0800229func (r *rule) without(properties, value string) *rule {
230 r.unlessProps = append(r.unlessProps, ruleProperty{
231 fields: fieldNamesForProperties(properties),
232 value: value,
233 })
234 return r
235}
Colin Crossfd4f7432019-03-05 15:06:16 -0800236
Steven Moreland65b3fd92017-12-06 14:18:35 -0800237func (r *rule) because(reason string) *rule {
238 r.reason = reason
239 return r
240}
241
242func (r *rule) String() string {
243 s := "neverallow"
244 for _, v := range r.paths {
245 s += " dir:" + v + "*"
246 }
247 for _, v := range r.unlessPaths {
248 s += " -dir:" + v + "*"
249 }
Colin Crossfd4f7432019-03-05 15:06:16 -0800250 for _, v := range r.moduleTypes {
251 s += " type:" + v
252 }
253 for _, v := range r.unlessModuleTypes {
254 s += " -type:" + v
255 }
Steven Moreland65b3fd92017-12-06 14:18:35 -0800256 for _, v := range r.props {
257 s += " " + strings.Join(v.fields, ".") + "=" + v.value
258 }
259 for _, v := range r.unlessProps {
260 s += " -" + strings.Join(v.fields, ".") + "=" + v.value
261 }
262 if len(r.reason) != 0 {
263 s += " which is restricted because " + r.reason
264 }
265 return s
266}
267
268func (r *rule) appliesToPath(dir string) bool {
269 includePath := len(r.paths) == 0 || hasAnyPrefix(dir, r.paths)
270 excludePath := hasAnyPrefix(dir, r.unlessPaths)
271 return includePath && !excludePath
272}
273
Colin Crossfd4f7432019-03-05 15:06:16 -0800274func (r *rule) appliesToModuleType(moduleType string) bool {
275 return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
276}
277
Steven Moreland65b3fd92017-12-06 14:18:35 -0800278func (r *rule) appliesToProperties(properties []interface{}) bool {
279 includeProps := hasAllProperties(properties, r.props)
280 excludeProps := hasAnyProperty(properties, r.unlessProps)
281 return includeProps && !excludeProps
282}
283
284// assorted utils
285
286func cleanPaths(paths []string) []string {
287 res := make([]string, len(paths))
288 for i, v := range paths {
289 res[i] = filepath.Clean(v) + "/"
290 }
291 return res
292}
293
294func fieldNamesForProperties(propertyNames string) []string {
295 names := strings.Split(propertyNames, ".")
296 for i, v := range names {
297 names[i] = proptools.FieldNameForProperty(v)
298 }
299 return names
300}
301
302func hasAnyPrefix(s string, prefixes []string) bool {
303 for _, prefix := range prefixes {
304 if strings.HasPrefix(s, prefix) {
305 return true
306 }
307 }
308 return false
309}
310
311func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
312 for _, v := range props {
313 if hasProperty(properties, v) {
314 return true
315 }
316 }
317 return false
318}
319
320func hasAllProperties(properties []interface{}, props []ruleProperty) bool {
321 for _, v := range props {
322 if !hasProperty(properties, v) {
323 return false
324 }
325 }
326 return true
327}
328
329func hasProperty(properties []interface{}, prop ruleProperty) bool {
330 for _, propertyStruct := range properties {
331 propertiesValue := reflect.ValueOf(propertyStruct).Elem()
332 for _, v := range prop.fields {
333 if !propertiesValue.IsValid() {
334 break
335 }
336 propertiesValue = propertiesValue.FieldByName(v)
337 }
338 if !propertiesValue.IsValid() {
339 continue
340 }
341
342 check := func(v string) bool {
343 return prop.value == "*" || prop.value == v
344 }
345
346 if matchValue(propertiesValue, check) {
347 return true
348 }
349 }
350 return false
351}
352
353func matchValue(value reflect.Value, check func(string) bool) bool {
354 if !value.IsValid() {
355 return false
356 }
357
358 if value.Kind() == reflect.Ptr {
359 if value.IsNil() {
360 return check("")
361 }
362 value = value.Elem()
363 }
364
365 switch value.Kind() {
366 case reflect.String:
367 return check(value.String())
368 case reflect.Bool:
369 return check(strconv.FormatBool(value.Bool()))
370 case reflect.Int:
371 return check(strconv.FormatInt(value.Int(), 10))
372 case reflect.Slice:
373 slice, ok := value.Interface().([]string)
374 if !ok {
375 panic("Can only handle slice of string")
376 }
377 for _, v := range slice {
378 if check(v) {
379 return true
380 }
381 }
382 return false
383 }
384
385 panic("Can't handle type: " + value.Kind().String())
386}