1// Copyright 2018 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 "regexp" 19 "testing" 20 21 "github.com/google/blueprint" 22) 23 24var neverallowTests = []struct { 25 // The name of the test. 26 name string 27 28 // Optional test specific rules. If specified then they are used instead of the default rules. 29 rules []Rule 30 31 // Additional contents to add to the virtual filesystem used by the tests. 32 fs MockFS 33 34 // The expected error patterns. If empty then no errors are expected, otherwise each error 35 // reported must be matched by at least one of these patterns. A pattern matches if the error 36 // message contains the pattern. A pattern does not have to match the whole error message. 37 expectedErrors []string 38}{ 39 // Test General Functionality 40 41 // in direct deps tests 42 { 43 name: "not_allowed_in_direct_deps", 44 rules: []Rule{ 45 NeverAllow().InDirectDeps("not_allowed_in_direct_deps"), 46 }, 47 fs: map[string][]byte{ 48 "top/Android.bp": []byte(` 49 cc_library { 50 name: "not_allowed_in_direct_deps", 51 }`), 52 "other/Android.bp": []byte(` 53 cc_library { 54 name: "libother", 55 static_libs: ["not_allowed_in_direct_deps"], 56 }`), 57 }, 58 expectedErrors: []string{ 59 regexp.QuoteMeta("module \"libother\": violates neverallow requirements. Not allowed:\n\tdep(s): [\"not_allowed_in_direct_deps\"]"), 60 }, 61 }, 62 { 63 name: "multiple constraints", 64 rules: []Rule{ 65 NeverAllow(). 66 InDirectDeps("not_allowed_in_direct_deps"). 67 In("other"). 68 ModuleType("cc_library"). 69 NotIn("top"). 70 NotModuleType("cc_binary"), 71 }, 72 fs: map[string][]byte{ 73 "top/Android.bp": []byte(` 74 cc_library { 75 name: "not_allowed_in_direct_deps", 76 }`), 77 "other/Android.bp": []byte(` 78 cc_library { 79 name: "libother", 80 static_libs: ["not_allowed_in_direct_deps"], 81 }`), 82 }, 83 expectedErrors: []string{ 84 regexp.QuoteMeta(`module "libother": violates neverallow requirements. Not allowed: 85 in dirs: ["other/"] 86 module types: ["cc_library"] 87 dep(s): ["not_allowed_in_direct_deps"] 88 EXCEPT in dirs: ["top/"] 89 EXCEPT module types: ["cc_binary"]`), 90 }, 91 }, 92 93 // Test android specific rules 94 95 // include_dir rule tests 96 { 97 name: "include_dir not allowed to reference art", 98 fs: map[string][]byte{ 99 "other/Android.bp": []byte(` 100 cc_library { 101 name: "libother", 102 include_dirs: ["art/libdexfile/include"], 103 }`), 104 }, 105 expectedErrors: []string{ 106 "all usages of 'art' have been migrated", 107 }, 108 }, 109 { 110 name: "include_dir not allowed to reference art", 111 fs: map[string][]byte{ 112 "system/libfmq/Android.bp": []byte(` 113 cc_library { 114 name: "libother", 115 include_dirs: ["any/random/file"], 116 }`), 117 }, 118 expectedErrors: []string{ 119 "all usages of them in 'system/libfmq' have been migrated", 120 }, 121 }, 122 { 123 name: "include_dir can work", 124 fs: map[string][]byte{ 125 "other/Android.bp": []byte(` 126 cc_library { 127 name: "libother", 128 include_dirs: ["another/include"], 129 }`), 130 }, 131 }, 132 // Treble rule tests 133 { 134 name: "no vndk.enabled under vendor directory", 135 fs: map[string][]byte{ 136 "vendor/Android.bp": []byte(` 137 cc_library { 138 name: "libvndk", 139 vendor_available: true, 140 vndk: { 141 enabled: true, 142 }, 143 }`), 144 }, 145 expectedErrors: []string{ 146 "VNDK can never contain a library that is device dependent", 147 }, 148 }, 149 { 150 name: "no vndk.enabled under device directory", 151 fs: map[string][]byte{ 152 "device/Android.bp": []byte(` 153 cc_library { 154 name: "libvndk", 155 vendor_available: true, 156 vndk: { 157 enabled: true, 158 }, 159 }`), 160 }, 161 expectedErrors: []string{ 162 "VNDK can never contain a library that is device dependent", 163 }, 164 }, 165 { 166 name: "vndk-ext under vendor or device directory", 167 fs: map[string][]byte{ 168 "device/Android.bp": []byte(` 169 cc_library { 170 name: "libvndk1_ext", 171 vendor: true, 172 vndk: { 173 enabled: true, 174 }, 175 }`), 176 "vendor/Android.bp": []byte(` 177 cc_library { 178 name: "libvndk2_ext", 179 vendor: true, 180 vndk: { 181 enabled: true, 182 }, 183 }`), 184 }, 185 }, 186 187 { 188 name: "no enforce_vintf_manifest.cflags", 189 fs: map[string][]byte{ 190 "Android.bp": []byte(` 191 cc_library { 192 name: "libexample", 193 product_variables: { 194 enforce_vintf_manifest: { 195 cflags: ["-DSHOULD_NOT_EXIST"], 196 }, 197 }, 198 }`), 199 }, 200 expectedErrors: []string{ 201 "manifest enforcement should be independent", 202 }, 203 }, 204 205 { 206 name: "no treble_linker_namespaces.cflags", 207 fs: map[string][]byte{ 208 "Android.bp": []byte(` 209 cc_library { 210 name: "libexample", 211 product_variables: { 212 treble_linker_namespaces: { 213 cflags: ["-DSHOULD_NOT_EXIST"], 214 }, 215 }, 216 }`), 217 }, 218 expectedErrors: []string{ 219 "nothing should care if linker namespaces are enabled or not", 220 }, 221 }, 222 { 223 name: "libc_bionic_ndk treble_linker_namespaces.cflags", 224 fs: map[string][]byte{ 225 "Android.bp": []byte(` 226 cc_library { 227 name: "libc_bionic_ndk", 228 product_variables: { 229 treble_linker_namespaces: { 230 cflags: ["-DSHOULD_NOT_EXIST"], 231 }, 232 }, 233 }`), 234 }, 235 }, 236 { 237 name: "java_device_for_host", 238 fs: map[string][]byte{ 239 "Android.bp": []byte(` 240 java_device_for_host { 241 name: "device_for_host", 242 libs: ["core-libart"], 243 }`), 244 }, 245 expectedErrors: []string{ 246 "java_device_for_host can only be used in allowed projects", 247 }, 248 }, 249 // CC sdk rule tests 250 { 251 name: `"sdk_variant_only" outside allowed list`, 252 fs: map[string][]byte{ 253 "Android.bp": []byte(` 254 cc_library { 255 name: "outside_allowed_list", 256 sdk_version: "current", 257 sdk_variant_only: true, 258 }`), 259 }, 260 expectedErrors: []string{ 261 `module "outside_allowed_list": violates neverallow`, 262 }, 263 }, 264 { 265 name: `"sdk_variant_only: false" outside allowed list`, 266 fs: map[string][]byte{ 267 "Android.bp": []byte(` 268 cc_library { 269 name: "outside_allowed_list", 270 sdk_version: "current", 271 sdk_variant_only: false, 272 }`), 273 }, 274 expectedErrors: []string{ 275 `module "outside_allowed_list": violates neverallow`, 276 }, 277 }, 278 { 279 name: `"platform" outside allowed list`, 280 fs: map[string][]byte{ 281 "Android.bp": []byte(` 282 cc_library { 283 name: "outside_allowed_list", 284 platform: { 285 shared_libs: ["libfoo"], 286 }, 287 }`), 288 }, 289 expectedErrors: []string{ 290 `module "outside_allowed_list": violates neverallow`, 291 }, 292 }, 293 { 294 name: "uncompress_dex inside art", 295 fs: map[string][]byte{ 296 "art/Android.bp": []byte(` 297 java_library { 298 name: "inside_art_libraries", 299 uncompress_dex: true, 300 }`), 301 }, 302 }, 303 { 304 name: "uncompress_dex outside art", 305 fs: map[string][]byte{ 306 "other/Android.bp": []byte(` 307 java_library { 308 name: "outside_art_libraries", 309 uncompress_dex: true, 310 }`), 311 }, 312 expectedErrors: []string{ 313 "module \"outside_art_libraries\": violates neverallow", 314 }, 315 }, 316 // Tests for the rule prohibiting the use of framework 317 { 318 name: "prohibit framework", 319 fs: map[string][]byte{ 320 "Android.bp": []byte(` 321 java_library { 322 name: "foo", 323 libs: ["framework"], 324 sdk_version: "current", 325 }`), 326 }, 327 expectedErrors: []string{ 328 "framework can't be used when building against SDK", 329 }, 330 }, 331 // Test for the rule restricting use of implementation_installable 332 { 333 name: `"implementation_installable" outside allowed list`, 334 fs: map[string][]byte{ 335 "Android.bp": []byte(` 336 cc_library { 337 name: "outside_allowed_list", 338 stubs: { 339 implementation_installable: true, 340 }, 341 }`), 342 }, 343 expectedErrors: []string{ 344 `module "outside_allowed_list": violates neverallow`, 345 }, 346 }, 347 // Test for the rule restricting use of exclude_static_libs 348 { 349 name: `"exclude_static_libs" outside allowed directory`, 350 fs: map[string][]byte{ 351 "a/b/Android.bp": []byte(` 352 java_library { 353 name: "baz", 354 exclude_static_libs: [ 355 "bar", 356 ], 357 } 358 `), 359 }, 360 expectedErrors: []string{ 361 `exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api`, 362 }, 363 }, 364 // Test for only allowing headers_only for framework-minus-apex-headers 365 { 366 name: `"headers_only" outside framework-minus-apex-headers modules`, 367 fs: map[string][]byte{ 368 "a/b/Android.bp": []byte(` 369 java_library { 370 name: "baz", 371 headers_only: true, 372 } 373 `), 374 }, 375 expectedErrors: []string{ 376 `headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`, 377 }, 378 }, 379} 380 381var prepareForNeverAllowTest = GroupFixturePreparers( 382 FixtureRegisterWithContext(func(ctx RegistrationContext) { 383 ctx.RegisterModuleType("cc_library", newMockCcLibraryModule) 384 ctx.RegisterModuleType("java_library", newMockJavaLibraryModule) 385 ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule) 386 ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule) 387 }), 388) 389 390func TestNeverallow(t *testing.T) { 391 for _, test := range neverallowTests { 392 t.Run(test.name, func(t *testing.T) { 393 GroupFixturePreparers( 394 prepareForNeverAllowTest, 395 PrepareForTestWithNeverallowRules(test.rules), 396 test.fs.AddToFixture(), 397 ). 398 ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). 399 RunTest(t) 400 }) 401 } 402} 403 404type mockCcLibraryProperties struct { 405 Include_dirs []string 406 Vendor_available *bool 407 Static_libs []string 408 Sdk_version *string 409 Sdk_variant_only *bool 410 411 Vndk struct { 412 Enabled *bool 413 Support_system_process *bool 414 Extends *string 415 } 416 417 Product_variables struct { 418 Enforce_vintf_manifest struct { 419 Cflags []string 420 } 421 422 Treble_linker_namespaces struct { 423 Cflags []string 424 } 425 } 426 427 Platform struct { 428 Shared_libs []string 429 } 430 431 Stubs struct { 432 Implementation_installable *bool 433 } 434} 435 436type mockCcLibraryModule struct { 437 ModuleBase 438 properties mockCcLibraryProperties 439} 440 441func newMockCcLibraryModule() Module { 442 m := &mockCcLibraryModule{} 443 m.AddProperties(&m.properties) 444 InitAndroidModule(m) 445 return m 446} 447 448type neverallowTestDependencyTag struct { 449 blueprint.BaseDependencyTag 450 name string 451} 452 453var staticDepTag = neverallowTestDependencyTag{name: "static"} 454 455func (c *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) { 456 for _, lib := range c.properties.Static_libs { 457 ctx.AddDependency(ctx.Module(), staticDepTag, lib) 458 } 459} 460 461func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) { 462} 463 464type mockJavaLibraryProperties struct { 465 Libs []string 466 Sdk_version *string 467 Uncompress_dex *bool 468 Exclude_static_libs []string 469 Headers_only *bool 470} 471 472type mockJavaLibraryModule struct { 473 ModuleBase 474 properties mockJavaLibraryProperties 475} 476 477func newMockJavaLibraryModule() Module { 478 m := &mockJavaLibraryModule{} 479 m.AddProperties(&m.properties) 480 InitAndroidModule(m) 481 return m 482} 483 484func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) { 485} 486