1// Copyright 2020 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 "reflect" 19 "regexp" 20 "strings" 21 "testing" 22 23 "github.com/google/blueprint/proptools" 24 25 "android/soong/android" 26) 27 28func TestAndroidAppImport(t *testing.T) { 29 ctx, _ := testJava(t, ` 30 android_app_import { 31 name: "foo", 32 apk: "prebuilts/apk/app.apk", 33 certificate: "platform", 34 dex_preopt: { 35 enabled: true, 36 }, 37 } 38 `) 39 40 variant := ctx.ModuleForTests("foo", "android_common") 41 42 // Check dexpreopt outputs. 43 if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil || 44 variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil { 45 t.Errorf("can't find dexpreopt outputs") 46 } 47 48 // Check cert signing flag. 49 signedApk := variant.Output("signed/foo.apk") 50 signingFlag := signedApk.Args["certificates"] 51 expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8" 52 if expected != signingFlag { 53 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) 54 } 55} 56 57func TestAndroidAppImport_NoDexPreopt(t *testing.T) { 58 ctx, _ := testJava(t, ` 59 android_app_import { 60 name: "foo", 61 apk: "prebuilts/apk/app.apk", 62 certificate: "platform", 63 dex_preopt: { 64 enabled: false, 65 }, 66 } 67 `) 68 69 variant := ctx.ModuleForTests("foo", "android_common") 70 71 // Check dexpreopt outputs. They shouldn't exist. 72 if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil || 73 variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil { 74 t.Errorf("dexpreopt shouldn't have run.") 75 } 76} 77 78func TestAndroidAppImport_Presigned(t *testing.T) { 79 ctx, _ := testJava(t, ` 80 android_app_import { 81 name: "foo", 82 apk: "prebuilts/apk/app.apk", 83 presigned: true, 84 dex_preopt: { 85 enabled: true, 86 }, 87 } 88 `) 89 90 variant := ctx.ModuleForTests("foo", "android_common") 91 92 // Check dexpreopt outputs. 93 if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil || 94 variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil { 95 t.Errorf("can't find dexpreopt outputs") 96 } 97 // Make sure signing was skipped and aligning was done. 98 if variant.MaybeOutput("signed/foo.apk").Rule != nil { 99 t.Errorf("signing rule shouldn't be included.") 100 } 101 if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil { 102 t.Errorf("can't find aligning rule") 103 } 104} 105 106func TestAndroidAppImport_SigningLineage(t *testing.T) { 107 ctx, _ := testJava(t, ` 108 android_app_import { 109 name: "foo", 110 apk: "prebuilts/apk/app.apk", 111 certificate: "platform", 112 additional_certificates: [":additional_certificate"], 113 lineage: "lineage.bin", 114 } 115 116 android_app_certificate { 117 name: "additional_certificate", 118 certificate: "cert/additional_cert", 119 } 120 `) 121 122 variant := ctx.ModuleForTests("foo", "android_common") 123 124 signedApk := variant.Output("signed/foo.apk") 125 // Check certificates 126 certificatesFlag := signedApk.Args["certificates"] 127 expected := "build/make/target/product/security/platform.x509.pem " + 128 "build/make/target/product/security/platform.pk8 " + 129 "cert/additional_cert.x509.pem cert/additional_cert.pk8" 130 if expected != certificatesFlag { 131 t.Errorf("Incorrect certificates flags, expected: %q, got: %q", expected, certificatesFlag) 132 } 133 // Check cert signing lineage flag. 134 signingFlag := signedApk.Args["flags"] 135 expected = "--lineage lineage.bin" 136 if expected != signingFlag { 137 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) 138 } 139} 140 141func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { 142 ctx, _ := testJava(t, ` 143 android_app_import { 144 name: "foo", 145 apk: "prebuilts/apk/app.apk", 146 certificate: "platform", 147 lineage: ":lineage_bin", 148 } 149 150 filegroup { 151 name: "lineage_bin", 152 srcs: ["lineage.bin"], 153 } 154 `) 155 156 variant := ctx.ModuleForTests("foo", "android_common") 157 158 signedApk := variant.Output("signed/foo.apk") 159 // Check cert signing lineage flag. 160 signingFlag := signedApk.Args["flags"] 161 expected := "--lineage lineage.bin" 162 if expected != signingFlag { 163 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) 164 } 165} 166 167func TestAndroidAppImport_DefaultDevCert(t *testing.T) { 168 ctx, _ := testJava(t, ` 169 android_app_import { 170 name: "foo", 171 apk: "prebuilts/apk/app.apk", 172 default_dev_cert: true, 173 dex_preopt: { 174 enabled: true, 175 }, 176 } 177 `) 178 179 variant := ctx.ModuleForTests("foo", "android_common") 180 181 // Check dexpreopt outputs. 182 if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil || 183 variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil { 184 t.Errorf("can't find dexpreopt outputs") 185 } 186 187 // Check cert signing flag. 188 signedApk := variant.Output("signed/foo.apk") 189 signingFlag := signedApk.Args["certificates"] 190 expected := "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8" 191 if expected != signingFlag { 192 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) 193 } 194} 195 196func TestAndroidAppImport_DpiVariants(t *testing.T) { 197 bp := ` 198 android_app_import { 199 name: "foo", 200 apk: "prebuilts/apk/app.apk", 201 dpi_variants: { 202 xhdpi: { 203 apk: "prebuilts/apk/app_xhdpi.apk", 204 }, 205 xxhdpi: { 206 apk: "prebuilts/apk/app_xxhdpi.apk", 207 }, 208 }, 209 presigned: true, 210 dex_preopt: { 211 enabled: true, 212 }, 213 } 214 ` 215 testCases := []struct { 216 name string 217 aaptPreferredConfig *string 218 aaptPrebuiltDPI []string 219 expected string 220 }{ 221 { 222 name: "no preferred", 223 aaptPreferredConfig: nil, 224 aaptPrebuiltDPI: []string{}, 225 expected: "verify_uses_libraries/apk/app.apk", 226 }, 227 { 228 name: "AAPTPreferredConfig matches", 229 aaptPreferredConfig: proptools.StringPtr("xhdpi"), 230 aaptPrebuiltDPI: []string{"xxhdpi", "ldpi"}, 231 expected: "verify_uses_libraries/apk/app_xhdpi.apk", 232 }, 233 { 234 name: "AAPTPrebuiltDPI matches", 235 aaptPreferredConfig: proptools.StringPtr("mdpi"), 236 aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"}, 237 expected: "verify_uses_libraries/apk/app_xxhdpi.apk", 238 }, 239 { 240 name: "non-first AAPTPrebuiltDPI matches", 241 aaptPreferredConfig: proptools.StringPtr("mdpi"), 242 aaptPrebuiltDPI: []string{"ldpi", "xhdpi"}, 243 expected: "verify_uses_libraries/apk/app_xhdpi.apk", 244 }, 245 { 246 name: "no matches", 247 aaptPreferredConfig: proptools.StringPtr("mdpi"), 248 aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"}, 249 expected: "verify_uses_libraries/apk/app.apk", 250 }, 251 } 252 253 jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)") 254 for _, test := range testCases { 255 result := android.GroupFixturePreparers( 256 PrepareForTestWithJavaDefaultModules, 257 android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { 258 variables.AAPTPreferredConfig = test.aaptPreferredConfig 259 variables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI 260 }), 261 ).RunTestWithBp(t, bp) 262 263 variant := result.ModuleForTests("foo", "android_common") 264 jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command 265 matches := jniRuleRe.FindStringSubmatch(jniRuleCommand) 266 if len(matches) != 2 { 267 t.Errorf("failed to extract the src apk path from %q", jniRuleCommand) 268 } 269 if strings.HasSuffix(matches[1], test.expected) { 270 t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1]) 271 } 272 } 273} 274 275func TestAndroidAppImport_Filename(t *testing.T) { 276 ctx, _ := testJava(t, ` 277 android_app_import { 278 name: "foo", 279 apk: "prebuilts/apk/app.apk", 280 presigned: true, 281 } 282 283 android_app_import { 284 name: "bar", 285 apk: "prebuilts/apk/app.apk", 286 presigned: true, 287 filename: "bar_sample.apk" 288 } 289 `) 290 291 testCases := []struct { 292 name string 293 expected string 294 }{ 295 { 296 name: "foo", 297 expected: "foo.apk", 298 }, 299 { 300 name: "bar", 301 expected: "bar_sample.apk", 302 }, 303 } 304 305 for _, test := range testCases { 306 variant := ctx.ModuleForTests(test.name, "android_common") 307 if variant.MaybeOutput(test.expected).Rule == nil { 308 t.Errorf("can't find output named %q - all outputs: %v", test.expected, variant.AllOutputs()) 309 } 310 311 a := variant.Module().(*AndroidAppImport) 312 expectedValues := []string{test.expected} 313 actualValues := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_INSTALLED_MODULE_STEM"] 314 if !reflect.DeepEqual(actualValues, expectedValues) { 315 t.Errorf("Incorrect LOCAL_INSTALLED_MODULE_STEM value '%s', expected '%s'", 316 actualValues, expectedValues) 317 } 318 } 319} 320 321func TestAndroidAppImport_ArchVariants(t *testing.T) { 322 // The test config's target arch is ARM64. 323 testCases := []struct { 324 name string 325 bp string 326 expected string 327 }{ 328 { 329 name: "matching arch", 330 bp: ` 331 android_app_import { 332 name: "foo", 333 apk: "prebuilts/apk/app.apk", 334 arch: { 335 arm64: { 336 apk: "prebuilts/apk/app_arm64.apk", 337 }, 338 }, 339 presigned: true, 340 dex_preopt: { 341 enabled: true, 342 }, 343 } 344 `, 345 expected: "verify_uses_libraries/apk/app_arm64.apk", 346 }, 347 { 348 name: "no matching arch", 349 bp: ` 350 android_app_import { 351 name: "foo", 352 apk: "prebuilts/apk/app.apk", 353 arch: { 354 arm: { 355 apk: "prebuilts/apk/app_arm.apk", 356 }, 357 }, 358 presigned: true, 359 dex_preopt: { 360 enabled: true, 361 }, 362 } 363 `, 364 expected: "verify_uses_libraries/apk/app.apk", 365 }, 366 { 367 name: "no matching arch without default", 368 bp: ` 369 android_app_import { 370 name: "foo", 371 arch: { 372 arm: { 373 apk: "prebuilts/apk/app_arm.apk", 374 }, 375 }, 376 presigned: true, 377 dex_preopt: { 378 enabled: true, 379 }, 380 } 381 `, 382 expected: "", 383 }, 384 } 385 386 jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)") 387 for _, test := range testCases { 388 ctx, _ := testJava(t, test.bp) 389 390 variant := ctx.ModuleForTests("foo", "android_common") 391 if test.expected == "" { 392 if variant.Module().Enabled() { 393 t.Error("module should have been disabled, but wasn't") 394 } 395 continue 396 } 397 jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command 398 matches := jniRuleRe.FindStringSubmatch(jniRuleCommand) 399 if len(matches) != 2 { 400 t.Errorf("failed to extract the src apk path from %q", jniRuleCommand) 401 } 402 if strings.HasSuffix(matches[1], test.expected) { 403 t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1]) 404 } 405 } 406} 407 408func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { 409 ctx, _ := testJava(t, ` 410 android_app { 411 name: "foo", 412 srcs: ["a.java"], 413 enabled: false, 414 } 415 416 android_app_import { 417 name: "foo", 418 apk: "prebuilts/apk/app.apk", 419 certificate: "platform", 420 prefer: true, 421 } 422 `) 423 424 variant := ctx.ModuleForTests("prebuilt_foo", "android_common") 425 a := variant.Module().(*AndroidAppImport) 426 // The prebuilt module should still be enabled and active even if the source-based counterpart 427 // is disabled. 428 if !a.prebuilt.UsePrebuilt() { 429 t.Errorf("prebuilt foo module is not active") 430 } 431 if !a.Enabled() { 432 t.Errorf("prebuilt foo module is disabled") 433 } 434} 435 436func TestAndroidAppImport_frameworkRes(t *testing.T) { 437 ctx, _ := testJava(t, ` 438 android_app_import { 439 name: "framework-res", 440 certificate: "platform", 441 apk: "package-res.apk", 442 prefer: true, 443 export_package_resources: true, 444 // Disable dexpreopt and verify_uses_libraries check as the app 445 // contains no Java code to be dexpreopted. 446 enforce_uses_libs: false, 447 dex_preopt: { 448 enabled: false, 449 }, 450 } 451 `) 452 453 mod := ctx.ModuleForTests("prebuilt_framework-res", "android_common").Module() 454 a := mod.(*AndroidAppImport) 455 456 if !a.preprocessed { 457 t.Errorf("prebuilt framework-res is not preprocessed") 458 } 459 460 expectedInstallPath := "out/soong/target/product/test_device/system/framework/framework-res.apk" 461 462 android.AssertPathRelativeToTopEquals(t, "prebuilt framework-res install location", expectedInstallPath, a.dexpreopter.installPath) 463 464 entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] 465 466 expectedPath := "." 467 // From apk property above, in the root of the source tree. 468 expectedPrebuiltModuleFile := "package-res.apk" 469 // Verify that the apk is preprocessed: The export package is the same 470 // as the prebuilt. 471 expectedSoongResourceExportPackage := expectedPrebuiltModuleFile 472 473 actualPath := entries.EntryMap["LOCAL_PATH"] 474 actualPrebuiltModuleFile := entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"] 475 actualSoongResourceExportPackage := entries.EntryMap["LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE"] 476 477 if len(actualPath) != 1 { 478 t.Errorf("LOCAL_PATH incorrect len %d", len(actualPath)) 479 } else if actualPath[0] != expectedPath { 480 t.Errorf("LOCAL_PATH mismatch, actual: %s, expected: %s", actualPath[0], expectedPath) 481 } 482 483 if len(actualPrebuiltModuleFile) != 1 { 484 t.Errorf("LOCAL_PREBUILT_MODULE_FILE incorrect len %d", len(actualPrebuiltModuleFile)) 485 } else if actualPrebuiltModuleFile[0] != expectedPrebuiltModuleFile { 486 t.Errorf("LOCAL_PREBUILT_MODULE_FILE mismatch, actual: %s, expected: %s", actualPrebuiltModuleFile[0], expectedPrebuiltModuleFile) 487 } 488 489 if len(actualSoongResourceExportPackage) != 1 { 490 t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE incorrect len %d", len(actualSoongResourceExportPackage)) 491 } else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage { 492 t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage) 493 } 494} 495 496func TestAndroidTestImport(t *testing.T) { 497 ctx, _ := testJava(t, ` 498 android_test_import { 499 name: "foo", 500 apk: "prebuilts/apk/app.apk", 501 presigned: true, 502 data: [ 503 "testdata/data", 504 ], 505 } 506 `) 507 508 test := ctx.ModuleForTests("foo", "android_common").Module().(*AndroidTestImport) 509 510 // Check android mks. 511 entries := android.AndroidMkEntriesForTest(t, ctx, test)[0] 512 expected := []string{"tests"} 513 actual := entries.EntryMap["LOCAL_MODULE_TAGS"] 514 if !reflect.DeepEqual(expected, actual) { 515 t.Errorf("Unexpected module tags - expected: %q, actual: %q", expected, actual) 516 } 517 expected = []string{"testdata/data:testdata/data"} 518 actual = entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"] 519 if !reflect.DeepEqual(expected, actual) { 520 t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual) 521 } 522} 523 524func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) { 525 ctx, _ := testJava(t, ` 526 android_test_import { 527 name: "foo", 528 apk: "prebuilts/apk/app.apk", 529 certificate: "cert/new_cert", 530 data: [ 531 "testdata/data", 532 ], 533 } 534 535 android_test_import { 536 name: "foo_presigned", 537 apk: "prebuilts/apk/app.apk", 538 presigned: true, 539 data: [ 540 "testdata/data", 541 ], 542 } 543 `) 544 545 variant := ctx.ModuleForTests("foo", "android_common") 546 jniRule := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command 547 if !strings.HasPrefix(jniRule, "if (zipinfo") { 548 t.Errorf("Unexpected JNI uncompress rule command: " + jniRule) 549 } 550 551 variant = ctx.ModuleForTests("foo_presigned", "android_common") 552 jniRule = variant.Output("jnis-uncompressed/foo_presigned.apk").BuildParams.Rule.String() 553 if jniRule != android.Cp.String() { 554 t.Errorf("Unexpected JNI uncompress rule: " + jniRule) 555 } 556 if variant.MaybeOutput("zip-aligned/foo_presigned.apk").Rule == nil { 557 t.Errorf("Presigned test apk should be aligned") 558 } 559} 560 561func TestAndroidTestImport_Preprocessed(t *testing.T) { 562 ctx, _ := testJava(t, ` 563 android_test_import { 564 name: "foo", 565 apk: "prebuilts/apk/app.apk", 566 presigned: true, 567 preprocessed: true, 568 } 569 570 android_test_import { 571 name: "foo_cert", 572 apk: "prebuilts/apk/app.apk", 573 certificate: "cert/new_cert", 574 preprocessed: true, 575 } 576 `) 577 578 testModules := []string{"foo", "foo_cert"} 579 for _, m := range testModules { 580 apkName := m + ".apk" 581 variant := ctx.ModuleForTests(m, "android_common") 582 jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String() 583 if jniRule != android.Cp.String() { 584 t.Errorf("Unexpected JNI uncompress rule: " + jniRule) 585 } 586 587 // Make sure signing and aligning were skipped. 588 if variant.MaybeOutput("signed/"+apkName).Rule != nil { 589 t.Errorf("signing rule shouldn't be included for preprocessed.") 590 } 591 if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil { 592 t.Errorf("aligning rule shouldn't be for preprocessed") 593 } 594 } 595} 596