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