1// 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 java 16 17import ( 18 "android/soong/android" 19 "android/soong/cc" 20 21 "fmt" 22 "path/filepath" 23 "reflect" 24 "sort" 25 "strings" 26 "testing" 27 28 "github.com/google/blueprint/proptools" 29) 30 31var ( 32 resourceFiles = []string{ 33 "res/layout/layout.xml", 34 "res/values/strings.xml", 35 "res/values-en-rUS/strings.xml", 36 } 37 38 compiledResourceFiles = []string{ 39 "aapt2/res/layout_layout.xml.flat", 40 "aapt2/res/values_strings.arsc.flat", 41 "aapt2/res/values-en-rUS_strings.arsc.flat", 42 } 43) 44 45func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext { 46 appFS := map[string][]byte{} 47 for k, v := range fs { 48 appFS[k] = v 49 } 50 51 for _, file := range resourceFiles { 52 appFS[file] = nil 53 } 54 55 return testContext(config, bp, appFS) 56} 57 58func testApp(t *testing.T, bp string) *android.TestContext { 59 config := testConfig(nil) 60 61 ctx := testAppContext(config, bp, nil) 62 63 run(t, ctx, config) 64 65 return ctx 66} 67 68func TestApp(t *testing.T) { 69 for _, moduleType := range []string{"android_app", "android_library"} { 70 t.Run(moduleType, func(t *testing.T) { 71 ctx := testApp(t, moduleType+` { 72 name: "foo", 73 srcs: ["a.java"], 74 } 75 `) 76 77 foo := ctx.ModuleForTests("foo", "android_common") 78 79 var expectedLinkImplicits []string 80 81 manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml") 82 expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String()) 83 84 frameworkRes := ctx.ModuleForTests("framework-res", "android_common") 85 expectedLinkImplicits = append(expectedLinkImplicits, 86 frameworkRes.Output("package-res.apk").Output.String()) 87 88 // Test the mapping from input files to compiled output file names 89 compile := foo.Output(compiledResourceFiles[0]) 90 if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) { 91 t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v", 92 resourceFiles, compile.Inputs.Strings()) 93 } 94 95 compiledResourceOutputs := compile.Outputs.Strings() 96 sort.Strings(compiledResourceOutputs) 97 98 expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...) 99 100 list := foo.Output("aapt2/res.list") 101 expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String()) 102 103 // Check that the link rule uses 104 res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk") 105 if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) { 106 t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v", 107 expectedLinkImplicits, res.Implicits.Strings()) 108 } 109 }) 110 } 111} 112 113func TestAppSplits(t *testing.T) { 114 ctx := testApp(t, ` 115 android_app { 116 name: "foo", 117 srcs: ["a.java"], 118 package_splits: ["v4", "v7,hdpi"], 119 }`) 120 121 foo := ctx.ModuleForTests("foo", "android_common") 122 123 expectedOutputs := []string{ 124 filepath.Join(buildDir, ".intermediates/foo/android_common/foo.apk"), 125 filepath.Join(buildDir, ".intermediates/foo/android_common/foo_v4.apk"), 126 filepath.Join(buildDir, ".intermediates/foo/android_common/foo_v7_hdpi.apk"), 127 } 128 for _, expectedOutput := range expectedOutputs { 129 foo.Output(expectedOutput) 130 } 131 132 if g, w := foo.Module().(*AndroidApp).Srcs().Strings(), expectedOutputs; !reflect.DeepEqual(g, w) { 133 t.Errorf("want Srcs() = %q, got %q", w, g) 134 } 135} 136 137func TestResourceDirs(t *testing.T) { 138 testCases := []struct { 139 name string 140 prop string 141 resources []string 142 }{ 143 { 144 name: "no resource_dirs", 145 prop: "", 146 resources: []string{"res/res/values/strings.xml"}, 147 }, 148 { 149 name: "resource_dirs", 150 prop: `resource_dirs: ["res"]`, 151 resources: []string{"res/res/values/strings.xml"}, 152 }, 153 { 154 name: "empty resource_dirs", 155 prop: `resource_dirs: []`, 156 resources: nil, 157 }, 158 } 159 160 fs := map[string][]byte{ 161 "res/res/values/strings.xml": nil, 162 } 163 164 bp := ` 165 android_app { 166 name: "foo", 167 %s 168 } 169 ` 170 171 for _, testCase := range testCases { 172 t.Run(testCase.name, func(t *testing.T) { 173 config := testConfig(nil) 174 ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs) 175 run(t, ctx, config) 176 177 module := ctx.ModuleForTests("foo", "android_common") 178 resourceList := module.MaybeOutput("aapt2/res.list") 179 180 var resources []string 181 if resourceList.Rule != nil { 182 for _, compiledResource := range resourceList.Inputs.Strings() { 183 resources = append(resources, module.Output(compiledResource).Inputs.Strings()...) 184 } 185 } 186 187 if !reflect.DeepEqual(resources, testCase.resources) { 188 t.Errorf("expected resource files %q, got %q", 189 testCase.resources, resources) 190 } 191 }) 192 } 193} 194 195func TestAndroidResources(t *testing.T) { 196 testCases := []struct { 197 name string 198 enforceRROTargets []string 199 enforceRROExcludedOverlays []string 200 resourceFiles map[string][]string 201 overlayFiles map[string][]string 202 rroDirs map[string][]string 203 }{ 204 { 205 name: "no RRO", 206 enforceRROTargets: nil, 207 enforceRROExcludedOverlays: nil, 208 resourceFiles: map[string][]string{ 209 "foo": nil, 210 "bar": {"bar/res/res/values/strings.xml"}, 211 "lib": nil, 212 "lib2": {"lib2/res/res/values/strings.xml"}, 213 }, 214 overlayFiles: map[string][]string{ 215 "foo": { 216 buildDir + "/.intermediates/lib2/android_common/package-res.apk", 217 buildDir + "/.intermediates/lib/android_common/package-res.apk", 218 buildDir + "/.intermediates/lib3/android_common/package-res.apk", 219 "foo/res/res/values/strings.xml", 220 "device/vendor/blah/static_overlay/foo/res/values/strings.xml", 221 "device/vendor/blah/overlay/foo/res/values/strings.xml", 222 "product/vendor/blah/overlay/foo/res/values/strings.xml", 223 }, 224 "bar": { 225 "device/vendor/blah/static_overlay/bar/res/values/strings.xml", 226 "device/vendor/blah/overlay/bar/res/values/strings.xml", 227 }, 228 "lib": { 229 buildDir + "/.intermediates/lib2/android_common/package-res.apk", 230 "lib/res/res/values/strings.xml", 231 "device/vendor/blah/overlay/lib/res/values/strings.xml", 232 }, 233 }, 234 rroDirs: map[string][]string{ 235 "foo": nil, 236 "bar": nil, 237 }, 238 }, 239 { 240 name: "enforce RRO on foo", 241 enforceRROTargets: []string{"foo"}, 242 enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"}, 243 resourceFiles: map[string][]string{ 244 "foo": nil, 245 "bar": {"bar/res/res/values/strings.xml"}, 246 "lib": nil, 247 "lib2": {"lib2/res/res/values/strings.xml"}, 248 }, 249 overlayFiles: map[string][]string{ 250 "foo": { 251 buildDir + "/.intermediates/lib2/android_common/package-res.apk", 252 buildDir + "/.intermediates/lib/android_common/package-res.apk", 253 buildDir + "/.intermediates/lib3/android_common/package-res.apk", 254 "foo/res/res/values/strings.xml", 255 "device/vendor/blah/static_overlay/foo/res/values/strings.xml", 256 }, 257 "bar": { 258 "device/vendor/blah/static_overlay/bar/res/values/strings.xml", 259 "device/vendor/blah/overlay/bar/res/values/strings.xml", 260 }, 261 "lib": { 262 buildDir + "/.intermediates/lib2/android_common/package-res.apk", 263 "lib/res/res/values/strings.xml", 264 "device/vendor/blah/overlay/lib/res/values/strings.xml", 265 }, 266 }, 267 268 rroDirs: map[string][]string{ 269 "foo": { 270 "device:device/vendor/blah/overlay/foo/res", 271 // Enforce RRO on "foo" could imply RRO on static dependencies, but for now it doesn't. 272 // "device/vendor/blah/overlay/lib/res", 273 "product:product/vendor/blah/overlay/foo/res", 274 }, 275 "bar": nil, 276 "lib": nil, 277 }, 278 }, 279 { 280 name: "enforce RRO on all", 281 enforceRROTargets: []string{"*"}, 282 enforceRROExcludedOverlays: []string{ 283 // Excluding specific apps/res directories also allowed. 284 "device/vendor/blah/static_overlay/foo", 285 "device/vendor/blah/static_overlay/bar/res", 286 }, 287 resourceFiles: map[string][]string{ 288 "foo": nil, 289 "bar": {"bar/res/res/values/strings.xml"}, 290 "lib": nil, 291 "lib2": {"lib2/res/res/values/strings.xml"}, 292 }, 293 overlayFiles: map[string][]string{ 294 "foo": { 295 buildDir + "/.intermediates/lib2/android_common/package-res.apk", 296 buildDir + "/.intermediates/lib/android_common/package-res.apk", 297 buildDir + "/.intermediates/lib3/android_common/package-res.apk", 298 "foo/res/res/values/strings.xml", 299 "device/vendor/blah/static_overlay/foo/res/values/strings.xml", 300 }, 301 "bar": {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"}, 302 "lib": { 303 buildDir + "/.intermediates/lib2/android_common/package-res.apk", 304 "lib/res/res/values/strings.xml", 305 }, 306 }, 307 rroDirs: map[string][]string{ 308 "foo": { 309 "device:device/vendor/blah/overlay/foo/res", 310 "product:product/vendor/blah/overlay/foo/res", 311 // Lib dep comes after the direct deps 312 "device:device/vendor/blah/overlay/lib/res", 313 }, 314 "bar": {"device:device/vendor/blah/overlay/bar/res"}, 315 "lib": {"device:device/vendor/blah/overlay/lib/res"}, 316 }, 317 }, 318 } 319 320 deviceResourceOverlays := []string{ 321 "device/vendor/blah/overlay", 322 "device/vendor/blah/overlay2", 323 "device/vendor/blah/static_overlay", 324 } 325 326 productResourceOverlays := []string{ 327 "product/vendor/blah/overlay", 328 } 329 330 fs := map[string][]byte{ 331 "foo/res/res/values/strings.xml": nil, 332 "bar/res/res/values/strings.xml": nil, 333 "lib/res/res/values/strings.xml": nil, 334 "lib2/res/res/values/strings.xml": nil, 335 "device/vendor/blah/overlay/foo/res/values/strings.xml": nil, 336 "device/vendor/blah/overlay/bar/res/values/strings.xml": nil, 337 "device/vendor/blah/overlay/lib/res/values/strings.xml": nil, 338 "device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil, 339 "device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil, 340 "device/vendor/blah/overlay2/res/values/strings.xml": nil, 341 "product/vendor/blah/overlay/foo/res/values/strings.xml": nil, 342 } 343 344 bp := ` 345 android_app { 346 name: "foo", 347 resource_dirs: ["foo/res"], 348 static_libs: ["lib", "lib3"], 349 } 350 351 android_app { 352 name: "bar", 353 resource_dirs: ["bar/res"], 354 } 355 356 android_library { 357 name: "lib", 358 resource_dirs: ["lib/res"], 359 static_libs: ["lib2"], 360 } 361 362 android_library { 363 name: "lib2", 364 resource_dirs: ["lib2/res"], 365 } 366 367 // This library has the same resources as lib (should not lead to dupe RROs) 368 android_library { 369 name: "lib3", 370 resource_dirs: ["lib/res"] 371 } 372 ` 373 374 for _, testCase := range testCases { 375 t.Run(testCase.name, func(t *testing.T) { 376 config := testConfig(nil) 377 config.TestProductVariables.DeviceResourceOverlays = deviceResourceOverlays 378 config.TestProductVariables.ProductResourceOverlays = productResourceOverlays 379 if testCase.enforceRROTargets != nil { 380 config.TestProductVariables.EnforceRROTargets = testCase.enforceRROTargets 381 } 382 if testCase.enforceRROExcludedOverlays != nil { 383 config.TestProductVariables.EnforceRROExcludedOverlays = testCase.enforceRROExcludedOverlays 384 } 385 386 ctx := testAppContext(config, bp, fs) 387 run(t, ctx, config) 388 389 resourceListToFiles := func(module android.TestingModule, list []string) (files []string) { 390 for _, o := range list { 391 res := module.MaybeOutput(o) 392 if res.Rule != nil { 393 // If the overlay is compiled as part of this module (i.e. a .arsc.flat file), 394 // verify the inputs to the .arsc.flat rule. 395 files = append(files, res.Inputs.Strings()...) 396 } else { 397 // Otherwise, verify the full path to the output of the other module 398 files = append(files, o) 399 } 400 } 401 return files 402 } 403 404 getResources := func(moduleName string) (resourceFiles, overlayFiles, rroDirs []string) { 405 module := ctx.ModuleForTests(moduleName, "android_common") 406 resourceList := module.MaybeOutput("aapt2/res.list") 407 if resourceList.Rule != nil { 408 resourceFiles = resourceListToFiles(module, resourceList.Inputs.Strings()) 409 } 410 overlayList := module.MaybeOutput("aapt2/overlay.list") 411 if overlayList.Rule != nil { 412 overlayFiles = resourceListToFiles(module, overlayList.Inputs.Strings()) 413 } 414 415 for _, d := range module.Module().(AndroidLibraryDependency).ExportedRRODirs() { 416 var prefix string 417 if d.overlayType == device { 418 prefix = "device:" 419 } else if d.overlayType == product { 420 prefix = "product:" 421 } else { 422 t.Fatalf("Unexpected overlayType %d", d.overlayType) 423 } 424 rroDirs = append(rroDirs, prefix+d.path.String()) 425 } 426 427 return resourceFiles, overlayFiles, rroDirs 428 } 429 430 modules := []string{"foo", "bar", "lib", "lib2"} 431 for _, module := range modules { 432 resourceFiles, overlayFiles, rroDirs := getResources(module) 433 434 if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[module]) { 435 t.Errorf("expected %s resource files:\n %#v\n got:\n %#v", 436 module, testCase.resourceFiles[module], resourceFiles) 437 } 438 if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[module]) { 439 t.Errorf("expected %s overlay files:\n %#v\n got:\n %#v", 440 module, testCase.overlayFiles[module], overlayFiles) 441 } 442 if !reflect.DeepEqual(rroDirs, testCase.rroDirs[module]) { 443 t.Errorf("expected %s rroDirs: %#v\n got:\n %#v", 444 module, testCase.rroDirs[module], rroDirs) 445 } 446 } 447 }) 448 } 449} 450 451func TestAppSdkVersion(t *testing.T) { 452 testCases := []struct { 453 name string 454 sdkVersion string 455 platformSdkInt int 456 platformSdkCodename string 457 platformSdkFinal bool 458 expectedMinSdkVersion string 459 }{ 460 { 461 name: "current final SDK", 462 sdkVersion: "current", 463 platformSdkInt: 27, 464 platformSdkCodename: "REL", 465 platformSdkFinal: true, 466 expectedMinSdkVersion: "27", 467 }, 468 { 469 name: "current non-final SDK", 470 sdkVersion: "current", 471 platformSdkInt: 27, 472 platformSdkCodename: "OMR1", 473 platformSdkFinal: false, 474 expectedMinSdkVersion: "OMR1", 475 }, 476 { 477 name: "default final SDK", 478 sdkVersion: "", 479 platformSdkInt: 27, 480 platformSdkCodename: "REL", 481 platformSdkFinal: true, 482 expectedMinSdkVersion: "27", 483 }, 484 { 485 name: "default non-final SDK", 486 sdkVersion: "", 487 platformSdkInt: 27, 488 platformSdkCodename: "OMR1", 489 platformSdkFinal: false, 490 expectedMinSdkVersion: "OMR1", 491 }, 492 { 493 name: "14", 494 sdkVersion: "14", 495 expectedMinSdkVersion: "14", 496 }, 497 } 498 499 for _, moduleType := range []string{"android_app", "android_library"} { 500 for _, test := range testCases { 501 t.Run(moduleType+" "+test.name, func(t *testing.T) { 502 bp := fmt.Sprintf(`%s { 503 name: "foo", 504 srcs: ["a.java"], 505 sdk_version: "%s", 506 }`, moduleType, test.sdkVersion) 507 508 config := testConfig(nil) 509 config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt 510 config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename 511 config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal 512 513 ctx := testAppContext(config, bp, nil) 514 515 run(t, ctx, config) 516 517 foo := ctx.ModuleForTests("foo", "android_common") 518 link := foo.Output("package-res.apk") 519 linkFlags := strings.Split(link.Args["flags"], " ") 520 min := android.IndexList("--min-sdk-version", linkFlags) 521 target := android.IndexList("--target-sdk-version", linkFlags) 522 523 if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { 524 t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) 525 } 526 527 gotMinSdkVersion := linkFlags[min+1] 528 gotTargetSdkVersion := linkFlags[target+1] 529 530 if gotMinSdkVersion != test.expectedMinSdkVersion { 531 t.Errorf("incorrect --min-sdk-version, expected %q got %q", 532 test.expectedMinSdkVersion, gotMinSdkVersion) 533 } 534 535 if gotTargetSdkVersion != test.expectedMinSdkVersion { 536 t.Errorf("incorrect --target-sdk-version, expected %q got %q", 537 test.expectedMinSdkVersion, gotTargetSdkVersion) 538 } 539 }) 540 } 541 } 542} 543 544func TestJNIABI(t *testing.T) { 545 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` 546 cc_library { 547 name: "libjni", 548 system_shared_libs: [], 549 stl: "none", 550 } 551 552 android_test { 553 name: "test", 554 no_framework_libs: true, 555 jni_libs: ["libjni"], 556 } 557 558 android_test { 559 name: "test_first", 560 no_framework_libs: true, 561 compile_multilib: "first", 562 jni_libs: ["libjni"], 563 } 564 565 android_test { 566 name: "test_both", 567 no_framework_libs: true, 568 compile_multilib: "both", 569 jni_libs: ["libjni"], 570 } 571 572 android_test { 573 name: "test_32", 574 no_framework_libs: true, 575 compile_multilib: "32", 576 jni_libs: ["libjni"], 577 } 578 579 android_test { 580 name: "test_64", 581 no_framework_libs: true, 582 compile_multilib: "64", 583 jni_libs: ["libjni"], 584 } 585 `) 586 587 testCases := []struct { 588 name string 589 abis []string 590 }{ 591 {"test", []string{"arm64-v8a"}}, 592 {"test_first", []string{"arm64-v8a"}}, 593 {"test_both", []string{"arm64-v8a", "armeabi-v7a"}}, 594 {"test_32", []string{"armeabi-v7a"}}, 595 {"test_64", []string{"arm64-v8a"}}, 596 } 597 598 for _, test := range testCases { 599 t.Run(test.name, func(t *testing.T) { 600 app := ctx.ModuleForTests(test.name, "android_common") 601 jniLibZip := app.Output("jnilibs.zip") 602 var abis []string 603 args := strings.Fields(jniLibZip.Args["jarArgs"]) 604 for i := 0; i < len(args); i++ { 605 if args[i] == "-P" { 606 abis = append(abis, filepath.Base(args[i+1])) 607 i++ 608 } 609 } 610 if !reflect.DeepEqual(abis, test.abis) { 611 t.Errorf("want abis %v, got %v", test.abis, abis) 612 } 613 }) 614 } 615} 616 617func TestJNIPackaging(t *testing.T) { 618 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` 619 cc_library { 620 name: "libjni", 621 system_shared_libs: [], 622 stl: "none", 623 } 624 625 android_app { 626 name: "app", 627 jni_libs: ["libjni"], 628 } 629 630 android_app { 631 name: "app_noembed", 632 jni_libs: ["libjni"], 633 use_embedded_native_libs: false, 634 } 635 636 android_app { 637 name: "app_embed", 638 jni_libs: ["libjni"], 639 use_embedded_native_libs: true, 640 } 641 642 android_test { 643 name: "test", 644 no_framework_libs: true, 645 jni_libs: ["libjni"], 646 } 647 648 android_test { 649 name: "test_noembed", 650 no_framework_libs: true, 651 jni_libs: ["libjni"], 652 use_embedded_native_libs: false, 653 } 654 655 android_test_helper_app { 656 name: "test_helper", 657 no_framework_libs: true, 658 jni_libs: ["libjni"], 659 } 660 661 android_test_helper_app { 662 name: "test_helper_noembed", 663 no_framework_libs: true, 664 jni_libs: ["libjni"], 665 use_embedded_native_libs: false, 666 } 667 `) 668 669 testCases := []struct { 670 name string 671 packaged bool 672 compressed bool 673 }{ 674 {"app", false, false}, 675 {"app_noembed", false, false}, 676 {"app_embed", true, false}, 677 {"test", true, false}, 678 {"test_noembed", true, true}, 679 {"test_helper", true, false}, 680 {"test_helper_noembed", true, true}, 681 } 682 683 for _, test := range testCases { 684 t.Run(test.name, func(t *testing.T) { 685 app := ctx.ModuleForTests(test.name, "android_common") 686 jniLibZip := app.MaybeOutput("jnilibs.zip") 687 if g, w := (jniLibZip.Rule != nil), test.packaged; g != w { 688 t.Errorf("expected jni packaged %v, got %v", w, g) 689 } 690 691 if jniLibZip.Rule != nil { 692 if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w { 693 t.Errorf("expected jni compressed %v, got %v", w, g) 694 } 695 } 696 }) 697 } 698 699} 700 701func TestCertificates(t *testing.T) { 702 testCases := []struct { 703 name string 704 bp string 705 certificateOverride string 706 expected string 707 }{ 708 { 709 name: "default", 710 bp: ` 711 android_app { 712 name: "foo", 713 srcs: ["a.java"], 714 } 715 `, 716 certificateOverride: "", 717 expected: "build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8", 718 }, 719 { 720 name: "module certificate property", 721 bp: ` 722 android_app { 723 name: "foo", 724 srcs: ["a.java"], 725 certificate: ":new_certificate" 726 } 727 728 android_app_certificate { 729 name: "new_certificate", 730 certificate: "cert/new_cert", 731 } 732 `, 733 certificateOverride: "", 734 expected: "cert/new_cert.x509.pem cert/new_cert.pk8", 735 }, 736 { 737 name: "path certificate property", 738 bp: ` 739 android_app { 740 name: "foo", 741 srcs: ["a.java"], 742 certificate: "expiredkey" 743 } 744 `, 745 certificateOverride: "", 746 expected: "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8", 747 }, 748 { 749 name: "certificate overrides", 750 bp: ` 751 android_app { 752 name: "foo", 753 srcs: ["a.java"], 754 certificate: "expiredkey" 755 } 756 757 android_app_certificate { 758 name: "new_certificate", 759 certificate: "cert/new_cert", 760 } 761 `, 762 certificateOverride: "foo:new_certificate", 763 expected: "cert/new_cert.x509.pem cert/new_cert.pk8", 764 }, 765 } 766 767 for _, test := range testCases { 768 t.Run(test.name, func(t *testing.T) { 769 config := testConfig(nil) 770 if test.certificateOverride != "" { 771 config.TestProductVariables.CertificateOverrides = []string{test.certificateOverride} 772 } 773 ctx := testAppContext(config, test.bp, nil) 774 775 run(t, ctx, config) 776 foo := ctx.ModuleForTests("foo", "android_common") 777 778 signapk := foo.Output("foo.apk") 779 signFlags := signapk.Args["certificates"] 780 if test.expected != signFlags { 781 t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags) 782 } 783 }) 784 } 785} 786 787func TestPackageNameOverride(t *testing.T) { 788 testCases := []struct { 789 name string 790 bp string 791 packageNameOverride string 792 expected []string 793 }{ 794 { 795 name: "default", 796 bp: ` 797 android_app { 798 name: "foo", 799 srcs: ["a.java"], 800 } 801 `, 802 packageNameOverride: "", 803 expected: []string{ 804 buildDir + "/.intermediates/foo/android_common/foo.apk", 805 buildDir + "/target/product/test_device/system/app/foo/foo.apk", 806 }, 807 }, 808 { 809 name: "overridden", 810 bp: ` 811 android_app { 812 name: "foo", 813 srcs: ["a.java"], 814 } 815 `, 816 packageNameOverride: "foo:bar", 817 expected: []string{ 818 // The package apk should be still be the original name for test dependencies. 819 buildDir + "/.intermediates/foo/android_common/foo.apk", 820 buildDir + "/target/product/test_device/system/app/bar/bar.apk", 821 }, 822 }, 823 } 824 825 for _, test := range testCases { 826 t.Run(test.name, func(t *testing.T) { 827 config := testConfig(nil) 828 if test.packageNameOverride != "" { 829 config.TestProductVariables.PackageNameOverrides = []string{test.packageNameOverride} 830 } 831 ctx := testAppContext(config, test.bp, nil) 832 833 run(t, ctx, config) 834 foo := ctx.ModuleForTests("foo", "android_common") 835 836 outputs := foo.AllOutputs() 837 outputMap := make(map[string]bool) 838 for _, o := range outputs { 839 outputMap[o] = true 840 } 841 for _, e := range test.expected { 842 if _, exist := outputMap[e]; !exist { 843 t.Errorf("Can't find %q in output files.\nAll outputs:%v", e, outputs) 844 } 845 } 846 }) 847 } 848} 849 850func TestInstrumentationTargetOverridden(t *testing.T) { 851 bp := ` 852 android_app { 853 name: "foo", 854 srcs: ["a.java"], 855 } 856 857 android_test { 858 name: "bar", 859 instrumentation_for: "foo", 860 } 861 ` 862 config := testConfig(nil) 863 config.TestProductVariables.ManifestPackageNameOverrides = []string{"foo:org.dandroid.bp"} 864 ctx := testAppContext(config, bp, nil) 865 866 run(t, ctx, config) 867 868 bar := ctx.ModuleForTests("bar", "android_common") 869 res := bar.Output("package-res.apk") 870 aapt2Flags := res.Args["flags"] 871 e := "--rename-instrumentation-target-package org.dandroid.bp" 872 if !strings.Contains(aapt2Flags, e) { 873 t.Errorf("target package renaming flag, %q is missing in aapt2 link flags, %q", e, aapt2Flags) 874 } 875} 876 877func TestOverrideAndroidApp(t *testing.T) { 878 ctx := testJava(t, ` 879 android_app { 880 name: "foo", 881 srcs: ["a.java"], 882 certificate: "expiredkey", 883 overrides: ["baz"], 884 } 885 886 override_android_app { 887 name: "bar", 888 base: "foo", 889 certificate: ":new_certificate", 890 } 891 892 android_app_certificate { 893 name: "new_certificate", 894 certificate: "cert/new_cert", 895 } 896 897 override_android_app { 898 name: "baz", 899 base: "foo", 900 package_name: "org.dandroid.bp", 901 } 902 `) 903 904 expectedVariants := []struct { 905 variantName string 906 apkName string 907 apkPath string 908 signFlag string 909 overrides []string 910 aaptFlag string 911 }{ 912 { 913 variantName: "android_common", 914 apkPath: "/target/product/test_device/system/app/foo/foo.apk", 915 signFlag: "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8", 916 overrides: []string{"baz"}, 917 aaptFlag: "", 918 }, 919 { 920 variantName: "bar_android_common", 921 apkPath: "/target/product/test_device/system/app/bar/bar.apk", 922 signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", 923 overrides: []string{"baz", "foo"}, 924 aaptFlag: "", 925 }, 926 { 927 variantName: "baz_android_common", 928 apkPath: "/target/product/test_device/system/app/baz/baz.apk", 929 signFlag: "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8", 930 overrides: []string{"baz", "foo"}, 931 aaptFlag: "--rename-manifest-package org.dandroid.bp", 932 }, 933 } 934 for _, expected := range expectedVariants { 935 variant := ctx.ModuleForTests("foo", expected.variantName) 936 937 // Check the final apk name 938 outputs := variant.AllOutputs() 939 expectedApkPath := buildDir + expected.apkPath 940 found := false 941 for _, o := range outputs { 942 if o == expectedApkPath { 943 found = true 944 break 945 } 946 } 947 if !found { 948 t.Errorf("Can't find %q in output files.\nAll outputs:%v", expectedApkPath, outputs) 949 } 950 951 // Check the certificate paths 952 signapk := variant.Output("foo.apk") 953 signFlag := signapk.Args["certificates"] 954 if expected.signFlag != signFlag { 955 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag) 956 } 957 958 // Check if the overrides field values are correctly aggregated. 959 mod := variant.Module().(*AndroidApp) 960 if !reflect.DeepEqual(expected.overrides, mod.appProperties.Overrides) { 961 t.Errorf("Incorrect overrides property value, expected: %q, got: %q", 962 expected.overrides, mod.appProperties.Overrides) 963 } 964 965 // Check the package renaming flag, if exists. 966 res := variant.Output("package-res.apk") 967 aapt2Flags := res.Args["flags"] 968 if !strings.Contains(aapt2Flags, expected.aaptFlag) { 969 t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags) 970 } 971 } 972} 973 974func TestEmbedNotice(t *testing.T) { 975 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` 976 android_app { 977 name: "foo", 978 srcs: ["a.java"], 979 static_libs: ["javalib"], 980 jni_libs: ["libjni"], 981 notice: "APP_NOTICE", 982 embed_notices: true, 983 } 984 985 // No embed_notice flag 986 android_app { 987 name: "bar", 988 srcs: ["a.java"], 989 jni_libs: ["libjni"], 990 notice: "APP_NOTICE", 991 } 992 993 // No NOTICE files 994 android_app { 995 name: "baz", 996 srcs: ["a.java"], 997 embed_notices: true, 998 } 999 1000 cc_library { 1001 name: "libjni", 1002 system_shared_libs: [], 1003 stl: "none", 1004 notice: "LIB_NOTICE", 1005 } 1006 1007 java_library { 1008 name: "javalib", 1009 srcs: [ 1010 ":gen", 1011 ], 1012 } 1013 1014 genrule { 1015 name: "gen", 1016 tools: ["gentool"], 1017 out: ["gen.java"], 1018 notice: "GENRULE_NOTICE", 1019 } 1020 1021 java_binary_host { 1022 name: "gentool", 1023 srcs: ["b.java"], 1024 notice: "TOOL_NOTICE", 1025 } 1026 `) 1027 1028 // foo has NOTICE files to process, and embed_notices is true. 1029 foo := ctx.ModuleForTests("foo", "android_common") 1030 // verify merge notices rule. 1031 mergeNotices := foo.Rule("mergeNoticesRule") 1032 noticeInputs := mergeNotices.Inputs.Strings() 1033 // TOOL_NOTICE should be excluded as it's a host module. 1034 if len(mergeNotices.Inputs) != 3 { 1035 t.Errorf("number of input notice files: expected = 3, actual = %q", noticeInputs) 1036 } 1037 if !inList("APP_NOTICE", noticeInputs) { 1038 t.Errorf("APP_NOTICE is missing from notice files, %q", noticeInputs) 1039 } 1040 if !inList("LIB_NOTICE", noticeInputs) { 1041 t.Errorf("LIB_NOTICE is missing from notice files, %q", noticeInputs) 1042 } 1043 if !inList("GENRULE_NOTICE", noticeInputs) { 1044 t.Errorf("GENRULE_NOTICE is missing from notice files, %q", noticeInputs) 1045 } 1046 // aapt2 flags should include -A <NOTICE dir> so that its contents are put in the APK's /assets. 1047 res := foo.Output("package-res.apk") 1048 aapt2Flags := res.Args["flags"] 1049 e := "-A " + buildDir + "/.intermediates/foo/android_common/NOTICE" 1050 if !strings.Contains(aapt2Flags, e) { 1051 t.Errorf("asset dir flag for NOTICE, %q is missing in aapt2 link flags, %q", e, aapt2Flags) 1052 } 1053 1054 // bar has NOTICE files to process, but embed_notices is not set. 1055 bar := ctx.ModuleForTests("bar", "android_common") 1056 mergeNotices = bar.MaybeRule("mergeNoticesRule") 1057 if mergeNotices.Rule != nil { 1058 t.Errorf("mergeNotices shouldn't have run for bar") 1059 } 1060 1061 // baz's embed_notice is true, but it doesn't have any NOTICE files. 1062 baz := ctx.ModuleForTests("baz", "android_common") 1063 mergeNotices = baz.MaybeRule("mergeNoticesRule") 1064 if mergeNotices.Rule != nil { 1065 t.Errorf("mergeNotices shouldn't have run for baz") 1066 } 1067} 1068 1069func TestUncompressDex(t *testing.T) { 1070 testCases := []struct { 1071 name string 1072 bp string 1073 1074 uncompressedPlatform bool 1075 uncompressedUnbundled bool 1076 }{ 1077 { 1078 name: "normal", 1079 bp: ` 1080 android_app { 1081 name: "foo", 1082 srcs: ["a.java"], 1083 } 1084 `, 1085 uncompressedPlatform: true, 1086 uncompressedUnbundled: false, 1087 }, 1088 { 1089 name: "use_embedded_dex", 1090 bp: ` 1091 android_app { 1092 name: "foo", 1093 use_embedded_dex: true, 1094 srcs: ["a.java"], 1095 } 1096 `, 1097 uncompressedPlatform: true, 1098 uncompressedUnbundled: true, 1099 }, 1100 { 1101 name: "privileged", 1102 bp: ` 1103 android_app { 1104 name: "foo", 1105 privileged: true, 1106 srcs: ["a.java"], 1107 } 1108 `, 1109 uncompressedPlatform: true, 1110 uncompressedUnbundled: true, 1111 }, 1112 } 1113 1114 test := func(t *testing.T, bp string, want bool, unbundled bool) { 1115 t.Helper() 1116 1117 config := testConfig(nil) 1118 if unbundled { 1119 config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true) 1120 } 1121 1122 ctx := testAppContext(config, bp, nil) 1123 1124 run(t, ctx, config) 1125 1126 foo := ctx.ModuleForTests("foo", "android_common") 1127 dex := foo.Rule("r8") 1128 uncompressedInDexJar := strings.Contains(dex.Args["zipFlags"], "-L 0") 1129 aligned := foo.MaybeRule("zipalign").Rule != nil 1130 1131 if uncompressedInDexJar != want { 1132 t.Errorf("want uncompressed in dex %v, got %v", want, uncompressedInDexJar) 1133 } 1134 1135 if aligned != want { 1136 t.Errorf("want aligned %v, got %v", want, aligned) 1137 } 1138 } 1139 1140 for _, tt := range testCases { 1141 t.Run(tt.name, func(t *testing.T) { 1142 t.Run("platform", func(t *testing.T) { 1143 test(t, tt.bp, tt.uncompressedPlatform, false) 1144 }) 1145 t.Run("unbundled", func(t *testing.T) { 1146 test(t, tt.bp, tt.uncompressedUnbundled, true) 1147 }) 1148 }) 1149 } 1150} 1151