1// Copyright 2019 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 apex 16 17import ( 18 "fmt" 19 "path/filepath" 20 "sort" 21 "testing" 22 23 "android/soong/android" 24 "android/soong/java" 25) 26 27func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOutputs []string, preferPrebuilt bool) { 28 bp := ` 29 // Platform. 30 31 java_sdk_library { 32 name: "foo", 33 srcs: ["a.java"], 34 api_packages: ["foo"], 35 } 36 37 java_library { 38 name: "bar", 39 srcs: ["b.java"], 40 installable: true, 41 system_ext_specific: true, 42 } 43 44 dex_import { 45 name: "baz", 46 jars: ["a.jar"], 47 } 48 49 platform_bootclasspath { 50 name: "platform-bootclasspath", 51 fragments: [ 52 { 53 apex: "com.android.art", 54 module: "art-bootclasspath-fragment", 55 }, 56 ], 57 } 58 59 // Source ART APEX. 60 61 java_library { 62 name: "core-oj", 63 srcs: ["core-oj.java"], 64 installable: true, 65 apex_available: [ 66 "com.android.art", 67 ], 68 } 69 70 bootclasspath_fragment { 71 name: "art-bootclasspath-fragment", 72 image_name: "art", 73 contents: ["core-oj"], 74 apex_available: [ 75 "com.android.art", 76 ], 77 hidden_api: { 78 split_packages: ["*"], 79 }, 80 } 81 82 apex_key { 83 name: "com.android.art.key", 84 public_key: "com.android.art.avbpubkey", 85 private_key: "com.android.art.pem", 86 } 87 88 apex { 89 name: "com.android.art", 90 key: "com.android.art.key", 91 bootclasspath_fragments: ["art-bootclasspath-fragment"], 92 updatable: false, 93 } 94 95 // Prebuilt ART APEX. 96 97 java_import { 98 name: "core-oj", 99 prefer: %[1]t, 100 jars: ["core-oj.jar"], 101 apex_available: [ 102 "com.android.art", 103 ], 104 } 105 106 prebuilt_bootclasspath_fragment { 107 name: "art-bootclasspath-fragment", 108 prefer: %[1]t, 109 image_name: "art", 110 contents: ["core-oj"], 111 hidden_api: { 112 annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", 113 metadata: "my-bootclasspath-fragment/metadata.csv", 114 index: "my-bootclasspath-fragment/index.csv", 115 stub_flags: "my-bootclasspath-fragment/stub-flags.csv", 116 all_flags: "my-bootclasspath-fragment/all-flags.csv", 117 }, 118 apex_available: [ 119 "com.android.art", 120 ], 121 } 122 123 prebuilt_apex { 124 name: "com.android.art", 125 prefer: %[1]t, 126 apex_name: "com.android.art", 127 src: "com.android.art-arm.apex", 128 exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], 129 } 130 131 apex_contributions { 132 name: "prebuilt_art_contributions", 133 contents: ["prebuilt_com.android.art"], 134 api_domain: "com.android.art", 135 } 136 ` 137 138 fixture := android.GroupFixturePreparers( 139 java.PrepareForTestWithDexpreopt, 140 java.PrepareForTestWithJavaSdkLibraryFiles, 141 java.FixtureWithLastReleaseApis("foo"), 142 java.FixtureConfigureBootJars("com.android.art:core-oj", "platform:foo", "system_ext:bar", "platform:baz"), 143 PrepareForTestWithApexBuildComponents, 144 prepareForTestWithArtApex, 145 ) 146 if preferPrebuilt { 147 fixture = android.GroupFixturePreparers( 148 fixture, 149 android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "prebuilt_art_contributions"), 150 ) 151 } 152 result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt)) 153 154 dexBootJars := result.ModuleForTests("dex_bootjars", "android_common") 155 rule := dexBootJars.Output(ruleFile) 156 157 inputs := rule.Implicits.Strings() 158 sort.Strings(inputs) 159 sort.Strings(expectedInputs) 160 161 outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Strings() 162 sort.Strings(outputs) 163 sort.Strings(expectedOutputs) 164 165 android.AssertStringPathsRelativeToTopEquals(t, "inputs", result.Config, expectedInputs, inputs) 166 167 android.AssertStringPathsRelativeToTopEquals(t, "outputs", result.Config, expectedOutputs, outputs) 168} 169 170func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) { 171 t.Parallel() 172 ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art" 173 174 expectedInputs := []string{ 175 "out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar", 176 "out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar", 177 "out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar", 178 "out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar", 179 "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof", 180 "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", 181 "out/soong/dexpreopt/uffd_gc_flag.txt", 182 } 183 184 expectedOutputs := []string{ 185 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.invocation", 186 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art", 187 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.art", 188 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.art", 189 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.art", 190 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat", 191 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.oat", 192 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.oat", 193 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.oat", 194 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex", 195 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.vdex", 196 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.vdex", 197 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.vdex", 198 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot.oat", 199 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat", 200 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat", 201 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat", 202 } 203 204 testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, false) 205} 206 207// The only difference is that the ART profile should be deapexed from the prebuilt APEX. Other 208// inputs and outputs should be the same as above. 209func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) { 210 t.Parallel() 211 ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art" 212 213 expectedInputs := []string{ 214 "out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar", 215 "out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar", 216 "out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar", 217 "out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar", 218 "out/soong/.intermediates/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof", 219 "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", 220 "out/soong/dexpreopt/uffd_gc_flag.txt", 221 } 222 223 expectedOutputs := []string{ 224 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.invocation", 225 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art", 226 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.art", 227 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.art", 228 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.art", 229 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat", 230 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.oat", 231 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.oat", 232 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.oat", 233 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex", 234 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-foo.vdex", 235 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-bar.vdex", 236 "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-baz.vdex", 237 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot.oat", 238 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat", 239 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat", 240 "out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat", 241 } 242 243 testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, true) 244} 245 246// Changes to the boot.zip structure may break the ART APK scanner. 247func TestDexpreoptBootZip(t *testing.T) { 248 t.Parallel() 249 ruleFile := "boot.zip" 250 251 ctx := android.PathContextForTesting(android.TestArchConfig("", nil, "", nil)) 252 expectedInputs := []string{} 253 for _, target := range ctx.Config().Targets[android.Android] { 254 for _, ext := range []string{".art", ".oat", ".vdex"} { 255 for _, suffix := range []string{"", "-foo", "-bar", "-baz"} { 256 expectedInputs = append(expectedInputs, 257 filepath.Join( 258 "out/soong/dexpreopt_arm64/dex_bootjars", 259 target.Os.String(), 260 "system/framework", 261 target.Arch.ArchType.String(), 262 "boot"+suffix+ext)) 263 } 264 } 265 } 266 267 expectedOutputs := []string{ 268 "out/soong/dexpreopt_arm64/dex_bootjars/boot.zip", 269 } 270 271 testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, false) 272} 273 274// Multiple ART apexes might exist in the tree. 275// The profile should correspond to the apex selected using release build flags 276func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) { 277 t.Parallel() 278 ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art" 279 bp := ` 280 // Platform. 281 282 platform_bootclasspath { 283 name: "platform-bootclasspath", 284 fragments: [ 285 { 286 apex: "com.android.art", 287 module: "art-bootclasspath-fragment", 288 }, 289 ], 290 } 291 292 // Source ART APEX. 293 294 java_library { 295 name: "core-oj", 296 srcs: ["core-oj.java"], 297 installable: true, 298 apex_available: [ 299 "com.android.art", 300 ], 301 } 302 303 bootclasspath_fragment { 304 name: "art-bootclasspath-fragment", 305 image_name: "art", 306 contents: ["core-oj"], 307 apex_available: [ 308 "com.android.art", 309 ], 310 hidden_api: { 311 split_packages: ["*"], 312 }, 313 } 314 315 apex_key { 316 name: "com.android.art.key", 317 public_key: "com.android.art.avbpubkey", 318 private_key: "com.android.art.pem", 319 } 320 321 apex { 322 name: "com.android.art", 323 key: "com.android.art.key", 324 bootclasspath_fragments: ["art-bootclasspath-fragment"], 325 updatable: false, 326 } 327 328 // Prebuilt ART APEX. 329 330 java_import { 331 name: "core-oj", 332 jars: ["core-oj.jar"], 333 apex_available: [ 334 "com.android.art", 335 ], 336 } 337 338 prebuilt_bootclasspath_fragment { 339 name: "art-bootclasspath-fragment", 340 image_name: "art", 341 contents: ["core-oj"], 342 hidden_api: { 343 annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", 344 metadata: "my-bootclasspath-fragment/metadata.csv", 345 index: "my-bootclasspath-fragment/index.csv", 346 stub_flags: "my-bootclasspath-fragment/stub-flags.csv", 347 all_flags: "my-bootclasspath-fragment/all-flags.csv", 348 }, 349 apex_available: [ 350 "com.android.art", 351 ], 352 } 353 354 prebuilt_apex { 355 name: "com.android.art", 356 apex_name: "com.android.art", 357 src: "com.android.art-arm.apex", 358 exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], 359 } 360 361 // Another Prebuilt ART APEX 362 prebuilt_apex { 363 name: "com.android.art.v2", 364 apex_name: "com.android.art", // Used to determine the API domain 365 src: "com.android.art-arm.apex", 366 exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], 367 } 368 369 // APEX contribution modules 370 371 apex_contributions { 372 name: "art.source.contributions", 373 api_domain: "com.android.art", 374 contents: ["com.android.art"], 375 } 376 377 apex_contributions { 378 name: "art.prebuilt.contributions", 379 api_domain: "com.android.art", 380 contents: ["prebuilt_com.android.art"], 381 } 382 383 apex_contributions { 384 name: "art.prebuilt.v2.contributions", 385 api_domain: "com.android.art", 386 contents: ["com.android.art.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator 387 } 388 389 ` 390 391 testCases := []struct { 392 desc string 393 selectedArtApexContributions string 394 expectedProfile string 395 }{ 396 { 397 desc: "Source apex com.android.art is selected, profile should come from source java library", 398 selectedArtApexContributions: "art.source.contributions", 399 expectedProfile: "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof", 400 }, 401 { 402 desc: "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt", 403 selectedArtApexContributions: "art.prebuilt.contributions", 404 expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof", 405 }, 406 { 407 desc: "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt", 408 selectedArtApexContributions: "art.prebuilt.v2.contributions", 409 expectedProfile: "out/soong/.intermediates/com.android.art.v2/android_common_com.android.art/deapexer/etc/boot-image.prof", 410 }, 411 } 412 for _, tc := range testCases { 413 result := android.GroupFixturePreparers( 414 java.PrepareForTestWithDexpreopt, 415 java.PrepareForTestWithJavaSdkLibraryFiles, 416 java.FixtureConfigureBootJars("com.android.art:core-oj"), 417 PrepareForTestWithApexBuildComponents, 418 prepareForTestWithArtApex, 419 android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", tc.selectedArtApexContributions), 420 ).RunTestWithBp(t, bp) 421 422 dexBootJars := result.ModuleForTests("dex_bootjars", "android_common") 423 rule := dexBootJars.Output(ruleFile) 424 425 inputs := rule.Implicits.Strings() 426 android.AssertStringListContains(t, tc.desc, inputs, tc.expectedProfile) 427 } 428} 429 430// Check that dexpreopt works with Google mainline prebuilts even in workspaces where source is missing 431func TestDexpreoptWithMainlinePrebuiltNoSource(t *testing.T) { 432 t.Parallel() 433 bp := ` 434 // Platform. 435 436 platform_bootclasspath { 437 name: "platform-bootclasspath", 438 fragments: [ 439 { 440 apex: "com.android.art", 441 module: "art-bootclasspath-fragment", 442 }, 443 ], 444 } 445 446 // Source AOSP ART apex 447 java_library { 448 name: "core-oj", 449 srcs: ["core-oj.java"], 450 installable: true, 451 apex_available: [ 452 "com.android.art", 453 ], 454 } 455 456 bootclasspath_fragment { 457 name: "art-bootclasspath-fragment", 458 image_name: "art", 459 contents: ["core-oj"], 460 apex_available: [ 461 "com.android.art", 462 ], 463 hidden_api: { 464 split_packages: ["*"], 465 }, 466 } 467 468 apex_key { 469 name: "com.android.art.key", 470 public_key: "com.android.art.avbpubkey", 471 private_key: "com.android.art.pem", 472 } 473 474 apex { 475 name: "com.android.art", 476 key: "com.android.art.key", 477 bootclasspath_fragments: ["art-bootclasspath-fragment"], 478 updatable: false, 479 } 480 481 482 // Prebuilt Google ART APEX. 483 484 java_import { 485 name: "core-oj", 486 jars: ["core-oj.jar"], 487 apex_available: [ 488 "com.android.art", 489 ], 490 } 491 492 prebuilt_bootclasspath_fragment { 493 name: "art-bootclasspath-fragment", 494 image_name: "art", 495 contents: ["core-oj"], 496 hidden_api: { 497 annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv", 498 metadata: "my-bootclasspath-fragment/metadata.csv", 499 index: "my-bootclasspath-fragment/index.csv", 500 stub_flags: "my-bootclasspath-fragment/stub-flags.csv", 501 all_flags: "my-bootclasspath-fragment/all-flags.csv", 502 }, 503 apex_available: [ 504 "com.android.art", 505 ], 506 } 507 508 prebuilt_apex { 509 name: "com.google.android.art", 510 apex_name: "com.android.art", 511 src: "com.android.art-arm.apex", 512 exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], 513 } 514 515 apex_contributions { 516 name: "art.prebuilt.contributions", 517 api_domain: "com.android.art", 518 contents: ["prebuilt_com.google.android.art"], 519 } 520 ` 521 res := android.GroupFixturePreparers( 522 java.PrepareForTestWithDexpreopt, 523 java.PrepareForTestWithJavaSdkLibraryFiles, 524 java.FixtureConfigureBootJars("com.android.art:core-oj"), 525 PrepareForTestWithApexBuildComponents, 526 prepareForTestWithArtApex, 527 android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "art.prebuilt.contributions"), 528 ).RunTestWithBp(t, bp) 529 if !java.CheckModuleHasDependency(t, res.TestContext, "dex_bootjars", "android_common", "prebuilt_com.google.android.art") { 530 t.Errorf("Expected dexpreopt to use prebuilt apex") 531 } 532} 533