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} 392 393var prepareForNeverAllowTest = GroupFixturePreparers( 394 FixtureRegisterWithContext(func(ctx RegistrationContext) { 395 ctx.RegisterModuleType("cc_library", newMockCcLibraryModule) 396 ctx.RegisterModuleType("java_library", newMockJavaLibraryModule) 397 ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule) 398 ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule) 399 ctx.RegisterModuleType("filesystem", newMockFilesystemModule) 400 ctx.RegisterModuleType("prebuilt_usr_srec", newMockPrebuiltUsrSrecModule) 401 }), 402) 403 404func TestNeverallow(t *testing.T) { 405 for _, test := range neverallowTests { 406 t.Run(test.name, func(t *testing.T) { 407 GroupFixturePreparers( 408 prepareForNeverAllowTest, 409 PrepareForTestWithNeverallowRules(test.rules), 410 test.fs.AddToFixture(), 411 ). 412 ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). 413 RunTest(t) 414 }) 415 } 416} 417 418type mockCcLibraryProperties struct { 419 Include_dirs []string 420 Vendor_available *bool 421 Static_libs []string 422 Sdk_version *string 423 Sdk_variant_only *bool 424 425 Vndk struct { 426 Enabled *bool 427 Support_system_process *bool 428 Extends *string 429 } 430 431 Product_variables struct { 432 Enforce_vintf_manifest struct { 433 Cflags []string 434 } 435 436 Treble_linker_namespaces struct { 437 Cflags []string 438 } 439 } 440 441 Platform struct { 442 Shared_libs []string 443 } 444 445 Stubs struct { 446 Implementation_installable *bool 447 } 448} 449 450type mockCcLibraryModule struct { 451 ModuleBase 452 properties mockCcLibraryProperties 453} 454 455func newMockCcLibraryModule() Module { 456 m := &mockCcLibraryModule{} 457 m.AddProperties(&m.properties) 458 InitAndroidModule(m) 459 return m 460} 461 462type neverallowTestDependencyTag struct { 463 blueprint.BaseDependencyTag 464 name string 465} 466 467var staticDepTag = neverallowTestDependencyTag{name: "static"} 468 469func (c *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) { 470 for _, lib := range c.properties.Static_libs { 471 ctx.AddDependency(ctx.Module(), staticDepTag, lib) 472 } 473} 474 475func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) { 476} 477 478type mockJavaLibraryProperties struct { 479 Libs []string 480 Sdk_version *string 481 Uncompress_dex *bool 482 Exclude_static_libs []string 483 Headers_only *bool 484} 485 486type mockJavaLibraryModule struct { 487 ModuleBase 488 properties mockJavaLibraryProperties 489} 490 491func newMockJavaLibraryModule() Module { 492 m := &mockJavaLibraryModule{} 493 m.AddProperties(&m.properties) 494 InitAndroidModule(m) 495 return m 496} 497 498func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) { 499} 500 501type mockPrebuiltUsrSrecModule struct { 502 ModuleBase 503} 504 505func (p *mockPrebuiltUsrSrecModule) GenerateAndroidBuildActions(ModuleContext) { 506} 507 508func newMockPrebuiltUsrSrecModule() Module { 509 m := &mockPrebuiltUsrSrecModule{} 510 InitAndroidModule(m) 511 return m 512} 513