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 eval := module.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) 195 android.AssertArrayString(t, "contents property", expected, module.properties.Contents.GetOrDefault(eval, nil)) 196 } 197 198 preparer := android.GroupFixturePreparers( 199 prepareForTestWithBootclasspathFragment, 200 PrepareForTestWithJavaSdkLibraryFiles, 201 FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"), 202 FixtureConfigureApexBootJars("someapex:mybootlib"), 203 prepareWithBp, 204 ) 205 206 t.Run("without coverage", func(t *testing.T) { 207 result := preparer.RunTest(t) 208 checkContents(t, result, "mybootlib") 209 }) 210 211 t.Run("with coverage", func(t *testing.T) { 212 result := android.GroupFixturePreparers( 213 prepareForTestWithFrameworkJacocoInstrumentation, 214 preparer, 215 ).RunTest(t) 216 checkContents(t, result, "mybootlib", "coveragelib") 217 }) 218} 219 220func TestBootclasspathFragment_StubLibs(t *testing.T) { 221 result := android.GroupFixturePreparers( 222 prepareForTestWithBootclasspathFragment, 223 PrepareForTestWithJavaSdkLibraryFiles, 224 FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"), 225 FixtureConfigureApexBootJars("someapex:mysdklibrary"), 226 android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"), 227 ).RunTestWithBp(t, ` 228 bootclasspath_fragment { 229 name: "myfragment", 230 contents: ["mysdklibrary"], 231 api: { 232 stub_libs: [ 233 "mystublib", 234 "myothersdklibrary", 235 ], 236 }, 237 core_platform_api: { 238 stub_libs: ["mycoreplatform.stubs"], 239 }, 240 hidden_api: { 241 split_packages: ["*"], 242 }, 243 } 244 245 java_library { 246 name: "mystublib", 247 srcs: ["Test.java"], 248 system_modules: "none", 249 sdk_version: "none", 250 compile_dex: true, 251 } 252 253 java_sdk_library { 254 name: "mysdklibrary", 255 srcs: ["a.java"], 256 shared_library: false, 257 public: {enabled: true}, 258 system: {enabled: true}, 259 } 260 261 java_sdk_library { 262 name: "myothersdklibrary", 263 srcs: ["a.java"], 264 shared_library: false, 265 public: {enabled: true}, 266 } 267 268 java_sdk_library { 269 name: "mycoreplatform", 270 srcs: ["a.java"], 271 shared_library: false, 272 public: {enabled: true}, 273 } 274 `) 275 276 fragment := result.Module("myfragment", "android_common") 277 info, _ := android.OtherModuleProvider(result, fragment, HiddenAPIInfoProvider) 278 279 stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar" 280 281 // Stubs jars for mysdklibrary 282 publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable/android_common/dex/mysdklibrary.stubs.exportable.jar" 283 systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable.system/android_common/dex/mysdklibrary.stubs.exportable.system.jar" 284 285 // Stubs jars for myothersdklibrary 286 otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs.exportable/android_common/dex/myothersdklibrary.stubs.exportable.jar" 287 288 // Check that SdkPublic uses public stubs for all sdk libraries. 289 android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(PublicHiddenAPIScope)) 290 291 // Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary 292 // as it does not provide system stubs. 293 android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(SystemHiddenAPIScope)) 294 295 // Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs 296 // and public stubs for myothersdklibrary as it does not provide test stubs either. 297 android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(TestHiddenAPIScope)) 298 299 // Check that SdkCorePlatform uses public stubs from the mycoreplatform library. 300 corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar" 301 android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(CorePlatformHiddenAPIScope)) 302 303 // Check the widest stubs.. The list contains the widest stub dex jar provided by each module. 304 expectedWidestPaths := []string{ 305 // mycoreplatform's widest API is core platform. 306 corePlatformStubsJar, 307 308 // myothersdklibrary's widest API is public. 309 otherPublicStubsJar, 310 311 // sdklibrary's widest API is system. 312 systemStubsJar, 313 314 // mystublib's only provides one API and so it must be the widest. 315 stubsJar, 316 } 317 318 android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope()) 319} 320 321func TestFromTextWidestApiScope(t *testing.T) { 322 result := android.GroupFixturePreparers( 323 prepareForTestWithBootclasspathFragment, 324 PrepareForTestWithJavaSdkLibraryFiles, 325 android.FixtureModifyConfig(func(config android.Config) { 326 config.SetBuildFromTextStub(true) 327 }), 328 FixtureWithLastReleaseApis("mysdklibrary", "android-non-updatable"), 329 FixtureConfigureApexBootJars("someapex:mysdklibrary"), 330 ).RunTestWithBp(t, ` 331 bootclasspath_fragment { 332 name: "myfragment", 333 contents: ["mysdklibrary"], 334 additional_stubs: [ 335 "android-non-updatable", 336 ], 337 hidden_api: { 338 split_packages: ["*"], 339 }, 340 } 341 java_sdk_library { 342 name: "mysdklibrary", 343 srcs: ["a.java"], 344 shared_library: false, 345 public: {enabled: true}, 346 system: {enabled: true}, 347 } 348 java_sdk_library { 349 name: "android-non-updatable", 350 srcs: ["b.java"], 351 compile_dex: true, 352 public: { 353 enabled: true, 354 }, 355 system: { 356 enabled: true, 357 }, 358 test: { 359 enabled: true, 360 }, 361 module_lib: { 362 enabled: true, 363 }, 364 } 365 `) 366 367 fragment := result.ModuleForTests("myfragment", "android_common") 368 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" 369 stubFlagsCommand := fragment.Output("modular-hiddenapi/stub-flags.csv").RuleParams.Command 370 android.AssertStringDoesContain(t, 371 "Stub flags generating command does not include the expected dependency stub dex file", 372 stubFlagsCommand, dependencyStubDexFlag) 373} 374 375func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { 376 result := android.GroupFixturePreparers( 377 prepareForTestWithBootclasspathFragment, 378 PrepareForTestWithJavaSdkLibraryFiles, 379 FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"), 380 FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"), 381 android.MockFS{ 382 "my-blocked.txt": nil, 383 "my-max-target-o-low-priority.txt": nil, 384 "my-max-target-p.txt": nil, 385 "my-max-target-q.txt": nil, 386 "my-max-target-r-low-priority.txt": nil, 387 "my-removed.txt": nil, 388 "my-unsupported-packages.txt": nil, 389 "my-unsupported.txt": nil, 390 "my-new-max-target-q.txt": nil, 391 }.AddToFixture(), 392 android.FixtureWithRootAndroidBp(` 393 bootclasspath_fragment { 394 name: "mybootclasspathfragment", 395 apex_available: ["myapex"], 396 contents: ["mybootlib", "mynewlibrary"], 397 hidden_api: { 398 unsupported: [ 399 "my-unsupported.txt", 400 ], 401 removed: [ 402 "my-removed.txt", 403 ], 404 max_target_r_low_priority: [ 405 "my-max-target-r-low-priority.txt", 406 ], 407 max_target_q: [ 408 "my-max-target-q.txt", 409 ], 410 max_target_p: [ 411 "my-max-target-p.txt", 412 ], 413 max_target_o_low_priority: [ 414 "my-max-target-o-low-priority.txt", 415 ], 416 blocked: [ 417 "my-blocked.txt", 418 ], 419 unsupported_packages: [ 420 "my-unsupported-packages.txt", 421 ], 422 split_packages: ["sdklibrary"], 423 package_prefixes: ["sdklibrary.all.mine"], 424 single_packages: ["sdklibrary.mine"], 425 }, 426 } 427 428 java_library { 429 name: "mybootlib", 430 apex_available: ["myapex"], 431 srcs: ["Test.java"], 432 system_modules: "none", 433 sdk_version: "none", 434 min_sdk_version: "1", 435 compile_dex: true, 436 permitted_packages: ["mybootlib"], 437 } 438 439 java_sdk_library { 440 name: "mynewlibrary", 441 apex_available: ["myapex"], 442 srcs: ["Test.java"], 443 min_sdk_version: "10", 444 compile_dex: true, 445 public: {enabled: true}, 446 permitted_packages: ["mysdklibrary"], 447 hidden_api: { 448 max_target_q: [ 449 "my-new-max-target-q.txt", 450 ], 451 split_packages: ["sdklibrary", "newlibrary"], 452 package_prefixes: ["newlibrary.all.mine"], 453 single_packages: ["newlibrary.mine"], 454 }, 455 } 456 `), 457 ).RunTest(t) 458 459 // Make sure that the library exports hidden API properties for use by the bootclasspath_fragment. 460 library := result.Module("mynewlibrary", "android_common") 461 info, _ := android.OtherModuleProvider(result, library, hiddenAPIPropertyInfoProvider) 462 android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages) 463 android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes) 464 android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages) 465 for _, c := range HiddenAPIFlagFileCategories { 466 expectedMaxTargetQPaths := []string(nil) 467 if c.PropertyName() == "max_target_q" { 468 expectedMaxTargetQPaths = []string{"my-new-max-target-q.txt"} 469 } 470 android.AssertPathsRelativeToTopEquals(t, c.PropertyName(), expectedMaxTargetQPaths, info.FlagFilesByCategory[c]) 471 } 472 473 // Make sure that the signature-patterns.csv is passed all the appropriate package properties 474 // from the bootclasspath_fragment and its contents. 475 fragment := result.ModuleForTests("mybootclasspathfragment", "android_common") 476 rule := fragment.Output("modular-hiddenapi/signature-patterns.csv") 477 expectedCommand := strings.Join([]string{ 478 "--split-package newlibrary", 479 "--split-package sdklibrary", 480 "--package-prefix newlibrary.all.mine", 481 "--package-prefix sdklibrary.all.mine", 482 "--single-package newlibrary.mine", 483 "--single-package sdklibrary", 484 }, " ") 485 android.AssertStringDoesContain(t, "signature patterns command", rule.RuleParams.Command, expectedCommand) 486} 487 488func TestBootclasspathFragment_Test(t *testing.T) { 489 result := android.GroupFixturePreparers( 490 prepareForTestWithBootclasspathFragment, 491 PrepareForTestWithJavaSdkLibraryFiles, 492 FixtureWithLastReleaseApis("mysdklibrary"), 493 ).RunTestWithBp(t, ` 494 bootclasspath_fragment { 495 name: "myfragment", 496 contents: ["mysdklibrary"], 497 hidden_api: { 498 split_packages: [], 499 }, 500 } 501 502 bootclasspath_fragment_test { 503 name: "a_test_fragment", 504 contents: ["mysdklibrary"], 505 hidden_api: { 506 split_packages: [], 507 }, 508 } 509 510 511 java_sdk_library { 512 name: "mysdklibrary", 513 srcs: ["a.java"], 514 shared_library: false, 515 public: {enabled: true}, 516 system: {enabled: true}, 517 } 518 `) 519 520 fragment := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule) 521 android.AssertBoolEquals(t, "not a test fragment", false, fragment.isTestFragment()) 522 523 fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule) 524 android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment()) 525} 526