1// Copyright (C) 2019 The Android Open Source Project 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 aidl 16 17import ( 18 "io/ioutil" 19 "os" 20 "path/filepath" 21 "strings" 22 "testing" 23 24 "github.com/google/blueprint" 25 "github.com/google/blueprint/proptools" 26 27 "android/soong/android" 28 "android/soong/cc" 29 "android/soong/java" 30) 31 32var buildDir string 33 34func setUp() { 35 var err error 36 buildDir, err = ioutil.TempDir("", "soong_aidl_test") 37 if err != nil { 38 panic(err) 39 } 40} 41 42func tearDown() { 43 os.RemoveAll(buildDir) 44} 45 46func TestMain(m *testing.M) { 47 run := func() int { 48 setUp() 49 defer tearDown() 50 51 return m.Run() 52 } 53 54 os.Exit(run()) 55} 56 57type testCustomizer func(fs map[string][]byte, config android.Config) 58 59func withFiles(files map[string][]byte) testCustomizer { 60 return func(fs map[string][]byte, config android.Config) { 61 for k, v := range files { 62 fs[k] = v 63 } 64 } 65} 66 67func setReleaseEnv() testCustomizer { 68 return func(_ map[string][]byte, config android.Config) { 69 config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("REL") 70 config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(true) 71 } 72} 73 74func _testAidl(t *testing.T, bp string, customizers ...testCustomizer) (*android.TestContext, android.Config) { 75 t.Helper() 76 77 bp = bp + java.GatherRequiredDepsForTest() 78 bp = bp + cc.GatherRequiredDepsForTest(android.Android) 79 bp = bp + ` 80 java_defaults { 81 name: "aidl-java-module-defaults", 82 } 83 cc_defaults { 84 name: "aidl-cpp-module-defaults", 85 } 86 cc_library { 87 name: "libbinder", 88 } 89 cc_library { 90 name: "libutils", 91 } 92 cc_library { 93 name: "libcutils", 94 } 95 cc_library { 96 name: "libbinder_ndk", 97 } 98 ndk_library { 99 name: "libbinder_ndk", 100 symbol_file: "libbinder_ndk.map.txt", 101 first_version: "29", 102 } 103 aidl_interfaces_metadata { 104 name: "aidl_metadata_json", 105 } 106 ` 107 fs := map[string][]byte{} 108 109 cc.GatherRequiredFilesForTest(fs) 110 111 for _, c := range customizers { 112 // The fs now needs to be populated before creating the config, call customizers twice 113 // for now, once to get any fs changes, and later after the config was created to 114 // set product variables or targets. 115 tempConfig := android.TestArchConfig(buildDir, nil, bp, fs) 116 c(fs, tempConfig) 117 } 118 119 config := android.TestArchConfig(buildDir, nil, bp, fs) 120 121 // To keep tests stable, fix Platform_sdk_codename and Platform_sdk_final 122 // Use setReleaseEnv() to test release version 123 config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q") 124 config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false) 125 126 for _, c := range customizers { 127 // The fs now needs to be populated before creating the config, call customizers twice 128 // for now, earlier to get any fs changes, and now after the config was created to 129 // set product variables or targets. 130 tempFS := map[string][]byte{} 131 c(tempFS, config) 132 } 133 134 ctx := android.NewTestArchContext() 135 cc.RegisterRequiredBuildComponentsForTest(ctx) 136 ctx.RegisterModuleType("aidl_interface", aidlInterfaceFactory) 137 ctx.RegisterModuleType("aidl_interfaces_metadata", aidlInterfacesMetadataSingletonFactory) 138 ctx.RegisterModuleType("android_app", java.AndroidAppFactory) 139 ctx.RegisterModuleType("java_defaults", func() android.Module { 140 return java.DefaultsFactory() 141 }) 142 ctx.RegisterModuleType("java_library_static", java.LibraryStaticFactory) 143 ctx.RegisterModuleType("java_library", java.LibraryFactory) 144 ctx.RegisterModuleType("java_system_modules", java.SystemModulesFactory) 145 146 ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) 147 ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) 148 ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { 149 ctx.BottomUp("checkUnstableModule", checkUnstableModuleMutator).Parallel() 150 ctx.BottomUp("checkDuplicatedVersions", checkDuplicatedVersions).Parallel() 151 }) 152 ctx.Register(config) 153 154 return ctx, config 155} 156 157func testAidl(t *testing.T, bp string, customizers ...testCustomizer) (*android.TestContext, android.Config) { 158 t.Helper() 159 ctx, config := _testAidl(t, bp, customizers...) 160 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 161 android.FailIfErrored(t, errs) 162 _, errs = ctx.PrepareBuildActions(config) 163 android.FailIfErrored(t, errs) 164 return ctx, config 165} 166 167func testAidlError(t *testing.T, pattern, bp string, customizers ...testCustomizer) { 168 t.Helper() 169 ctx, config := _testAidl(t, bp, customizers...) 170 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 171 if len(errs) > 0 { 172 android.FailIfNoMatchingErrors(t, pattern, errs) 173 return 174 } 175 _, errs = ctx.PrepareBuildActions(config) 176 if len(errs) > 0 { 177 android.FailIfNoMatchingErrors(t, pattern, errs) 178 return 179 } 180 t.Fatalf("missing expected error %q (0 errors are returned)", pattern) 181} 182 183// asserts that there are expected module regardless of variants 184func assertModulesExists(t *testing.T, ctx *android.TestContext, names ...string) { 185 missing := []string{} 186 for _, name := range names { 187 variants := ctx.ModuleVariantsForTests(name) 188 if len(variants) == 0 { 189 missing = append(missing, name) 190 } 191 } 192 if len(missing) > 0 { 193 // find all the modules that do exist 194 allModuleNames := make(map[string]bool) 195 ctx.VisitAllModules(func(m blueprint.Module) { 196 allModuleNames[ctx.ModuleName(m)] = true 197 }) 198 t.Errorf("expected modules(%v) not found. all modules: %v", missing, android.SortedStringKeys(allModuleNames)) 199 } 200} 201 202// Vintf module must have versions in release version 203func TestVintfWithoutVersionInRelease(t *testing.T) { 204 vintfWithoutVersionBp := ` 205 aidl_interface { 206 name: "foo", 207 stability: "vintf", 208 srcs: [ 209 "IFoo.aidl", 210 ], 211 }` 212 expectedError := `module "foo_interface": versions: must be set \(need to be frozen\) when "unstable" is false, PLATFORM_VERSION_CODENAME is REL, and "owner" property is missing.` 213 testAidlError(t, expectedError, vintfWithoutVersionBp, setReleaseEnv()) 214 215 ctx, _ := testAidl(t, vintfWithoutVersionBp) 216 assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform") 217} 218 219// Check if using unstable version in release cause an error. 220func TestUnstableVersionUsageInRelease(t *testing.T) { 221 unstableVersionUsageInJavaBp := ` 222 aidl_interface { 223 name: "foo", 224 versions: [ 225 "1", 226 ], 227 srcs: [ 228 "IFoo.aidl", 229 ], 230 } 231 java_library { 232 name: "bar", 233 libs: ["foo-unstable-java"], 234 }` 235 236 expectedError := `unstable-java is disallowed in release version because it is unstable.` 237 testAidlError(t, expectedError, unstableVersionUsageInJavaBp, setReleaseEnv(), withFiles(map[string][]byte{ 238 "aidl_api/foo/1/foo.1.aidl": nil, 239 })) 240 241 testAidl(t, unstableVersionUsageInJavaBp, withFiles(map[string][]byte{ 242 "aidl_api/foo/1/foo.1.aidl": nil, 243 })) 244 245 // A stable version can be used in release version 246 stableVersionUsageInJavaBp := ` 247 aidl_interface { 248 name: "foo", 249 versions: [ 250 "1", 251 ], 252 srcs: [ 253 "IFoo.aidl", 254 ], 255 } 256 java_library { 257 name: "bar", 258 libs: ["foo-java"], 259 }` 260 261 testAidl(t, stableVersionUsageInJavaBp, setReleaseEnv(), withFiles(map[string][]byte{ 262 "aidl_api/foo/1/foo.1.aidl": nil, 263 })) 264 265 testAidl(t, stableVersionUsageInJavaBp, withFiles(map[string][]byte{ 266 "aidl_api/foo/1/foo.1.aidl": nil, 267 })) 268} 269 270// The module which has never been frozen and is not "unstable" is not allowed in release version. 271func TestNonVersionedModuleUsageInRelease(t *testing.T) { 272 nonVersionedModuleUsageInJavaBp := ` 273 aidl_interface { 274 name: "foo", 275 srcs: [ 276 "IFoo.aidl", 277 ], 278 } 279 280 java_library { 281 name: "bar", 282 libs: ["foo-java"], 283 }` 284 285 expectedError := `"foo_interface": versions: must be set \(need to be frozen\) when "unstable" is false, PLATFORM_VERSION_CODENAME is REL, and "owner" property is missing.` 286 testAidlError(t, expectedError, nonVersionedModuleUsageInJavaBp, setReleaseEnv()) 287 testAidl(t, nonVersionedModuleUsageInJavaBp) 288 289 nonVersionedUnstableModuleUsageInJavaBp := ` 290 aidl_interface { 291 name: "foo", 292 srcs: [ 293 "IFoo.aidl", 294 ], 295 unstable: true, 296 } 297 298 java_library { 299 name: "bar", 300 libs: ["foo-java"], 301 }` 302 303 testAidl(t, nonVersionedUnstableModuleUsageInJavaBp, setReleaseEnv()) 304 testAidl(t, nonVersionedUnstableModuleUsageInJavaBp) 305} 306 307func TestUnstableModules(t *testing.T) { 308 testAidlError(t, `module "foo_interface": stability: must be empty when "unstable" is true`, ` 309 aidl_interface { 310 name: "foo", 311 stability: "vintf", 312 unstable: true, 313 srcs: [ 314 "IFoo.aidl", 315 ], 316 } 317 `) 318 319 testAidlError(t, `module "foo_interface": versions: cannot have versions for an unstable interface`, ` 320 aidl_interface { 321 name: "foo", 322 versions: [ 323 "1", 324 ], 325 unstable: true, 326 srcs: [ 327 "IFoo.aidl", 328 ], 329 } 330 `) 331 332 ctx, _ := testAidl(t, ` 333 aidl_interface { 334 name: "foo", 335 unstable: true, 336 srcs: [ 337 "IFoo.aidl", 338 ], 339 } 340 `) 341 342 assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform") 343} 344 345func TestCreatesModulesWithNoVersions(t *testing.T) { 346 ctx, _ := testAidl(t, ` 347 aidl_interface { 348 name: "foo", 349 srcs: [ 350 "IFoo.aidl", 351 ], 352 } 353 `) 354 355 assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform") 356} 357 358func TestCreatesModulesWithFrozenVersions(t *testing.T) { 359 // Each version should be under aidl_api/<name>/<ver> 360 testAidlError(t, `aidl_api/foo/1`, ` 361 aidl_interface { 362 name: "foo", 363 srcs: [ 364 "IFoo.aidl", 365 ], 366 versions: [ 367 "1", 368 ], 369 } 370 `) 371 372 ctx, _ := testAidl(t, ` 373 aidl_interface { 374 name: "foo", 375 srcs: [ 376 "IFoo.aidl", 377 ], 378 versions: [ 379 "1", 380 ], 381 } 382 `, withFiles(map[string][]byte{ 383 "aidl_api/foo/1/foo.1.aidl": nil, 384 })) 385 386 // For alias for the latest frozen version (=1) 387 assertModulesExists(t, ctx, "foo-java", "foo-cpp", "foo-ndk", "foo-ndk_platform") 388 389 // For frozen version "1" 390 // Note that it is not yet implemented to generate native modules for latest frozen version 391 assertModulesExists(t, ctx, "foo-V1-java") 392 393 // For ToT (current) 394 assertModulesExists(t, ctx, "foo-unstable-java", "foo-unstable-cpp", "foo-unstable-ndk", "foo-unstable-ndk_platform") 395} 396 397const ( 398 androidVariant = "android_common" 399 nativeVariant = "android_arm_armv7-a-neon_shared" 400) 401 402func TestNativeOutputIsAlwaysVersioned(t *testing.T) { 403 var ctx *android.TestContext 404 assertOutput := func(moduleName, variant, outputFilename string) { 405 t.Helper() 406 producer, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer) 407 if !ok { 408 t.Errorf("%s(%s): should be OutputFileProducer.", moduleName, variant) 409 } 410 paths, err := producer.OutputFiles("") 411 if err != nil { 412 t.Errorf("%s(%s): failed to get OutputFiles: %v", moduleName, variant, err) 413 } 414 if len(paths) != 1 || paths[0].Base() != outputFilename { 415 t.Errorf("%s(%s): expected output %q, but got %v", moduleName, variant, outputFilename, paths) 416 } 417 } 418 419 // No versions 420 ctx, _ = testAidl(t, ` 421 aidl_interface { 422 name: "foo", 423 srcs: [ 424 "IFoo.aidl", 425 ], 426 } 427 `) 428 429 assertOutput("foo-java", androidVariant, "foo-java.jar") 430 assertOutput("foo-cpp", nativeVariant, "foo-V1-cpp.so") 431 432 // With versions: "1", "2" 433 ctx, _ = testAidl(t, ` 434 aidl_interface { 435 name: "foo", 436 srcs: [ 437 "IFoo.aidl", 438 ], 439 versions: [ 440 "1", "2", 441 ], 442 } 443 `, withFiles(map[string][]byte{ 444 "aidl_api/foo/1/foo.1.aidl": nil, 445 "aidl_api/foo/2/foo.2.aidl": nil, 446 })) 447 448 // alias for the latest frozen version (=2) 449 assertOutput("foo-java", androidVariant, "foo-java.jar") 450 assertOutput("foo-cpp", nativeVariant, "foo-V2-cpp.so") 451 452 // frozen "1" 453 assertOutput("foo-V1-java", androidVariant, "foo-V1-java.jar") 454 assertOutput("foo-V1-cpp", nativeVariant, "foo-V1-cpp.so") 455 456 // tot 457 assertOutput("foo-unstable-java", androidVariant, "foo-unstable-java.jar") 458 assertOutput("foo-unstable-cpp", nativeVariant, "foo-V3-cpp.so") 459 460 // skip ndk/ndk_platform since they follow the same rule with cpp 461} 462 463func TestGenLogForNativeBackendRequiresJson(t *testing.T) { 464 testAidlError(t, `"foo-cpp" depends on .*"libjsoncpp"`, ` 465 aidl_interface { 466 name: "foo", 467 srcs: [ 468 "IFoo.aidl", 469 ], 470 backend: { 471 cpp: { 472 gen_log: true, 473 }, 474 }, 475 } 476 `) 477 testAidl(t, ` 478 aidl_interface { 479 name: "foo", 480 srcs: [ 481 "IFoo.aidl", 482 ], 483 backend: { 484 cpp: { 485 gen_log: true, 486 }, 487 }, 488 } 489 cc_library { 490 name: "libjsoncpp", 491 } 492 `) 493} 494 495func TestImports(t *testing.T) { 496 testAidlError(t, `Import does not exist:`, ` 497 aidl_interface { 498 name: "foo", 499 srcs: [ 500 "IFoo.aidl", 501 ], 502 imports: [ 503 "bar", 504 ] 505 } 506 `) 507 508 testAidlError(t, `backend.java.enabled: Java backend not enabled in the imported AIDL interface "bar"`, ` 509 aidl_interface { 510 name: "foo", 511 srcs: [ 512 "IFoo.aidl", 513 ], 514 imports: [ 515 "bar", 516 ] 517 } 518 aidl_interface { 519 name: "bar", 520 srcs: [ 521 "IBar.aidl", 522 ], 523 backend: { 524 java: { 525 enabled: false, 526 }, 527 }, 528 } 529 `) 530 531 testAidlError(t, `backend.cpp.enabled: C\+\+ backend not enabled in the imported AIDL interface "bar"`, ` 532 aidl_interface { 533 name: "foo", 534 srcs: [ 535 "IFoo.aidl", 536 ], 537 imports: [ 538 "bar", 539 ] 540 } 541 aidl_interface { 542 name: "bar", 543 srcs: [ 544 "IBar.aidl", 545 ], 546 backend: { 547 cpp: { 548 enabled: false, 549 }, 550 }, 551 } 552 `) 553 554 ctx, _ := testAidl(t, ` 555 aidl_interface { 556 name: "foo", 557 srcs: [ 558 "IFoo.aidl", 559 ], 560 imports: [ 561 "bar", 562 ] 563 } 564 aidl_interface { 565 name: "bar", 566 srcs: [ 567 "IBar.aidl", 568 ], 569 } 570 `) 571 572 ldRule := ctx.ModuleForTests("foo-cpp", nativeVariant).Rule("ld") 573 libFlags := ldRule.Args["libFlags"] 574 libBar := filepath.Join("bar-cpp", nativeVariant, "bar-V1-cpp.so") 575 if !strings.Contains(libFlags, libBar) { 576 t.Errorf("%q is not found in %q", libBar, libFlags) 577 } 578} 579 580func TestDuplicatedVersions(t *testing.T) { 581 // foo depends on myiface-ndk (v2) via direct dep and also on 582 // myiface-V1-ndk via indirect dep. This should be prohibited. 583 testAidlError(t, `multiple versions of aidl_interface myiface \(backend:ndk\) are used`, ` 584 aidl_interface { 585 name: "myiface", 586 srcs: ["IFoo.aidl"], 587 versions: ["1", "2"], 588 } 589 590 cc_library { 591 name: "foo", 592 shared_libs: ["myiface-ndk", "bar"], 593 } 594 595 cc_library { 596 name: "bar", 597 shared_libs: ["myiface-V1-ndk"], 598 } 599 600 `, withFiles(map[string][]byte{ 601 "aidl_api/myiface/1/myiface.1.aidl": nil, 602 "aidl_api/myiface/1/.hash": nil, 603 "aidl_api/myiface/2/myiface.2.aidl": nil, 604 "aidl_api/myiface/2/.hash": nil, 605 })) 606} 607