1// Copyright (C) 2021 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 java 16 17import ( 18 "strings" 19 "testing" 20 21 "android/soong/android" 22 "android/soong/dexpreopt" 23) 24 25// Contains some simple tests for bootclasspath_fragment logic, additional tests can be found in 26// apex/bootclasspath_fragment_test.go as the ART boot image requires modules from the ART apex. 27 28var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers( 29 PrepareForTestWithJavaDefaultModules, 30 dexpreopt.PrepareForTestByEnablingDexpreopt, 31) 32 33func TestBootclasspathFragment_UnknownImageName(t *testing.T) { 34 t.Parallel() 35 prepareForTestWithBootclasspathFragment. 36 ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( 37 `\Qimage_name: unknown image name "unknown", expected "art"\E`)). 38 RunTestWithBp(t, ` 39 bootclasspath_fragment { 40 name: "unknown-bootclasspath-fragment", 41 image_name: "unknown", 42 contents: ["foo"], 43 } 44 45 java_library { 46 name: "foo", 47 srcs: ["foo.java"], 48 installable: true, 49 } 50 `) 51} 52 53func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) { 54 t.Parallel() 55 prepareForTestWithBootclasspathFragment. 56 ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( 57 `\Qimage_name: unknown image name "unknown", expected "art"\E`)). 58 RunTestWithBp(t, ` 59 prebuilt_bootclasspath_fragment { 60 name: "unknown-bootclasspath-fragment", 61 image_name: "unknown", 62 contents: ["foo"], 63 } 64 65 java_import { 66 name: "foo", 67 jars: ["foo.jar"], 68 } 69 `) 70} 71 72func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T) { 73 t.Parallel() 74 android.GroupFixturePreparers( 75 prepareForTestWithBootclasspathFragment, 76 dexpreopt.FixtureSetArtBootJars("platform:foo", "apex:bar"), 77 ). 78 ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( 79 `\QArtApexJars is invalid as it requests a platform variant of "foo"\E`)). 80 RunTestWithBp(t, ` 81 bootclasspath_fragment { 82 name: "bootclasspath-fragment", 83 image_name: "art", 84 contents: ["foo", "bar"], 85 apex_available: [ 86 "apex", 87 ], 88 } 89 90 java_library { 91 name: "foo", 92 srcs: ["foo.java"], 93 installable: true, 94 } 95 96 java_library { 97 name: "bar", 98 srcs: ["bar.java"], 99 installable: true, 100 } 101 `) 102} 103 104func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testing.T) { 105 t.Parallel() 106 android.GroupFixturePreparers( 107 prepareForTestWithBootclasspathFragment, 108 dexpreopt.FixtureSetArtBootJars("apex1:foo", "apex2:bar"), 109 ). 110 ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( 111 `\QArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex "apex1" and "apex2"\E`)). 112 RunTestWithBp(t, ` 113 bootclasspath_fragment { 114 name: "bootclasspath-fragment", 115 image_name: "art", 116 contents: ["foo", "bar"], 117 apex_available: [ 118 "apex1", 119 "apex2", 120 ], 121 } 122 123 java_library { 124 name: "foo", 125 srcs: ["foo.java"], 126 installable: true, 127 } 128 129 java_library { 130 name: "bar", 131 srcs: ["bar.java"], 132 installable: true, 133 } 134 `) 135} 136 137func TestBootclasspathFragment_Coverage(t *testing.T) { 138 t.Parallel() 139 prepareWithBp := android.FixtureWithRootAndroidBp(` 140 bootclasspath_fragment { 141 name: "myfragment", 142 contents: [ 143 "mybootlib", 144 ], 145 api: { 146 stub_libs: [ 147 "mysdklibrary", 148 ], 149 }, 150 coverage: { 151 contents: [ 152 "coveragelib", 153 ], 154 api: { 155 stub_libs: [ 156 "mycoveragestubs", 157 ], 158 }, 159 }, 160 hidden_api: { 161 split_packages: ["*"], 162 }, 163 } 164 165 java_library { 166 name: "mybootlib", 167 srcs: ["Test.java"], 168 system_modules: "none", 169 sdk_version: "none", 170 compile_dex: true, 171 } 172 173 java_library { 174 name: "coveragelib", 175 srcs: ["Test.java"], 176 system_modules: "none", 177 sdk_version: "none", 178 compile_dex: true, 179 } 180 181 java_sdk_library { 182 name: "mysdklibrary", 183 srcs: ["Test.java"], 184 compile_dex: true, 185 public: {enabled: true}, 186 system: {enabled: true}, 187 } 188 189 java_sdk_library { 190 name: "mycoveragestubs", 191 srcs: ["Test.java"], 192 compile_dex: true, 193 public: {enabled: true}, 194 } 195 `) 196 197 checkContents := func(t *testing.T, result *android.TestResult, expected ...string) { 198 module := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule) 199 eval := module.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) 200 android.AssertArrayString(t, "contents property", expected, module.properties.Contents.GetOrDefault(eval, nil)) 201 } 202 203 preparer := android.GroupFixturePreparers( 204 prepareForTestWithBootclasspathFragment, 205 PrepareForTestWithJavaSdkLibraryFiles, 206 FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"), 207 FixtureConfigureApexBootJars("someapex:mybootlib"), 208 prepareWithBp, 209 ) 210 211 t.Run("without coverage", func(t *testing.T) { 212 t.Parallel() 213 result := preparer.RunTest(t) 214 checkContents(t, result, "mybootlib") 215 }) 216 217 t.Run("with coverage", func(t *testing.T) { 218 t.Parallel() 219 result := android.GroupFixturePreparers( 220 prepareForTestWithFrameworkJacocoInstrumentation, 221 preparer, 222 ).RunTest(t) 223 checkContents(t, result, "mybootlib", "coveragelib") 224 }) 225} 226 227func TestBootclasspathFragment_StubLibs(t *testing.T) { 228 result := android.GroupFixturePreparers( 229 prepareForTestWithBootclasspathFragment, 230 PrepareForTestWithJavaSdkLibraryFiles, 231 FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"), 232 FixtureConfigureApexBootJars("someapex:mysdklibrary"), 233 android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"), 234 ).RunTestWithBp(t, ` 235 bootclasspath_fragment { 236 name: "myfragment", 237 contents: ["mysdklibrary"], 238 api: { 239 stub_libs: [ 240 "mystublib", 241 "myothersdklibrary", 242 ], 243 }, 244 core_platform_api: { 245 stub_libs: ["mycoreplatform.stubs"], 246 }, 247 hidden_api: { 248 split_packages: ["*"], 249 }, 250 } 251 252 java_library { 253 name: "mystublib", 254 srcs: ["Test.java"], 255 system_modules: "none", 256 sdk_version: "none", 257 compile_dex: true, 258 } 259 260 java_sdk_library { 261 name: "mysdklibrary", 262 srcs: ["a.java"], 263 shared_library: false, 264 public: {enabled: true}, 265 system: {enabled: true}, 266 } 267 268 java_sdk_library { 269 name: "myothersdklibrary", 270 srcs: ["a.java"], 271 shared_library: false, 272 public: {enabled: true}, 273 } 274 275 java_sdk_library { 276 name: "mycoreplatform", 277 srcs: ["a.java"], 278 shared_library: false, 279 public: {enabled: true}, 280 } 281 `) 282 283 fragment := result.Module("myfragment", "android_common") 284 info, _ := android.OtherModuleProvider(result, fragment, HiddenAPIInfoProvider) 285 286 stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar" 287 288 // Stubs jars for mysdklibrary 289 publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable/android_common/dex/mysdklibrary.stubs.exportable.jar" 290 systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable.system/android_common/dex/mysdklibrary.stubs.exportable.system.jar" 291 292 // Stubs jars for myothersdklibrary 293 otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs.exportable/android_common/dex/myothersdklibrary.stubs.exportable.jar" 294 295 // Check that SdkPublic uses public stubs for all sdk libraries. 296 android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(PublicHiddenAPIScope)) 297 298 // Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary 299 // as it does not provide system stubs. 300 android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(SystemHiddenAPIScope)) 301 302 // Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs 303 // and public stubs for myothersdklibrary as it does not provide test stubs either. 304 android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(TestHiddenAPIScope)) 305 306 // Check that SdkCorePlatform uses public stubs from the mycoreplatform library. 307 corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar" 308 android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(CorePlatformHiddenAPIScope)) 309 310 // Check the widest stubs.. The list contains the widest stub dex jar provided by each module. 311 expectedWidestPaths := []string{ 312 // mycoreplatform's widest API is core platform. 313 corePlatformStubsJar, 314 315 // myothersdklibrary's widest API is public. 316 otherPublicStubsJar, 317 318 // sdklibrary's widest API is system. 319 systemStubsJar, 320 321 // mystublib's only provides one API and so it must be the widest. 322 stubsJar, 323 } 324 325 android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope()) 326} 327 328func TestFromTextWidestApiScope(t *testing.T) { 329 result := android.GroupFixturePreparers( 330 prepareForTestWithBootclasspathFragment, 331 PrepareForTestWithJavaSdkLibraryFiles, 332 android.FixtureModifyConfig(func(config android.Config) { 333 config.SetBuildFromTextStub(true) 334 }), 335 FixtureWithLastReleaseApis("mysdklibrary", "android-non-updatable"), 336 FixtureConfigureApexBootJars("someapex:mysdklibrary"), 337 ).RunTestWithBp(t, ` 338 bootclasspath_fragment { 339 name: "myfragment", 340 contents: ["mysdklibrary"], 341 additional_stubs: [ 342 "android-non-updatable", 343 ], 344 hidden_api: { 345 split_packages: ["*"], 346 }, 347 } 348 java_sdk_library { 349 name: "mysdklibrary", 350 srcs: ["a.java"], 351 shared_library: false, 352 public: {enabled: true}, 353 system: {enabled: true}, 354 } 355 java_sdk_library { 356 name: "android-non-updatable", 357 srcs: ["b.java"], 358 compile_dex: true, 359 public: { 360 enabled: true, 361 }, 362 system: { 363 enabled: true, 364 }, 365 test: { 366 enabled: true, 367 }, 368 module_lib: { 369 enabled: true, 370 }, 371 } 372 `) 373 374 fragment := result.ModuleForTests(t, "myfragment", "android_common") 375 dependencyStubDexFlag := "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.test_module_lib/android_common/dex/android-non-updatable.stubs.test_module_lib.jar" 376 stubFlagsCommand := fragment.Output("modular-hiddenapi/stub-flags.csv").RuleParams.Command 377 android.AssertStringDoesContain(t, 378 "Stub flags generating command does not include the expected dependency stub dex file", 379 stubFlagsCommand, dependencyStubDexFlag) 380} 381 382func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { 383 result := android.GroupFixturePreparers( 384 prepareForTestWithBootclasspathFragment, 385 PrepareForTestWithJavaSdkLibraryFiles, 386 FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"), 387 FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"), 388 android.MockFS{ 389 "my-blocked.txt": nil, 390 "my-max-target-o-low-priority.txt": nil, 391 "my-max-target-p.txt": nil, 392 "my-max-target-q.txt": nil, 393 "my-max-target-r-low-priority.txt": nil, 394 "my-removed.txt": nil, 395 "my-unsupported-packages.txt": nil, 396 "my-unsupported.txt": nil, 397 "my-new-max-target-q.txt": nil, 398 }.AddToFixture(), 399 android.FixtureWithRootAndroidBp(` 400 bootclasspath_fragment { 401 name: "mybootclasspathfragment", 402 apex_available: ["myapex"], 403 contents: ["mybootlib", "mynewlibrary"], 404 hidden_api: { 405 unsupported: [ 406 "my-unsupported.txt", 407 ], 408 removed: [ 409 "my-removed.txt", 410 ], 411 max_target_r_low_priority: [ 412 "my-max-target-r-low-priority.txt", 413 ], 414 max_target_q: [ 415 "my-max-target-q.txt", 416 ], 417 max_target_p: [ 418 "my-max-target-p.txt", 419 ], 420 max_target_o_low_priority: [ 421 "my-max-target-o-low-priority.txt", 422 ], 423 blocked: [ 424 "my-blocked.txt", 425 ], 426 unsupported_packages: [ 427 "my-unsupported-packages.txt", 428 ], 429 split_packages: ["sdklibrary"], 430 package_prefixes: ["sdklibrary.all.mine"], 431 single_packages: ["sdklibrary.mine"], 432 }, 433 } 434 435 java_library { 436 name: "mybootlib", 437 apex_available: ["myapex"], 438 srcs: ["Test.java"], 439 system_modules: "none", 440 sdk_version: "none", 441 min_sdk_version: "1", 442 compile_dex: true, 443 permitted_packages: ["mybootlib"], 444 } 445 446 java_sdk_library { 447 name: "mynewlibrary", 448 apex_available: ["myapex"], 449 srcs: ["Test.java"], 450 min_sdk_version: "10", 451 compile_dex: true, 452 public: {enabled: true}, 453 permitted_packages: ["mysdklibrary"], 454 hidden_api: { 455 max_target_q: [ 456 "my-new-max-target-q.txt", 457 ], 458 split_packages: ["sdklibrary", "newlibrary"], 459 package_prefixes: ["newlibrary.all.mine"], 460 single_packages: ["newlibrary.mine"], 461 }, 462 } 463 `), 464 ).RunTest(t) 465 466 // Make sure that the library exports hidden API properties for use by the bootclasspath_fragment. 467 library := result.Module("mynewlibrary", "android_common") 468 info, _ := android.OtherModuleProvider(result, library, hiddenAPIPropertyInfoProvider) 469 android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages) 470 android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes) 471 android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages) 472 for _, c := range HiddenAPIFlagFileCategories { 473 expectedMaxTargetQPaths := []string(nil) 474 if c.PropertyName() == "max_target_q" { 475 expectedMaxTargetQPaths = []string{"my-new-max-target-q.txt"} 476 } 477 android.AssertPathsRelativeToTopEquals(t, c.PropertyName(), expectedMaxTargetQPaths, info.FlagFilesByCategory[c]) 478 } 479 480 // Make sure that the signature-patterns.csv is passed all the appropriate package properties 481 // from the bootclasspath_fragment and its contents. 482 fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common") 483 rule := fragment.Output("modular-hiddenapi/signature-patterns.csv") 484 expectedCommand := strings.Join([]string{ 485 "--split-package newlibrary", 486 "--split-package sdklibrary", 487 "--package-prefix newlibrary.all.mine", 488 "--package-prefix sdklibrary.all.mine", 489 "--single-package newlibrary.mine", 490 "--single-package sdklibrary", 491 }, " ") 492 android.AssertStringDoesContain(t, "signature patterns command", rule.RuleParams.Command, expectedCommand) 493} 494 495func TestBootclasspathFragment_Test(t *testing.T) { 496 result := android.GroupFixturePreparers( 497 prepareForTestWithBootclasspathFragment, 498 PrepareForTestWithJavaSdkLibraryFiles, 499 FixtureWithLastReleaseApis("mysdklibrary"), 500 ).RunTestWithBp(t, ` 501 bootclasspath_fragment { 502 name: "myfragment", 503 contents: ["mysdklibrary"], 504 hidden_api: { 505 split_packages: [], 506 }, 507 } 508 509 bootclasspath_fragment_test { 510 name: "a_test_fragment", 511 contents: ["mysdklibrary"], 512 hidden_api: { 513 split_packages: [], 514 }, 515 } 516 517 518 java_sdk_library { 519 name: "mysdklibrary", 520 srcs: ["a.java"], 521 shared_library: false, 522 public: {enabled: true}, 523 system: {enabled: true}, 524 } 525 `) 526 527 fragment := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule) 528 android.AssertBoolEquals(t, "not a test fragment", false, fragment.isTestFragment()) 529 530 fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule) 531 android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment()) 532} 533