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 only allowing headers_only for framework-minus-apex-headers 348 { 349 name: `"headers_only" outside framework-minus-apex-headers modules`, 350 fs: map[string][]byte{ 351 "a/b/Android.bp": []byte(` 352 java_library { 353 name: "baz", 354 headers_only: true, 355 } 356 `), 357 }, 358 expectedErrors: []string{ 359 `headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`, 360 }, 361 }, 362 // Test for the rule restricting use of is_auto_generated 363 { 364 name: `"is_auto_generated" outside allowed directory`, 365 fs: map[string][]byte{ 366 "a/b/Android.bp": []byte(` 367 filesystem { 368 name: "baaz", 369 is_auto_generated: true, 370 } 371 `), 372 }, 373 expectedErrors: []string{ 374 `is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory`, 375 }, 376 }, 377 // Test for the rule restricting use of prebuilt_* module 378 { 379 name: `"prebuilt_usr_srec" defined in Android.bp file`, 380 fs: map[string][]byte{ 381 "a/b/Android.bp": []byte(` 382 prebuilt_usr_srec { 383 name: "foo", 384 } 385 `), 386 }, 387 expectedErrors: []string{ 388 `module type not allowed to be defined in bp file`, 389 }, 390 }, 391 // Test the a neverallowed module type can't be smuggled through a soong config module type 392 { 393 name: `smuggling module types through soong config modules`, 394 fs: map[string][]byte{ 395 "a/b/Android.bp": []byte(` 396 soong_config_bool_variable { 397 name: "my_var", 398 } 399 soong_config_module_type { 400 name: "smuggled_prebuilt_usr_srec", 401 module_type: "prebuilt_usr_srec", 402 config_namespace: "ANDROID", 403 variables: ["my_var"], 404 properties: ["enabled"], 405 } 406 smuggled_prebuilt_usr_srec { 407 name: "foo", 408 } 409 `), 410 }, 411 expectedErrors: []string{ 412 `module type not allowed to be defined in bp file`, 413 }, 414 }, 415} 416 417var prepareForNeverAllowTest = GroupFixturePreparers( 418 FixtureRegisterWithContext(func(ctx RegistrationContext) { 419 ctx.RegisterModuleType("cc_library", newMockCcLibraryModule) 420 ctx.RegisterModuleType("java_library", newMockJavaLibraryModule) 421 ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule) 422 ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule) 423 ctx.RegisterModuleType("filesystem", newMockFilesystemModule) 424 ctx.RegisterModuleType("prebuilt_usr_srec", newMockPrebuiltUsrSrecModule) 425 }), 426 PrepareForTestWithSoongConfigModuleBuildComponents, 427) 428 429func TestNeverallow(t *testing.T) { 430 for _, test := range neverallowTests { 431 t.Run(test.name, func(t *testing.T) { 432 GroupFixturePreparers( 433 prepareForNeverAllowTest, 434 PrepareForTestWithNeverallowRules(test.rules), 435 test.fs.AddToFixture(), 436 ). 437 ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). 438 RunTest(t) 439 }) 440 } 441} 442 443type mockCcLibraryProperties struct { 444 Include_dirs []string 445 Vendor_available *bool 446 Static_libs []string 447 Sdk_version *string 448 Sdk_variant_only *bool 449 450 Vndk struct { 451 Enabled *bool 452 Support_system_process *bool 453 Extends *string 454 } 455 456 Product_variables struct { 457 Enforce_vintf_manifest struct { 458 Cflags []string 459 } 460 461 Treble_linker_namespaces struct { 462 Cflags []string 463 } 464 } 465 466 Platform struct { 467 Shared_libs []string 468 } 469 470 Stubs struct { 471 Implementation_installable *bool 472 } 473} 474 475type mockCcLibraryModule struct { 476 ModuleBase 477 properties mockCcLibraryProperties 478} 479 480func newMockCcLibraryModule() Module { 481 m := &mockCcLibraryModule{} 482 m.AddProperties(&m.properties) 483 InitAndroidModule(m) 484 return m 485} 486 487type neverallowTestDependencyTag struct { 488 blueprint.BaseDependencyTag 489 name string 490} 491 492var staticDepTag = neverallowTestDependencyTag{name: "static"} 493 494func (c *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) { 495 for _, lib := range c.properties.Static_libs { 496 ctx.AddDependency(ctx.Module(), staticDepTag, lib) 497 } 498} 499 500func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) { 501} 502 503type mockJavaLibraryProperties struct { 504 Libs []string 505 Sdk_version *string 506 Uncompress_dex *bool 507 Exclude_static_libs []string 508 Headers_only *bool 509} 510 511type mockJavaLibraryModule struct { 512 ModuleBase 513 properties mockJavaLibraryProperties 514} 515 516func newMockJavaLibraryModule() Module { 517 m := &mockJavaLibraryModule{} 518 m.AddProperties(&m.properties) 519 InitAndroidModule(m) 520 return m 521} 522 523func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) { 524} 525 526type mockPrebuiltUsrSrecModule struct { 527 ModuleBase 528} 529 530func (p *mockPrebuiltUsrSrecModule) GenerateAndroidBuildActions(ModuleContext) { 531} 532 533func newMockPrebuiltUsrSrecModule() Module { 534 m := &mockPrebuiltUsrSrecModule{} 535 InitAndroidModule(m) 536 return m 537} 538