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