1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <regex> 18 #include <sstream> 19 #include <string> 20 #include <vector> 21 22 #include <sys/wait.h> 23 #include <unistd.h> 24 25 #include <android-base/logging.h> 26 #include <android-base/stringprintf.h> 27 28 #include "common_runtime_test.h" 29 30 #include "base/macros.h" 31 #include "base/mutex-inl.h" 32 #include "base/utils.h" 33 #include "dex/art_dex_file_loader.h" 34 #include "dex/base64_test_util.h" 35 #include "dex/bytecode_utils.h" 36 #include "dex/code_item_accessors-inl.h" 37 #include "dex/dex_file-inl.h" 38 #include "dex/dex_file_loader.h" 39 #include "dex2oat_environment_test.h" 40 #include "dex2oat_return_codes.h" 41 #include "jit/profile_compilation_info.h" 42 #include "oat.h" 43 #include "oat_file.h" 44 #include "vdex_file.h" 45 #include "ziparchive/zip_writer.h" 46 47 namespace art { 48 49 static constexpr size_t kMaxMethodIds = 65535; 50 static constexpr bool kDebugArgs = false; 51 static const char* kDisableCompactDex = "--compact-dex-level=none"; 52 53 using android::base::StringPrintf; 54 55 class Dex2oatTest : public Dex2oatEnvironmentTest { 56 public: 57 virtual void TearDown() OVERRIDE { 58 Dex2oatEnvironmentTest::TearDown(); 59 60 output_ = ""; 61 error_msg_ = ""; 62 success_ = false; 63 } 64 65 protected: 66 int GenerateOdexForTestWithStatus(const std::vector<std::string>& dex_locations, 67 const std::string& odex_location, 68 CompilerFilter::Filter filter, 69 std::string* error_msg, 70 const std::vector<std::string>& extra_args = {}, 71 bool use_fd = false) { 72 std::unique_ptr<File> oat_file; 73 std::vector<std::string> args; 74 // Add dex file args. 75 for (const std::string& dex_location : dex_locations) { 76 args.push_back("--dex-file=" + dex_location); 77 } 78 if (use_fd) { 79 oat_file.reset(OS::CreateEmptyFile(odex_location.c_str())); 80 CHECK(oat_file != nullptr) << odex_location; 81 args.push_back("--oat-fd=" + std::to_string(oat_file->Fd())); 82 args.push_back("--oat-location=" + odex_location); 83 } else { 84 args.push_back("--oat-file=" + odex_location); 85 } 86 args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter)); 87 args.push_back("--runtime-arg"); 88 args.push_back("-Xnorelocate"); 89 90 args.insert(args.end(), extra_args.begin(), extra_args.end()); 91 92 int status = Dex2Oat(args, error_msg); 93 if (oat_file != nullptr) { 94 CHECK_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file"; 95 } 96 return status; 97 } 98 99 void GenerateOdexForTest( 100 const std::string& dex_location, 101 const std::string& odex_location, 102 CompilerFilter::Filter filter, 103 const std::vector<std::string>& extra_args = {}, 104 bool expect_success = true, 105 bool use_fd = false) { 106 GenerateOdexForTest(dex_location, 107 odex_location, 108 filter, 109 extra_args, 110 expect_success, 111 use_fd, 112 [](const OatFile&) {}); 113 } 114 115 bool test_accepts_odex_file_on_failure = false; 116 117 template <typename T> 118 void GenerateOdexForTest( 119 const std::string& dex_location, 120 const std::string& odex_location, 121 CompilerFilter::Filter filter, 122 const std::vector<std::string>& extra_args, 123 bool expect_success, 124 bool use_fd, 125 T check_oat) { 126 std::string error_msg; 127 int status = GenerateOdexForTestWithStatus({dex_location}, 128 odex_location, 129 filter, 130 &error_msg, 131 extra_args, 132 use_fd); 133 bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0); 134 if (expect_success) { 135 ASSERT_TRUE(success) << error_msg << std::endl << output_; 136 137 // Verify the odex file was generated as expected. 138 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 139 odex_location.c_str(), 140 odex_location.c_str(), 141 nullptr, 142 nullptr, 143 false, 144 /*low_4gb*/false, 145 dex_location.c_str(), 146 &error_msg)); 147 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; 148 149 CheckFilter(filter, odex_file->GetCompilerFilter()); 150 check_oat(*(odex_file.get())); 151 } else { 152 ASSERT_FALSE(success) << output_; 153 154 error_msg_ = error_msg; 155 156 if (!test_accepts_odex_file_on_failure) { 157 // Verify there's no loadable odex file. 158 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 159 odex_location.c_str(), 160 odex_location.c_str(), 161 nullptr, 162 nullptr, 163 false, 164 /*low_4gb*/false, 165 dex_location.c_str(), 166 &error_msg)); 167 ASSERT_TRUE(odex_file.get() == nullptr); 168 } 169 } 170 } 171 172 // Check the input compiler filter against the generated oat file's filter. May be overridden 173 // in subclasses when equality is not expected. 174 virtual void CheckFilter(CompilerFilter::Filter expected, CompilerFilter::Filter actual) { 175 EXPECT_EQ(expected, actual); 176 } 177 178 int Dex2Oat(const std::vector<std::string>& dex2oat_args, std::string* error_msg) { 179 Runtime* runtime = Runtime::Current(); 180 181 const std::vector<gc::space::ImageSpace*>& image_spaces = 182 runtime->GetHeap()->GetBootImageSpaces(); 183 if (image_spaces.empty()) { 184 *error_msg = "No image location found for Dex2Oat."; 185 return false; 186 } 187 std::string image_location = image_spaces[0]->GetImageLocation(); 188 189 std::vector<std::string> argv; 190 argv.push_back(runtime->GetCompilerExecutable()); 191 192 if (runtime->IsJavaDebuggable()) { 193 argv.push_back("--debuggable"); 194 } 195 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv); 196 197 if (!runtime->IsVerificationEnabled()) { 198 argv.push_back("--compiler-filter=assume-verified"); 199 } 200 201 if (runtime->MustRelocateIfPossible()) { 202 argv.push_back("--runtime-arg"); 203 argv.push_back("-Xrelocate"); 204 } else { 205 argv.push_back("--runtime-arg"); 206 argv.push_back("-Xnorelocate"); 207 } 208 209 if (!kIsTargetBuild) { 210 argv.push_back("--host"); 211 } 212 213 argv.push_back("--boot-image=" + image_location); 214 215 std::vector<std::string> compiler_options = runtime->GetCompilerOptions(); 216 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end()); 217 218 argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.end()); 219 220 // We must set --android-root. 221 const char* android_root = getenv("ANDROID_ROOT"); 222 CHECK(android_root != nullptr); 223 argv.push_back("--android-root=" + std::string(android_root)); 224 225 if (kDebugArgs) { 226 std::string all_args; 227 for (const std::string& arg : argv) { 228 all_args += arg + " "; 229 } 230 LOG(ERROR) << all_args; 231 } 232 233 int link[2]; 234 235 if (pipe(link) == -1) { 236 return false; 237 } 238 239 pid_t pid = fork(); 240 if (pid == -1) { 241 return false; 242 } 243 244 if (pid == 0) { 245 // We need dex2oat to actually log things. 246 setenv("ANDROID_LOG_TAGS", "*:d", 1); 247 dup2(link[1], STDERR_FILENO); 248 close(link[0]); 249 close(link[1]); 250 std::vector<const char*> c_args; 251 for (const std::string& str : argv) { 252 c_args.push_back(str.c_str()); 253 } 254 c_args.push_back(nullptr); 255 execv(c_args[0], const_cast<char* const*>(c_args.data())); 256 exit(1); 257 UNREACHABLE(); 258 } else { 259 close(link[1]); 260 char buffer[128]; 261 memset(buffer, 0, 128); 262 ssize_t bytes_read = 0; 263 264 while (TEMP_FAILURE_RETRY(bytes_read = read(link[0], buffer, 128)) > 0) { 265 output_ += std::string(buffer, bytes_read); 266 } 267 close(link[0]); 268 int status = -1; 269 if (waitpid(pid, &status, 0) != -1) { 270 success_ = (status == 0); 271 } 272 return status; 273 } 274 } 275 276 std::string output_ = ""; 277 std::string error_msg_ = ""; 278 bool success_ = false; 279 }; 280 281 class Dex2oatSwapTest : public Dex2oatTest { 282 protected: 283 void RunTest(bool use_fd, bool expect_use, const std::vector<std::string>& extra_args = {}) { 284 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar"; 285 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex"; 286 287 Copy(GetTestDexFileName(), dex_location); 288 289 std::vector<std::string> copy(extra_args); 290 291 std::unique_ptr<ScratchFile> sf; 292 if (use_fd) { 293 sf.reset(new ScratchFile()); 294 copy.push_back(android::base::StringPrintf("--swap-fd=%d", sf->GetFd())); 295 } else { 296 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap"; 297 copy.push_back("--swap-file=" + swap_location); 298 } 299 GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy); 300 301 CheckValidity(); 302 ASSERT_TRUE(success_); 303 CheckResult(expect_use); 304 } 305 306 virtual std::string GetTestDexFileName() { 307 return Dex2oatEnvironmentTest::GetTestDexFileName("VerifierDeps"); 308 } 309 310 virtual void CheckResult(bool expect_use) { 311 if (kIsTargetBuild) { 312 CheckTargetResult(expect_use); 313 } else { 314 CheckHostResult(expect_use); 315 } 316 } 317 318 virtual void CheckTargetResult(bool expect_use ATTRIBUTE_UNUSED) { 319 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do 320 // something for variants with file descriptor where we can control the lifetime of 321 // the swap file and thus take a look at it. 322 } 323 324 virtual void CheckHostResult(bool expect_use) { 325 if (!kIsTargetBuild) { 326 if (expect_use) { 327 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos) 328 << output_; 329 } else { 330 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos) 331 << output_; 332 } 333 } 334 } 335 336 // Check whether the dex2oat run was really successful. 337 virtual void CheckValidity() { 338 if (kIsTargetBuild) { 339 CheckTargetValidity(); 340 } else { 341 CheckHostValidity(); 342 } 343 } 344 345 virtual void CheckTargetValidity() { 346 // TODO: Ignore for now, as we won't capture any output (it goes to the logcat). We may do 347 // something for variants with file descriptor where we can control the lifetime of 348 // the swap file and thus take a look at it. 349 } 350 351 // On the host, we can get the dex2oat output. Here, look for "dex2oat took." 352 virtual void CheckHostValidity() { 353 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; 354 } 355 }; 356 357 TEST_F(Dex2oatSwapTest, DoNotUseSwapDefaultSingleSmall) { 358 RunTest(false /* use_fd */, false /* expect_use */); 359 RunTest(true /* use_fd */, false /* expect_use */); 360 } 361 362 TEST_F(Dex2oatSwapTest, DoNotUseSwapSingle) { 363 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" }); 364 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-size-threshold=0" }); 365 } 366 367 TEST_F(Dex2oatSwapTest, DoNotUseSwapSmall) { 368 RunTest(false /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" }); 369 RunTest(true /* use_fd */, false /* expect_use */, { "--swap-dex-count-threshold=0" }); 370 } 371 372 TEST_F(Dex2oatSwapTest, DoUseSwapSingleSmall) { 373 RunTest(false /* use_fd */, 374 true /* expect_use */, 375 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); 376 RunTest(true /* use_fd */, 377 true /* expect_use */, 378 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); 379 } 380 381 class Dex2oatSwapUseTest : public Dex2oatSwapTest { 382 protected: 383 void CheckHostResult(bool expect_use) OVERRIDE { 384 if (!kIsTargetBuild) { 385 if (expect_use) { 386 EXPECT_NE(output_.find("Large app, accepted running with swap."), std::string::npos) 387 << output_; 388 } else { 389 EXPECT_EQ(output_.find("Large app, accepted running with swap."), std::string::npos) 390 << output_; 391 } 392 } 393 } 394 395 std::string GetTestDexFileName() OVERRIDE { 396 // Use Statics as it has a handful of functions. 397 return CommonRuntimeTest::GetTestDexFileName("Statics"); 398 } 399 400 void GrabResult1() { 401 if (!kIsTargetBuild) { 402 native_alloc_1_ = ParseNativeAlloc(); 403 swap_1_ = ParseSwap(false /* expected */); 404 } else { 405 native_alloc_1_ = std::numeric_limits<size_t>::max(); 406 swap_1_ = 0; 407 } 408 } 409 410 void GrabResult2() { 411 if (!kIsTargetBuild) { 412 native_alloc_2_ = ParseNativeAlloc(); 413 swap_2_ = ParseSwap(true /* expected */); 414 } else { 415 native_alloc_2_ = 0; 416 swap_2_ = std::numeric_limits<size_t>::max(); 417 } 418 } 419 420 private: 421 size_t ParseNativeAlloc() { 422 std::regex native_alloc_regex("dex2oat took.*native alloc=[^ ]+ \\(([0-9]+)B\\)"); 423 std::smatch native_alloc_match; 424 bool found = std::regex_search(output_, native_alloc_match, native_alloc_regex); 425 if (!found) { 426 EXPECT_TRUE(found); 427 return 0; 428 } 429 if (native_alloc_match.size() != 2U) { 430 EXPECT_EQ(native_alloc_match.size(), 2U); 431 return 0; 432 } 433 434 std::istringstream stream(native_alloc_match[1].str()); 435 size_t value; 436 stream >> value; 437 438 return value; 439 } 440 441 size_t ParseSwap(bool expected) { 442 std::regex swap_regex("dex2oat took[^\\n]+swap=[^ ]+ \\(([0-9]+)B\\)"); 443 std::smatch swap_match; 444 bool found = std::regex_search(output_, swap_match, swap_regex); 445 if (found != expected) { 446 EXPECT_EQ(expected, found); 447 return 0; 448 } 449 450 if (!found) { 451 return 0; 452 } 453 454 if (swap_match.size() != 2U) { 455 EXPECT_EQ(swap_match.size(), 2U); 456 return 0; 457 } 458 459 std::istringstream stream(swap_match[1].str()); 460 size_t value; 461 stream >> value; 462 463 return value; 464 } 465 466 protected: 467 size_t native_alloc_1_; 468 size_t native_alloc_2_; 469 470 size_t swap_1_; 471 size_t swap_2_; 472 }; 473 474 TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) { 475 // Native memory usage isn't correctly tracked under sanitization. 476 TEST_DISABLED_FOR_MEMORY_TOOL_ASAN(); 477 478 // The `native_alloc_2_ >= native_alloc_1_` assertion below may not 479 // hold true on some x86 systems; disable this test while we 480 // investigate (b/29259363). 481 TEST_DISABLED_FOR_X86(); 482 483 RunTest(false /* use_fd */, 484 false /* expect_use */); 485 GrabResult1(); 486 std::string output_1 = output_; 487 488 output_ = ""; 489 490 RunTest(false /* use_fd */, 491 true /* expect_use */, 492 { "--swap-dex-size-threshold=0", "--swap-dex-count-threshold=0" }); 493 GrabResult2(); 494 std::string output_2 = output_; 495 496 if (native_alloc_2_ >= native_alloc_1_ || swap_1_ >= swap_2_) { 497 EXPECT_LT(native_alloc_2_, native_alloc_1_); 498 EXPECT_LT(swap_1_, swap_2_); 499 500 LOG(ERROR) << output_1; 501 LOG(ERROR) << output_2; 502 } 503 } 504 505 class Dex2oatVeryLargeTest : public Dex2oatTest { 506 protected: 507 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED, 508 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE { 509 // Ignore, we'll do our own checks. 510 } 511 512 void RunTest(CompilerFilter::Filter filter, 513 bool expect_large, 514 bool expect_downgrade, 515 const std::vector<std::string>& extra_args = {}) { 516 std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; 517 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; 518 std::string app_image_file = GetScratchDir() + "/Test.art"; 519 520 Copy(GetDexSrc1(), dex_location); 521 522 std::vector<std::string> new_args(extra_args); 523 new_args.push_back("--app-image-file=" + app_image_file); 524 GenerateOdexForTest(dex_location, odex_location, filter, new_args); 525 526 CheckValidity(); 527 ASSERT_TRUE(success_); 528 CheckResult(dex_location, 529 odex_location, 530 app_image_file, 531 filter, 532 expect_large, 533 expect_downgrade); 534 } 535 536 void CheckResult(const std::string& dex_location, 537 const std::string& odex_location, 538 const std::string& app_image_file, 539 CompilerFilter::Filter filter, 540 bool expect_large, 541 bool expect_downgrade) { 542 if (expect_downgrade) { 543 EXPECT_TRUE(expect_large); 544 } 545 // Host/target independent checks. 546 std::string error_msg; 547 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 548 odex_location.c_str(), 549 odex_location.c_str(), 550 nullptr, 551 nullptr, 552 false, 553 /*low_4gb*/false, 554 dex_location.c_str(), 555 &error_msg)); 556 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; 557 EXPECT_GT(app_image_file.length(), 0u); 558 std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file.c_str())); 559 if (expect_large) { 560 // Note: we cannot check the following 561 // EXPECT_FALSE(CompilerFilter::IsAotCompilationEnabled(odex_file->GetCompilerFilter())); 562 // The reason is that the filter override currently happens when the dex files are 563 // loaded in dex2oat, which is after the oat file has been started. Thus, the header 564 // store cannot be changed, and the original filter is set in stone. 565 566 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { 567 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg); 568 ASSERT_TRUE(dex_file != nullptr); 569 uint32_t class_def_count = dex_file->NumClassDefs(); 570 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max()); 571 for (uint16_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { 572 OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index); 573 EXPECT_EQ(oat_class.GetType(), OatClassType::kOatClassNoneCompiled); 574 } 575 } 576 577 // If the input filter was "below," it should have been used. 578 if (!CompilerFilter::IsAsGoodAs(CompilerFilter::kExtract, filter)) { 579 EXPECT_EQ(odex_file->GetCompilerFilter(), filter); 580 } 581 582 // If expect large, make sure the app image isn't generated or is empty. 583 if (file != nullptr) { 584 EXPECT_EQ(file->GetLength(), 0u); 585 } 586 } else { 587 EXPECT_EQ(odex_file->GetCompilerFilter(), filter); 588 ASSERT_TRUE(file != nullptr) << app_image_file; 589 EXPECT_GT(file->GetLength(), 0u); 590 } 591 592 // Host/target dependent checks. 593 if (kIsTargetBuild) { 594 CheckTargetResult(expect_downgrade); 595 } else { 596 CheckHostResult(expect_downgrade); 597 } 598 } 599 600 void CheckTargetResult(bool expect_downgrade ATTRIBUTE_UNUSED) { 601 // TODO: Ignore for now. May do something for fd things. 602 } 603 604 void CheckHostResult(bool expect_downgrade) { 605 if (!kIsTargetBuild) { 606 if (expect_downgrade) { 607 EXPECT_NE(output_.find("Very large app, downgrading to"), std::string::npos) << output_; 608 } else { 609 EXPECT_EQ(output_.find("Very large app, downgrading to"), std::string::npos) << output_; 610 } 611 } 612 } 613 614 // Check whether the dex2oat run was really successful. 615 void CheckValidity() { 616 if (kIsTargetBuild) { 617 CheckTargetValidity(); 618 } else { 619 CheckHostValidity(); 620 } 621 } 622 623 void CheckTargetValidity() { 624 // TODO: Ignore for now. 625 } 626 627 // On the host, we can get the dex2oat output. Here, look for "dex2oat took." 628 void CheckHostValidity() { 629 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; 630 } 631 }; 632 633 TEST_F(Dex2oatVeryLargeTest, DontUseVeryLarge) { 634 RunTest(CompilerFilter::kAssumeVerified, false, false); 635 RunTest(CompilerFilter::kExtract, false, false); 636 RunTest(CompilerFilter::kQuicken, false, false); 637 RunTest(CompilerFilter::kSpeed, false, false); 638 639 RunTest(CompilerFilter::kAssumeVerified, false, false, { "--very-large-app-threshold=10000000" }); 640 RunTest(CompilerFilter::kExtract, false, false, { "--very-large-app-threshold=10000000" }); 641 RunTest(CompilerFilter::kQuicken, false, false, { "--very-large-app-threshold=10000000" }); 642 RunTest(CompilerFilter::kSpeed, false, false, { "--very-large-app-threshold=10000000" }); 643 } 644 645 TEST_F(Dex2oatVeryLargeTest, UseVeryLarge) { 646 RunTest(CompilerFilter::kAssumeVerified, true, false, { "--very-large-app-threshold=100" }); 647 RunTest(CompilerFilter::kExtract, true, false, { "--very-large-app-threshold=100" }); 648 RunTest(CompilerFilter::kQuicken, true, true, { "--very-large-app-threshold=100" }); 649 RunTest(CompilerFilter::kSpeed, true, true, { "--very-large-app-threshold=100" }); 650 } 651 652 // Regressin test for b/35665292. 653 TEST_F(Dex2oatVeryLargeTest, SpeedProfileNoProfile) { 654 // Test that dex2oat doesn't crash with speed-profile but no input profile. 655 RunTest(CompilerFilter::kSpeedProfile, false, false); 656 } 657 658 class Dex2oatLayoutTest : public Dex2oatTest { 659 protected: 660 void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED, 661 CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE { 662 // Ignore, we'll do our own checks. 663 } 664 665 // Emits a profile with a single dex file with the given location and a single class index of 1. 666 void GenerateProfile(const std::string& test_profile, 667 const std::string& dex_location, 668 size_t num_classes, 669 uint32_t checksum) { 670 int profile_test_fd = open(test_profile.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0644); 671 CHECK_GE(profile_test_fd, 0); 672 673 ProfileCompilationInfo info; 674 std::string profile_key = ProfileCompilationInfo::GetProfileDexFileKey(dex_location); 675 for (size_t i = 0; i < num_classes; ++i) { 676 info.AddClassIndex(profile_key, checksum, dex::TypeIndex(1 + i), kMaxMethodIds); 677 } 678 bool result = info.Save(profile_test_fd); 679 close(profile_test_fd); 680 ASSERT_TRUE(result); 681 } 682 683 void CompileProfileOdex(const std::string& dex_location, 684 const std::string& odex_location, 685 const std::string& app_image_file_name, 686 bool use_fd, 687 size_t num_profile_classes, 688 const std::vector<std::string>& extra_args = {}, 689 bool expect_success = true) { 690 const std::string profile_location = GetScratchDir() + "/primary.prof"; 691 const char* location = dex_location.c_str(); 692 std::string error_msg; 693 std::vector<std::unique_ptr<const DexFile>> dex_files; 694 const ArtDexFileLoader dex_file_loader; 695 ASSERT_TRUE(dex_file_loader.Open( 696 location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files)); 697 EXPECT_EQ(dex_files.size(), 1U); 698 std::unique_ptr<const DexFile>& dex_file = dex_files[0]; 699 GenerateProfile(profile_location, 700 dex_location, 701 num_profile_classes, 702 dex_file->GetLocationChecksum()); 703 std::vector<std::string> copy(extra_args); 704 copy.push_back("--profile-file=" + profile_location); 705 std::unique_ptr<File> app_image_file; 706 if (!app_image_file_name.empty()) { 707 if (use_fd) { 708 app_image_file.reset(OS::CreateEmptyFile(app_image_file_name.c_str())); 709 copy.push_back("--app-image-fd=" + std::to_string(app_image_file->Fd())); 710 } else { 711 copy.push_back("--app-image-file=" + app_image_file_name); 712 } 713 } 714 GenerateOdexForTest(dex_location, 715 odex_location, 716 CompilerFilter::kSpeedProfile, 717 copy, 718 expect_success, 719 use_fd); 720 if (app_image_file != nullptr) { 721 ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file"; 722 } 723 } 724 725 uint64_t GetImageObjectSectionSize(const std::string& image_file_name) { 726 EXPECT_FALSE(image_file_name.empty()); 727 std::unique_ptr<File> file(OS::OpenFileForReading(image_file_name.c_str())); 728 CHECK(file != nullptr); 729 ImageHeader image_header; 730 const bool success = file->ReadFully(&image_header, sizeof(image_header)); 731 CHECK(success); 732 CHECK(image_header.IsValid()); 733 ReaderMutexLock mu(Thread::Current(), *Locks::mutator_lock_); 734 return image_header.GetObjectsSection().Size(); 735 } 736 737 void RunTest(bool app_image) { 738 std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; 739 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; 740 std::string app_image_file = app_image ? (GetOdexDir() + "/DexOdexNoOat.art"): ""; 741 Copy(GetDexSrc2(), dex_location); 742 743 uint64_t image_file_empty_profile = 0; 744 if (app_image) { 745 CompileProfileOdex(dex_location, 746 odex_location, 747 app_image_file, 748 /* use_fd */ false, 749 /* num_profile_classes */ 0); 750 CheckValidity(); 751 ASSERT_TRUE(success_); 752 // Don't check the result since CheckResult relies on the class being in the profile. 753 image_file_empty_profile = GetImageObjectSectionSize(app_image_file); 754 EXPECT_GT(image_file_empty_profile, 0u); 755 } 756 757 // Small profile. 758 CompileProfileOdex(dex_location, 759 odex_location, 760 app_image_file, 761 /* use_fd */ false, 762 /* num_profile_classes */ 1); 763 CheckValidity(); 764 ASSERT_TRUE(success_); 765 CheckResult(dex_location, odex_location, app_image_file); 766 767 if (app_image) { 768 // Test that the profile made a difference by adding more classes. 769 const uint64_t image_file_small_profile = GetImageObjectSectionSize(app_image_file); 770 ASSERT_LT(image_file_empty_profile, image_file_small_profile); 771 } 772 } 773 774 void RunTestVDex() { 775 std::string dex_location = GetScratchDir() + "/DexNoOat.jar"; 776 std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex"; 777 std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex"; 778 std::string app_image_file_name = GetOdexDir() + "/DexOdexNoOat.art"; 779 Copy(GetDexSrc2(), dex_location); 780 781 std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str())); 782 CHECK(vdex_file1 != nullptr) << vdex_location; 783 ScratchFile vdex_file2; 784 { 785 std::string input_vdex = "--input-vdex-fd=-1"; 786 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); 787 CompileProfileOdex(dex_location, 788 odex_location, 789 app_image_file_name, 790 /* use_fd */ true, 791 /* num_profile_classes */ 1, 792 { input_vdex, output_vdex }); 793 EXPECT_GT(vdex_file1->GetLength(), 0u); 794 } 795 { 796 // Test that vdex and dexlayout fail gracefully. 797 std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd()); 798 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd()); 799 CompileProfileOdex(dex_location, 800 odex_location, 801 app_image_file_name, 802 /* use_fd */ true, 803 /* num_profile_classes */ 1, 804 { input_vdex, output_vdex }, 805 /* expect_success */ true); 806 EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u); 807 } 808 ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; 809 CheckValidity(); 810 ASSERT_TRUE(success_); 811 } 812 813 void CheckResult(const std::string& dex_location, 814 const std::string& odex_location, 815 const std::string& app_image_file_name) { 816 // Host/target independent checks. 817 std::string error_msg; 818 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 819 odex_location.c_str(), 820 odex_location.c_str(), 821 nullptr, 822 nullptr, 823 false, 824 /*low_4gb*/false, 825 dex_location.c_str(), 826 &error_msg)); 827 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; 828 829 const char* location = dex_location.c_str(); 830 std::vector<std::unique_ptr<const DexFile>> dex_files; 831 const ArtDexFileLoader dex_file_loader; 832 ASSERT_TRUE(dex_file_loader.Open( 833 location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files)); 834 EXPECT_EQ(dex_files.size(), 1U); 835 std::unique_ptr<const DexFile>& old_dex_file = dex_files[0]; 836 837 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { 838 std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg); 839 ASSERT_TRUE(new_dex_file != nullptr); 840 uint32_t class_def_count = new_dex_file->NumClassDefs(); 841 ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max()); 842 ASSERT_GE(class_def_count, 2U); 843 844 // Make sure the indexes stay the same. 845 std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_); 846 std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_); 847 std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_); 848 std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_); 849 EXPECT_EQ(old_class0, new_class0); 850 EXPECT_EQ(old_class1, new_class1); 851 } 852 853 EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile); 854 855 if (!app_image_file_name.empty()) { 856 // Go peek at the image header to make sure it was large enough to contain the class. 857 std::unique_ptr<File> file(OS::OpenFileForReading(app_image_file_name.c_str())); 858 ImageHeader image_header; 859 bool success = file->ReadFully(&image_header, sizeof(image_header)); 860 ASSERT_TRUE(success); 861 ASSERT_TRUE(image_header.IsValid()); 862 EXPECT_GT(image_header.GetObjectsSection().Size(), 0u); 863 } 864 } 865 866 // Check whether the dex2oat run was really successful. 867 void CheckValidity() { 868 if (kIsTargetBuild) { 869 CheckTargetValidity(); 870 } else { 871 CheckHostValidity(); 872 } 873 } 874 875 void CheckTargetValidity() { 876 // TODO: Ignore for now. 877 } 878 879 // On the host, we can get the dex2oat output. Here, look for "dex2oat took." 880 void CheckHostValidity() { 881 EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_; 882 } 883 }; 884 885 TEST_F(Dex2oatLayoutTest, TestLayout) { 886 RunTest(/* app-image */ false); 887 } 888 889 TEST_F(Dex2oatLayoutTest, TestLayoutAppImage) { 890 RunTest(/* app-image */ true); 891 } 892 893 TEST_F(Dex2oatLayoutTest, TestVdexLayout) { 894 RunTestVDex(); 895 } 896 897 class Dex2oatUnquickenTest : public Dex2oatTest { 898 protected: 899 void RunUnquickenMultiDex() { 900 std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar"; 901 std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex"; 902 std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex"; 903 Copy(GetTestDexFileName("MultiDex"), dex_location); 904 905 std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str())); 906 CHECK(vdex_file1 != nullptr) << vdex_location; 907 // Quicken the dex file into a vdex file. 908 { 909 std::string input_vdex = "--input-vdex-fd=-1"; 910 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); 911 GenerateOdexForTest(dex_location, 912 odex_location, 913 CompilerFilter::kQuicken, 914 { input_vdex, output_vdex }, 915 /* expect_success */ true, 916 /* use_fd */ true); 917 EXPECT_GT(vdex_file1->GetLength(), 0u); 918 } 919 // Unquicken by running the verify compiler filter on the vdex file. 920 { 921 std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd()); 922 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); 923 GenerateOdexForTest(dex_location, 924 odex_location, 925 CompilerFilter::kVerify, 926 { input_vdex, output_vdex, kDisableCompactDex }, 927 /* expect_success */ true, 928 /* use_fd */ true); 929 } 930 ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; 931 CheckResult(dex_location, odex_location); 932 ASSERT_TRUE(success_); 933 } 934 935 void RunUnquickenMultiDexCDex() { 936 std::string dex_location = GetScratchDir() + "/UnquickenMultiDex.jar"; 937 std::string odex_location = GetOdexDir() + "/UnquickenMultiDex.odex"; 938 std::string odex_location2 = GetOdexDir() + "/UnquickenMultiDex2.odex"; 939 std::string vdex_location = GetOdexDir() + "/UnquickenMultiDex.vdex"; 940 std::string vdex_location2 = GetOdexDir() + "/UnquickenMultiDex2.vdex"; 941 Copy(GetTestDexFileName("MultiDex"), dex_location); 942 943 std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str())); 944 std::unique_ptr<File> vdex_file2(OS::CreateEmptyFile(vdex_location2.c_str())); 945 CHECK(vdex_file1 != nullptr) << vdex_location; 946 CHECK(vdex_file2 != nullptr) << vdex_location2; 947 948 // Quicken the dex file into a vdex file. 949 { 950 std::string input_vdex = "--input-vdex-fd=-1"; 951 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd()); 952 GenerateOdexForTest(dex_location, 953 odex_location, 954 CompilerFilter::kQuicken, 955 { input_vdex, output_vdex, "--compact-dex-level=fast"}, 956 /* expect_success */ true, 957 /* use_fd */ true); 958 EXPECT_GT(vdex_file1->GetLength(), 0u); 959 } 960 961 // Unquicken by running the verify compiler filter on the vdex file. 962 { 963 std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd()); 964 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2->Fd()); 965 GenerateOdexForTest(dex_location, 966 odex_location2, 967 CompilerFilter::kVerify, 968 { input_vdex, output_vdex, "--compact-dex-level=none"}, 969 /* expect_success */ true, 970 /* use_fd */ true); 971 } 972 ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; 973 ASSERT_EQ(vdex_file2->FlushCloseOrErase(), 0) << "Could not flush and close vdex file"; 974 CheckResult(dex_location, odex_location2); 975 ASSERT_TRUE(success_); 976 } 977 978 void CheckResult(const std::string& dex_location, const std::string& odex_location) { 979 std::string error_msg; 980 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 981 odex_location.c_str(), 982 odex_location.c_str(), 983 nullptr, 984 nullptr, 985 false, 986 /*low_4gb*/false, 987 dex_location.c_str(), 988 &error_msg)); 989 ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; 990 ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u); 991 992 // Iterate over the dex files and ensure there is no quickened instruction. 993 for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) { 994 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg); 995 for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { 996 const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); 997 const uint8_t* class_data = dex_file->GetClassData(class_def); 998 if (class_data != nullptr) { 999 for (ClassDataItemIterator class_it(*dex_file, class_data); 1000 class_it.HasNext(); 1001 class_it.Next()) { 1002 if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) { 1003 for (const DexInstructionPcPair& inst : 1004 CodeItemInstructionAccessor(*dex_file, class_it.GetMethodCodeItem())) { 1005 ASSERT_FALSE(inst->IsQuickened()) << inst->Opcode() << " " << output_; 1006 } 1007 } 1008 } 1009 } 1010 } 1011 } 1012 } 1013 }; 1014 1015 TEST_F(Dex2oatUnquickenTest, UnquickenMultiDex) { 1016 RunUnquickenMultiDex(); 1017 } 1018 1019 TEST_F(Dex2oatUnquickenTest, UnquickenMultiDexCDex) { 1020 RunUnquickenMultiDexCDex(); 1021 } 1022 1023 class Dex2oatWatchdogTest : public Dex2oatTest { 1024 protected: 1025 void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) { 1026 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar"; 1027 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex"; 1028 1029 Copy(GetTestDexFileName(), dex_location); 1030 1031 std::vector<std::string> copy(extra_args); 1032 1033 std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap"; 1034 copy.push_back("--swap-file=" + swap_location); 1035 copy.push_back("-j512"); // Excessive idle threads just slow down dex2oat. 1036 GenerateOdexForTest(dex_location, 1037 odex_location, 1038 CompilerFilter::kSpeed, 1039 copy, 1040 expect_success); 1041 } 1042 1043 std::string GetTestDexFileName() { 1044 return GetDexSrc1(); 1045 } 1046 }; 1047 1048 TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) { 1049 // Check with default. 1050 RunTest(true); 1051 1052 // Check with ten minutes. 1053 RunTest(true, { "--watchdog-timeout=600000" }); 1054 } 1055 1056 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) { 1057 TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND(); // b/63052624 1058 1059 // The watchdog is independent of dex2oat and will not delete intermediates. It is possible 1060 // that the compilation succeeds and the file is completely written by the time the watchdog 1061 // kills dex2oat (but the dex2oat threads must have been scheduled pretty badly). 1062 test_accepts_odex_file_on_failure = true; 1063 1064 // Check with ten milliseconds. 1065 RunTest(false, { "--watchdog-timeout=10" }); 1066 } 1067 1068 class Dex2oatReturnCodeTest : public Dex2oatTest { 1069 protected: 1070 int RunTest(const std::vector<std::string>& extra_args = {}) { 1071 std::string dex_location = GetScratchDir() + "/Dex2OatSwapTest.jar"; 1072 std::string odex_location = GetOdexDir() + "/Dex2OatSwapTest.odex"; 1073 1074 Copy(GetTestDexFileName(), dex_location); 1075 1076 std::string error_msg; 1077 return GenerateOdexForTestWithStatus({dex_location}, 1078 odex_location, 1079 CompilerFilter::kSpeed, 1080 &error_msg, 1081 extra_args); 1082 } 1083 1084 std::string GetTestDexFileName() { 1085 return GetDexSrc1(); 1086 } 1087 }; 1088 1089 TEST_F(Dex2oatReturnCodeTest, TestCreateRuntime) { 1090 TEST_DISABLED_FOR_MEMORY_TOOL(); // b/19100793 1091 int status = RunTest({ "--boot-image=/this/does/not/exist/yolo.oat" }); 1092 EXPECT_EQ(static_cast<int>(dex2oat::ReturnCode::kCreateRuntime), WEXITSTATUS(status)) << output_; 1093 } 1094 1095 class Dex2oatClassLoaderContextTest : public Dex2oatTest { 1096 protected: 1097 void RunTest(const char* class_loader_context, 1098 const char* expected_classpath_key, 1099 bool expected_success, 1100 bool use_second_source = false) { 1101 std::string dex_location = GetUsedDexLocation(); 1102 std::string odex_location = GetUsedOatLocation(); 1103 1104 Copy(use_second_source ? GetDexSrc2() : GetDexSrc1(), dex_location); 1105 1106 std::string error_msg; 1107 std::vector<std::string> extra_args; 1108 if (class_loader_context != nullptr) { 1109 extra_args.push_back(std::string("--class-loader-context=") + class_loader_context); 1110 } 1111 auto check_oat = [expected_classpath_key](const OatFile& oat_file) { 1112 ASSERT_TRUE(expected_classpath_key != nullptr); 1113 const char* classpath = oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey); 1114 ASSERT_TRUE(classpath != nullptr); 1115 ASSERT_STREQ(expected_classpath_key, classpath); 1116 }; 1117 1118 GenerateOdexForTest(dex_location, 1119 odex_location, 1120 CompilerFilter::kQuicken, 1121 extra_args, 1122 expected_success, 1123 /*use_fd*/ false, 1124 check_oat); 1125 } 1126 1127 std::string GetUsedDexLocation() { 1128 return GetScratchDir() + "/Context.jar"; 1129 } 1130 1131 std::string GetUsedOatLocation() { 1132 return GetOdexDir() + "/Context.odex"; 1133 } 1134 1135 const char* kEmptyClassPathKey = "PCL[]"; 1136 }; 1137 1138 TEST_F(Dex2oatClassLoaderContextTest, InvalidContext) { 1139 RunTest("Invalid[]", /*expected_classpath_key*/ nullptr, /*expected_success*/ false); 1140 } 1141 1142 TEST_F(Dex2oatClassLoaderContextTest, EmptyContext) { 1143 RunTest("PCL[]", kEmptyClassPathKey, /*expected_success*/ true); 1144 } 1145 1146 TEST_F(Dex2oatClassLoaderContextTest, SpecialContext) { 1147 RunTest(OatFile::kSpecialSharedLibrary, 1148 OatFile::kSpecialSharedLibrary, 1149 /*expected_success*/ true); 1150 } 1151 1152 TEST_F(Dex2oatClassLoaderContextTest, ContextWithTheSourceDexFiles) { 1153 std::string context = "PCL[" + GetUsedDexLocation() + "]"; 1154 RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true); 1155 } 1156 1157 TEST_F(Dex2oatClassLoaderContextTest, ContextWithOtherDexFiles) { 1158 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Nested"); 1159 1160 std::string context = "PCL[" + dex_files[0]->GetLocation() + "]"; 1161 std::string expected_classpath_key = "PCL[" + 1162 dex_files[0]->GetLocation() + "*" + std::to_string(dex_files[0]->GetLocationChecksum()) + "]"; 1163 RunTest(context.c_str(), expected_classpath_key.c_str(), true); 1164 } 1165 1166 TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFiles) { 1167 std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar"; 1168 Copy(GetStrippedDexSrc1(), stripped_classpath); 1169 1170 std::string context = "PCL[" + stripped_classpath + "]"; 1171 // Expect an empty context because stripped dex files cannot be open. 1172 RunTest(context.c_str(), kEmptyClassPathKey , /*expected_success*/ true); 1173 } 1174 1175 TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFilesBackedByOdex) { 1176 std::string stripped_classpath = GetScratchDir() + "/stripped_classpath.jar"; 1177 std::string odex_for_classpath = GetOdexDir() + "/stripped_classpath.odex"; 1178 1179 Copy(GetDexSrc1(), stripped_classpath); 1180 1181 GenerateOdexForTest(stripped_classpath, 1182 odex_for_classpath, 1183 CompilerFilter::kQuicken, 1184 {}, 1185 true); 1186 1187 // Strip the dex file 1188 Copy(GetStrippedDexSrc1(), stripped_classpath); 1189 1190 std::string context = "PCL[" + stripped_classpath + "]"; 1191 std::string expected_classpath_key; 1192 { 1193 // Open the oat file to get the expected classpath. 1194 OatFileAssistant oat_file_assistant(stripped_classpath.c_str(), kRuntimeISA, false, false); 1195 std::unique_ptr<OatFile> oat_file(oat_file_assistant.GetBestOatFile()); 1196 std::vector<std::unique_ptr<const DexFile>> oat_dex_files = 1197 OatFileAssistant::LoadDexFiles(*oat_file, stripped_classpath.c_str()); 1198 expected_classpath_key = "PCL["; 1199 for (size_t i = 0; i < oat_dex_files.size(); i++) { 1200 if (i > 0) { 1201 expected_classpath_key + ":"; 1202 } 1203 expected_classpath_key += oat_dex_files[i]->GetLocation() + "*" + 1204 std::to_string(oat_dex_files[i]->GetLocationChecksum()); 1205 } 1206 expected_classpath_key += "]"; 1207 } 1208 1209 RunTest(context.c_str(), 1210 expected_classpath_key.c_str(), 1211 /*expected_success*/ true, 1212 /*use_second_source*/ true); 1213 } 1214 1215 TEST_F(Dex2oatClassLoaderContextTest, ContextWithNotExistentDexFiles) { 1216 std::string context = "PCL[does_not_exists.dex]"; 1217 // Expect an empty context because stripped dex files cannot be open. 1218 RunTest(context.c_str(), kEmptyClassPathKey, /*expected_success*/ true); 1219 } 1220 1221 TEST_F(Dex2oatClassLoaderContextTest, ChainContext) { 1222 std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested"); 1223 std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex"); 1224 1225 std::string context = "PCL[" + GetTestDexFileName("Nested") + "];" + 1226 "DLC[" + GetTestDexFileName("MultiDex") + "]"; 1227 std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "];" + 1228 "DLC[" + CreateClassPathWithChecksums(dex_files2) + "]"; 1229 1230 RunTest(context.c_str(), expected_classpath_key.c_str(), true); 1231 } 1232 1233 class Dex2oatDeterminism : public Dex2oatTest {}; 1234 1235 TEST_F(Dex2oatDeterminism, UnloadCompile) { 1236 if (!kUseReadBarrier && 1237 gc::kCollectorTypeDefault != gc::kCollectorTypeCMS && 1238 gc::kCollectorTypeDefault != gc::kCollectorTypeMS) { 1239 LOG(INFO) << "Test requires determinism support."; 1240 return; 1241 } 1242 Runtime* const runtime = Runtime::Current(); 1243 std::string out_dir = GetScratchDir(); 1244 const std::string base_oat_name = out_dir + "/base.oat"; 1245 const std::string base_vdex_name = out_dir + "/base.vdex"; 1246 const std::string unload_oat_name = out_dir + "/unload.oat"; 1247 const std::string unload_vdex_name = out_dir + "/unload.vdex"; 1248 const std::string no_unload_oat_name = out_dir + "/nounload.oat"; 1249 const std::string no_unload_vdex_name = out_dir + "/nounload.vdex"; 1250 const std::string app_image_name = out_dir + "/unload.art"; 1251 std::string error_msg; 1252 const std::vector<gc::space::ImageSpace*>& spaces = runtime->GetHeap()->GetBootImageSpaces(); 1253 ASSERT_GT(spaces.size(), 0u); 1254 const std::string image_location = spaces[0]->GetImageLocation(); 1255 // Without passing in an app image, it will unload in between compilations. 1256 const int res = GenerateOdexForTestWithStatus( 1257 GetLibCoreDexFileNames(), 1258 base_oat_name, 1259 CompilerFilter::Filter::kQuicken, 1260 &error_msg, 1261 {"--force-determinism", "--avoid-storing-invocation"}); 1262 EXPECT_EQ(res, 0); 1263 Copy(base_oat_name, unload_oat_name); 1264 Copy(base_vdex_name, unload_vdex_name); 1265 std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str())); 1266 std::unique_ptr<File> unload_vdex(OS::OpenFileForReading(unload_vdex_name.c_str())); 1267 ASSERT_TRUE(unload_oat != nullptr); 1268 ASSERT_TRUE(unload_vdex != nullptr); 1269 EXPECT_GT(unload_oat->GetLength(), 0u); 1270 EXPECT_GT(unload_vdex->GetLength(), 0u); 1271 // Regenerate with an app image to disable the dex2oat unloading and verify that the output is 1272 // the same. 1273 const int res2 = GenerateOdexForTestWithStatus( 1274 GetLibCoreDexFileNames(), 1275 base_oat_name, 1276 CompilerFilter::Filter::kQuicken, 1277 &error_msg, 1278 {"--force-determinism", "--avoid-storing-invocation", "--app-image-file=" + app_image_name}); 1279 EXPECT_EQ(res2, 0); 1280 Copy(base_oat_name, no_unload_oat_name); 1281 Copy(base_vdex_name, no_unload_vdex_name); 1282 std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str())); 1283 std::unique_ptr<File> no_unload_vdex(OS::OpenFileForReading(no_unload_vdex_name.c_str())); 1284 ASSERT_TRUE(no_unload_oat != nullptr); 1285 ASSERT_TRUE(no_unload_vdex != nullptr); 1286 EXPECT_GT(no_unload_oat->GetLength(), 0u); 1287 EXPECT_GT(no_unload_vdex->GetLength(), 0u); 1288 // Verify that both of the files are the same (odex and vdex). 1289 EXPECT_EQ(unload_oat->GetLength(), no_unload_oat->GetLength()); 1290 EXPECT_EQ(unload_vdex->GetLength(), no_unload_vdex->GetLength()); 1291 EXPECT_EQ(unload_oat->Compare(no_unload_oat.get()), 0) 1292 << unload_oat_name << " " << no_unload_oat_name; 1293 EXPECT_EQ(unload_vdex->Compare(no_unload_vdex.get()), 0) 1294 << unload_vdex_name << " " << no_unload_vdex_name; 1295 // App image file. 1296 std::unique_ptr<File> app_image_file(OS::OpenFileForReading(app_image_name.c_str())); 1297 ASSERT_TRUE(app_image_file != nullptr); 1298 EXPECT_GT(app_image_file->GetLength(), 0u); 1299 } 1300 1301 // Test that dexlayout section info is correctly written to the oat file for profile based 1302 // compilation. 1303 TEST_F(Dex2oatTest, LayoutSections) { 1304 using Hotness = ProfileCompilationInfo::MethodHotness; 1305 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods")); 1306 ScratchFile profile_file; 1307 // We can only layout method indices with code items, figure out which ones have this property 1308 // first. 1309 std::vector<uint16_t> methods; 1310 { 1311 const DexFile::TypeId* type_id = dex->FindTypeId("LManyMethods;"); 1312 dex::TypeIndex type_idx = dex->GetIndexForTypeId(*type_id); 1313 const DexFile::ClassDef* class_def = dex->FindClassDef(type_idx); 1314 ClassDataItemIterator it(*dex, dex->GetClassData(*class_def)); 1315 it.SkipAllFields(); 1316 std::set<size_t> code_item_offsets; 1317 for (; it.HasNextMethod(); it.Next()) { 1318 const uint16_t method_idx = it.GetMemberIndex(); 1319 const size_t code_item_offset = it.GetMethodCodeItemOffset(); 1320 if (code_item_offsets.insert(code_item_offset).second) { 1321 // Unique code item, add the method index. 1322 methods.push_back(method_idx); 1323 } 1324 } 1325 DCHECK(!it.HasNext()); 1326 } 1327 ASSERT_GE(methods.size(), 8u); 1328 std::vector<uint16_t> hot_methods = {methods[1], methods[3], methods[5]}; 1329 std::vector<uint16_t> startup_methods = {methods[1], methods[2], methods[7]}; 1330 std::vector<uint16_t> post_methods = {methods[0], methods[2], methods[6]}; 1331 // Here, we build the profile from the method lists. 1332 ProfileCompilationInfo info; 1333 info.AddMethodsForDex( 1334 static_cast<Hotness::Flag>(Hotness::kFlagHot | Hotness::kFlagStartup), 1335 dex.get(), 1336 hot_methods.begin(), 1337 hot_methods.end()); 1338 info.AddMethodsForDex( 1339 Hotness::kFlagStartup, 1340 dex.get(), 1341 startup_methods.begin(), 1342 startup_methods.end()); 1343 info.AddMethodsForDex( 1344 Hotness::kFlagPostStartup, 1345 dex.get(), 1346 post_methods.begin(), 1347 post_methods.end()); 1348 for (uint16_t id : hot_methods) { 1349 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsHot()); 1350 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup()); 1351 } 1352 for (uint16_t id : startup_methods) { 1353 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsStartup()); 1354 } 1355 for (uint16_t id : post_methods) { 1356 EXPECT_TRUE(info.GetMethodHotness(MethodReference(dex.get(), id)).IsPostStartup()); 1357 } 1358 // Save the profile since we want to use it with dex2oat to produce an oat file. 1359 ASSERT_TRUE(info.Save(profile_file.GetFd())); 1360 // Generate a profile based odex. 1361 const std::string dir = GetScratchDir(); 1362 const std::string oat_filename = dir + "/base.oat"; 1363 const std::string vdex_filename = dir + "/base.vdex"; 1364 std::string error_msg; 1365 const int res = GenerateOdexForTestWithStatus( 1366 {dex->GetLocation()}, 1367 oat_filename, 1368 CompilerFilter::Filter::kQuicken, 1369 &error_msg, 1370 {"--profile-file=" + profile_file.GetFilename()}); 1371 EXPECT_EQ(res, 0); 1372 1373 // Open our generated oat file. 1374 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 1375 oat_filename.c_str(), 1376 oat_filename.c_str(), 1377 nullptr, 1378 nullptr, 1379 false, 1380 /*low_4gb*/false, 1381 dex->GetLocation().c_str(), 1382 &error_msg)); 1383 ASSERT_TRUE(odex_file != nullptr); 1384 std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles(); 1385 ASSERT_EQ(oat_dex_files.size(), 1u); 1386 // Check that the code sections match what we expect. 1387 for (const OatDexFile* oat_dex : oat_dex_files) { 1388 const DexLayoutSections* const sections = oat_dex->GetDexLayoutSections(); 1389 // Testing of logging the sections. 1390 ASSERT_TRUE(sections != nullptr); 1391 LOG(INFO) << *sections; 1392 1393 // Load the sections into temporary variables for convenience. 1394 const DexLayoutSection& code_section = 1395 sections->sections_[static_cast<size_t>(DexLayoutSections::SectionType::kSectionTypeCode)]; 1396 const DexLayoutSection::Subsection& section_hot_code = 1397 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeHot)]; 1398 const DexLayoutSection::Subsection& section_sometimes_used = 1399 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeSometimesUsed)]; 1400 const DexLayoutSection::Subsection& section_startup_only = 1401 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeStartupOnly)]; 1402 const DexLayoutSection::Subsection& section_unused = 1403 code_section.parts_[static_cast<size_t>(LayoutType::kLayoutTypeUnused)]; 1404 1405 // All the sections should be non-empty. 1406 EXPECT_GT(section_hot_code.Size(), 0u); 1407 EXPECT_GT(section_sometimes_used.Size(), 0u); 1408 EXPECT_GT(section_startup_only.Size(), 0u); 1409 EXPECT_GT(section_unused.Size(), 0u); 1410 1411 // Open the dex file since we need to peek at the code items to verify the layout matches what 1412 // we expect. 1413 std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg)); 1414 ASSERT_TRUE(dex_file != nullptr) << error_msg; 1415 const DexFile::TypeId* type_id = dex_file->FindTypeId("LManyMethods;"); 1416 ASSERT_TRUE(type_id != nullptr); 1417 dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id); 1418 const DexFile::ClassDef* class_def = dex_file->FindClassDef(type_idx); 1419 ASSERT_TRUE(class_def != nullptr); 1420 1421 // Count how many code items are for each category, there should be at least one per category. 1422 size_t hot_count = 0; 1423 size_t post_startup_count = 0; 1424 size_t startup_count = 0; 1425 size_t unused_count = 0; 1426 // Visit all of the methdos of the main class and cross reference the method indices to their 1427 // corresponding code item offsets to verify the layout. 1428 ClassDataItemIterator it(*dex_file, dex_file->GetClassData(*class_def)); 1429 it.SkipAllFields(); 1430 for (; it.HasNextMethod(); it.Next()) { 1431 const size_t method_idx = it.GetMemberIndex(); 1432 const size_t code_item_offset = it.GetMethodCodeItemOffset(); 1433 const bool is_hot = ContainsElement(hot_methods, method_idx); 1434 const bool is_startup = ContainsElement(startup_methods, method_idx); 1435 const bool is_post_startup = ContainsElement(post_methods, method_idx); 1436 if (is_hot) { 1437 // Hot is highest precedence, check that the hot methods are in the hot section. 1438 EXPECT_TRUE(section_hot_code.Contains(code_item_offset)); 1439 ++hot_count; 1440 } else if (is_post_startup) { 1441 // Post startup is sometimes used section. 1442 EXPECT_TRUE(section_sometimes_used.Contains(code_item_offset)); 1443 ++post_startup_count; 1444 } else if (is_startup) { 1445 // Startup at this point means not hot or post startup, these must be startup only then. 1446 EXPECT_TRUE(section_startup_only.Contains(code_item_offset)); 1447 ++startup_count; 1448 } else { 1449 if (section_unused.Contains(code_item_offset)) { 1450 // If no flags are set, the method should be unused ... 1451 ++unused_count; 1452 } else { 1453 // or this method is part of the last code item and the end is 4 byte aligned. 1454 ClassDataItemIterator it2(*dex_file, dex_file->GetClassData(*class_def)); 1455 it2.SkipAllFields(); 1456 for (; it2.HasNextMethod(); it2.Next()) { 1457 EXPECT_LE(it2.GetMethodCodeItemOffset(), code_item_offset); 1458 } 1459 uint32_t code_item_size = dex_file->FindCodeItemOffset(*class_def, method_idx); 1460 EXPECT_EQ((code_item_offset + code_item_size) % 4, 0u); 1461 } 1462 } 1463 } 1464 DCHECK(!it.HasNext()); 1465 EXPECT_GT(hot_count, 0u); 1466 EXPECT_GT(post_startup_count, 0u); 1467 EXPECT_GT(startup_count, 0u); 1468 EXPECT_GT(unused_count, 0u); 1469 } 1470 } 1471 1472 // Test that generating compact dex works. 1473 TEST_F(Dex2oatTest, GenerateCompactDex) { 1474 // Generate a compact dex based odex. 1475 const std::string dir = GetScratchDir(); 1476 const std::string oat_filename = dir + "/base.oat"; 1477 const std::string vdex_filename = dir + "/base.vdex"; 1478 const std::string dex_location = GetTestDexFileName("MultiDex"); 1479 std::string error_msg; 1480 const int res = GenerateOdexForTestWithStatus( 1481 { dex_location }, 1482 oat_filename, 1483 CompilerFilter::Filter::kQuicken, 1484 &error_msg, 1485 {"--compact-dex-level=fast"}); 1486 EXPECT_EQ(res, 0); 1487 // Open our generated oat file. 1488 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 1489 oat_filename.c_str(), 1490 oat_filename.c_str(), 1491 nullptr, 1492 nullptr, 1493 false, 1494 /*low_4gb*/false, 1495 dex_location.c_str(), 1496 &error_msg)); 1497 ASSERT_TRUE(odex_file != nullptr); 1498 std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles(); 1499 ASSERT_GT(oat_dex_files.size(), 1u); 1500 // Check that each dex is a compact dex file. 1501 std::vector<std::unique_ptr<const CompactDexFile>> compact_dex_files; 1502 for (const OatDexFile* oat_dex : oat_dex_files) { 1503 std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg)); 1504 ASSERT_TRUE(dex_file != nullptr) << error_msg; 1505 ASSERT_TRUE(dex_file->IsCompactDexFile()); 1506 compact_dex_files.push_back( 1507 std::unique_ptr<const CompactDexFile>(dex_file.release()->AsCompactDexFile())); 1508 } 1509 for (const std::unique_ptr<const CompactDexFile>& dex_file : compact_dex_files) { 1510 // Test that every code item is in the owned section. 1511 const CompactDexFile::Header& header = dex_file->GetHeader(); 1512 EXPECT_LE(header.OwnedDataBegin(), header.OwnedDataEnd()); 1513 EXPECT_LE(header.OwnedDataBegin(), header.data_size_); 1514 EXPECT_LE(header.OwnedDataEnd(), header.data_size_); 1515 for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { 1516 const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); 1517 class_def.VisitMethods(dex_file.get(), [&](const ClassDataItemIterator& it) { 1518 if (it.GetMethodCodeItemOffset() != 0u) { 1519 ASSERT_GE(it.GetMethodCodeItemOffset(), header.OwnedDataBegin()); 1520 ASSERT_LT(it.GetMethodCodeItemOffset(), header.OwnedDataEnd()); 1521 } 1522 }); 1523 } 1524 // Test that the owned sections don't overlap. 1525 for (const std::unique_ptr<const CompactDexFile>& other_dex : compact_dex_files) { 1526 if (dex_file != other_dex) { 1527 ASSERT_TRUE( 1528 (dex_file->GetHeader().OwnedDataBegin() >= other_dex->GetHeader().OwnedDataEnd()) || 1529 (dex_file->GetHeader().OwnedDataEnd() <= other_dex->GetHeader().OwnedDataBegin())); 1530 } 1531 } 1532 } 1533 } 1534 1535 class Dex2oatVerifierAbort : public Dex2oatTest {}; 1536 1537 TEST_F(Dex2oatVerifierAbort, HardFail) { 1538 // Use VerifierDeps as it has hard-failing classes. 1539 std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDeps")); 1540 std::string out_dir = GetScratchDir(); 1541 const std::string base_oat_name = out_dir + "/base.oat"; 1542 std::string error_msg; 1543 const int res_fail = GenerateOdexForTestWithStatus( 1544 {dex->GetLocation()}, 1545 base_oat_name, 1546 CompilerFilter::Filter::kQuicken, 1547 &error_msg, 1548 {"--abort-on-hard-verifier-error"}); 1549 EXPECT_NE(0, res_fail); 1550 1551 const int res_no_fail = GenerateOdexForTestWithStatus( 1552 {dex->GetLocation()}, 1553 base_oat_name, 1554 CompilerFilter::Filter::kQuicken, 1555 &error_msg, 1556 {"--no-abort-on-hard-verifier-error"}); 1557 EXPECT_EQ(0, res_no_fail); 1558 } 1559 1560 TEST_F(Dex2oatVerifierAbort, SoftFail) { 1561 // Use VerifierDepsMulti as it has hard-failing classes. 1562 std::unique_ptr<const DexFile> dex(OpenTestDexFile("VerifierDepsMulti")); 1563 std::string out_dir = GetScratchDir(); 1564 const std::string base_oat_name = out_dir + "/base.oat"; 1565 std::string error_msg; 1566 const int res_fail = GenerateOdexForTestWithStatus( 1567 {dex->GetLocation()}, 1568 base_oat_name, 1569 CompilerFilter::Filter::kQuicken, 1570 &error_msg, 1571 {"--abort-on-soft-verifier-error"}); 1572 EXPECT_NE(0, res_fail); 1573 1574 const int res_no_fail = GenerateOdexForTestWithStatus( 1575 {dex->GetLocation()}, 1576 base_oat_name, 1577 CompilerFilter::Filter::kQuicken, 1578 &error_msg, 1579 {"--no-abort-on-soft-verifier-error"}); 1580 EXPECT_EQ(0, res_no_fail); 1581 } 1582 1583 class Dex2oatDedupeCode : public Dex2oatTest {}; 1584 1585 TEST_F(Dex2oatDedupeCode, DedupeTest) { 1586 // Use MyClassNatives. It has lots of native methods that will produce deduplicate-able code. 1587 std::unique_ptr<const DexFile> dex(OpenTestDexFile("MyClassNatives")); 1588 std::string out_dir = GetScratchDir(); 1589 const std::string base_oat_name = out_dir + "/base.oat"; 1590 size_t no_dedupe_size = 0; 1591 GenerateOdexForTest(dex->GetLocation(), 1592 base_oat_name, 1593 CompilerFilter::Filter::kSpeed, 1594 { "--deduplicate-code=false" }, 1595 true, // expect_success 1596 false, // use_fd 1597 [&no_dedupe_size](const OatFile& o) { 1598 no_dedupe_size = o.Size(); 1599 }); 1600 1601 size_t dedupe_size = 0; 1602 GenerateOdexForTest(dex->GetLocation(), 1603 base_oat_name, 1604 CompilerFilter::Filter::kSpeed, 1605 { "--deduplicate-code=true" }, 1606 true, // expect_success 1607 false, // use_fd 1608 [&dedupe_size](const OatFile& o) { 1609 dedupe_size = o.Size(); 1610 }); 1611 1612 EXPECT_LT(dedupe_size, no_dedupe_size); 1613 } 1614 1615 TEST_F(Dex2oatTest, UncompressedTest) { 1616 std::unique_ptr<const DexFile> dex(OpenTestDexFile("MainUncompressed")); 1617 std::string out_dir = GetScratchDir(); 1618 const std::string base_oat_name = out_dir + "/base.oat"; 1619 GenerateOdexForTest(dex->GetLocation(), 1620 base_oat_name, 1621 CompilerFilter::Filter::kQuicken, 1622 { }, 1623 true, // expect_success 1624 false, // use_fd 1625 [](const OatFile& o) { 1626 CHECK(!o.ContainsDexCode()); 1627 }); 1628 } 1629 1630 TEST_F(Dex2oatTest, EmptyUncompressedDexTest) { 1631 std::string out_dir = GetScratchDir(); 1632 const std::string base_oat_name = out_dir + "/base.oat"; 1633 std::string error_msg; 1634 int status = GenerateOdexForTestWithStatus( 1635 { GetTestDexFileName("MainEmptyUncompressed") }, 1636 base_oat_name, 1637 CompilerFilter::Filter::kQuicken, 1638 &error_msg, 1639 { }, 1640 /*use_fd*/ false); 1641 // Expect to fail with code 1 and not SIGSEGV or SIGABRT. 1642 ASSERT_TRUE(WIFEXITED(status)); 1643 ASSERT_EQ(WEXITSTATUS(status), 1) << error_msg; 1644 } 1645 1646 // Dex file that has duplicate methods have different code items and debug info. 1647 static const char kDuplicateMethodInputDex[] = 1648 "ZGV4CjAzOQDEy8VPdj4qHpgPYFWtLCtOykfFP4kB8tGYDAAAcAAAAHhWNBIAAAAAAAAAANALAABI" 1649 "AAAAcAAAAA4AAACQAQAABQAAAMgBAAANAAAABAIAABkAAABsAgAABAAAADQDAADgCAAAuAMAADgI" 1650 "AABCCAAASggAAE8IAABcCAAAaggAAHkIAACICAAAlggAAKQIAACyCAAAwAgAAM4IAADcCAAA6ggA" 1651 "APgIAAD7CAAA/wgAABcJAAAuCQAARQkAAFQJAAB4CQAAmAkAALsJAADSCQAA5gkAAPoJAAAVCgAA" 1652 "KQoAADsKAABCCgAASgoAAFIKAABbCgAAZAoAAGwKAAB0CgAAfAoAAIQKAACMCgAAlAoAAJwKAACk" 1653 "CgAArQoAALcKAADACgAAwwoAAMcKAADcCgAA6QoAAPEKAAD3CgAA/QoAAAMLAAAJCwAAEAsAABcL" 1654 "AAAdCwAAIwsAACkLAAAvCwAANQsAADsLAABBCwAARwsAAE0LAABSCwAAWwsAAF4LAABoCwAAbwsA" 1655 "ABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAC4AAAAwAAAA" 1656 "DwAAAAkAAAAAAAAAEAAAAAoAAACoBwAALgAAAAwAAAAAAAAALwAAAAwAAACoBwAALwAAAAwAAACw" 1657 "BwAAAgAJADUAAAACAAkANgAAAAIACQA3AAAAAgAJADgAAAACAAkAOQAAAAIACQA6AAAAAgAJADsA" 1658 "AAACAAkAPAAAAAIACQA9AAAAAgAJAD4AAAACAAkAPwAAAAIACQBAAAAACwAHAEIAAAAAAAIAAQAA" 1659 "AAAAAwAeAAAAAQACAAEAAAABAAMAHgAAAAIAAgAAAAAAAgACAAEAAAADAAIAAQAAAAMAAgAfAAAA" 1660 "AwACACAAAAADAAIAIQAAAAMAAgAiAAAAAwACACMAAAADAAIAJAAAAAMAAgAlAAAAAwACACYAAAAD" 1661 "AAIAJwAAAAMAAgAoAAAAAwACACkAAAADAAIAKgAAAAMABAA0AAAABwADAEMAAAAIAAIAAQAAAAoA" 1662 "AgABAAAACgABADIAAAAKAAAARQAAAAAAAAAAAAAACAAAAAAAAAAdAAAAaAcAALYHAAAAAAAAAQAA" 1663 "AAAAAAAIAAAAAAAAAB0AAAB4BwAAxAcAAAAAAAACAAAAAAAAAAgAAAAAAAAAHQAAAIgHAADSBwAA" 1664 "AAAAAAMAAAAAAAAACAAAAAAAAAAdAAAAmAcAAPoHAAAAAAAAAAAAAAEAAAAAAAAArAYAADEAAAAa" 1665 "AAMAaQAAABoABABpAAEAGgAHAGkABAAaAAgAaQAFABoACQBpAAYAGgAKAGkABwAaAAsAaQAIABoA" 1666 "DABpAAkAGgANAGkACgAaAA4AaQALABoABQBpAAIAGgAGAGkAAwAOAAAAAQABAAEAAACSBgAABAAA" 1667 "AHAQFQAAAA4ABAABAAIAAACWBgAAFwAAAGIADAAiAQoAcBAWAAEAGgICAG4gFwAhAG4gFwAxAG4Q" 1668 "GAABAAwBbiAUABAADgAAAAEAAQABAAAAngYAAAQAAABwEBUAAAAOAAIAAQACAAAAogYAAAYAAABi" 1669 "AAwAbiAUABAADgABAAEAAQAAAKgGAAAEAAAAcBAVAAAADgABAAEAAQAAALsGAAAEAAAAcBAVAAAA" 1670 "DgABAAAAAQAAAL8GAAAGAAAAYgAAAHEQAwAAAA4AAQAAAAEAAADEBgAABgAAAGIAAQBxEAMAAAAO" 1671 "AAEAAAABAAAA8QYAAAYAAABiAAIAcRABAAAADgABAAAAAQAAAPYGAAAGAAAAYgADAHEQAwAAAA4A" 1672 "AQAAAAEAAADJBgAABgAAAGIABABxEAMAAAAOAAEAAAABAAAAzgYAAAYAAABiAAEAcRADAAAADgAB" 1673 "AAAAAQAAANMGAAAGAAAAYgAGAHEQAwAAAA4AAQAAAAEAAADYBgAABgAAAGIABwBxEAMAAAAOAAEA" 1674 "AAABAAAA3QYAAAYAAABiAAgAcRABAAAADgABAAAAAQAAAOIGAAAGAAAAYgAJAHEQAwAAAA4AAQAA" 1675 "AAEAAADnBgAABgAAAGIACgBxEAMAAAAOAAEAAAABAAAA7AYAAAYAAABiAAsAcRABAAAADgABAAEA" 1676 "AAAAAPsGAAAlAAAAcQAHAAAAcQAIAAAAcQALAAAAcQAMAAAAcQANAAAAcQAOAAAAcQAPAAAAcQAQ" 1677 "AAAAcQARAAAAcQASAAAAcQAJAAAAcQAKAAAADgAnAA4AKQFFDgEWDwAhAA4AIwFFDloAEgAOABMA" 1678 "DktLS0tLS0tLS0tLABEADgAuAA5aADIADloANgAOWgA6AA5aAD4ADloAQgAOWgBGAA5aAEoADloA" 1679 "TgAOWgBSAA5aAFYADloAWgAOWgBeATQOPDw8PDw8PDw8PDw8AAIEAUYYAwIFAjEECEEXLAIFAjEE" 1680 "CEEXKwIFAjEECEEXLQIGAUYcAxgAGAEYAgAAAAIAAAAMBwAAEgcAAAIAAAAMBwAAGwcAAAIAAAAM" 1681 "BwAAJAcAAAEAAAAtBwAAPAcAAAAAAAAAAAAAAAAAAEgHAAAAAAAAAAAAAAAAAABUBwAAAAAAAAAA" 1682 "AAAAAAAAYAcAAAAAAAAAAAAAAAAAAAEAAAAJAAAAAQAAAA0AAAACAACAgASsCAEIxAgAAAIAAoCA" 1683 "BIQJAQicCQwAAgAACQEJAQkBCQEJAQkBCQEJAQkBCQEJAQkEiIAEuAcBgIAEuAkAAA4ABoCABNAJ" 1684 "AQnoCQAJhAoACaAKAAm8CgAJ2AoACfQKAAmQCwAJrAsACcgLAAnkCwAJgAwACZwMAAm4DAg8Y2xp" 1685 "bml0PgAGPGluaXQ+AANBQUEAC0hlbGxvIFdvcmxkAAxIZWxsbyBXb3JsZDEADUhlbGxvIFdvcmxk" 1686 "MTAADUhlbGxvIFdvcmxkMTEADEhlbGxvIFdvcmxkMgAMSGVsbG8gV29ybGQzAAxIZWxsbyBXb3Js" 1687 "ZDQADEhlbGxvIFdvcmxkNQAMSGVsbG8gV29ybGQ2AAxIZWxsbyBXb3JsZDcADEhlbGxvIFdvcmxk" 1688 "OAAMSGVsbG8gV29ybGQ5AAFMAAJMTAAWTE1hbnlNZXRob2RzJFByaW50ZXIyOwAVTE1hbnlNZXRo" 1689 "b2RzJFByaW50ZXI7ABVMTWFueU1ldGhvZHMkU3RyaW5nczsADUxNYW55TWV0aG9kczsAIkxkYWx2" 1690 "aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5lckNs" 1691 "YXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNzZXM7ABVMamF2YS9pby9QcmludFN0" 1692 "cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5n" 1693 "L1N0cmluZ0J1aWxkZXI7ABJMamF2YS9sYW5nL1N5c3RlbTsAEE1hbnlNZXRob2RzLmphdmEABVBy" 1694 "aW50AAZQcmludDAABlByaW50MQAHUHJpbnQxMAAHUHJpbnQxMQAGUHJpbnQyAAZQcmludDMABlBy" 1695 "aW50NAAGUHJpbnQ1AAZQcmludDYABlByaW50NwAGUHJpbnQ4AAZQcmludDkAB1ByaW50ZXIACFBy" 1696 "aW50ZXIyAAdTdHJpbmdzAAFWAAJWTAATW0xqYXZhL2xhbmcvU3RyaW5nOwALYWNjZXNzRmxhZ3MA" 1697 "BmFwcGVuZAAEYXJncwAEbWFpbgAEbXNnMAAEbXNnMQAFbXNnMTAABW1zZzExAARtc2cyAARtc2cz" 1698 "AARtc2c0AARtc2c1AARtc2c2AARtc2c3AARtc2c4AARtc2c5AARuYW1lAANvdXQAB3ByaW50bG4A" 1699 "AXMACHRvU3RyaW5nAAV2YWx1ZQBffn5EOHsibWluLWFwaSI6MTAwMDAsInNoYS0xIjoiZmViODZj" 1700 "MDA2ZWZhY2YxZDc5ODRiODVlMTc5MGZlZjdhNzY3YWViYyIsInZlcnNpb24iOiJ2MS4xLjUtZGV2" 1701 "In0AEAAAAAAAAAABAAAAAAAAAAEAAABIAAAAcAAAAAIAAAAOAAAAkAEAAAMAAAAFAAAAyAEAAAQA" 1702 "AAANAAAABAIAAAUAAAAZAAAAbAIAAAYAAAAEAAAANAMAAAEgAAAUAAAAuAMAAAMgAAAUAAAAkgYA" 1703 "AAQgAAAFAAAADAcAAAMQAAAEAAAAOQcAAAYgAAAEAAAAaAcAAAEQAAACAAAAqAcAAAAgAAAEAAAA" 1704 "tgcAAAIgAABIAAAAOAgAAAAQAAABAAAA0AsAAAAAAAA="; 1705 1706 static void WriteBase64ToFile(const char* base64, File* file) { 1707 // Decode base64. 1708 CHECK(base64 != nullptr); 1709 size_t length; 1710 std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length)); 1711 CHECK(bytes != nullptr); 1712 if (!file->WriteFully(bytes.get(), length)) { 1713 PLOG(FATAL) << "Failed to write base64 as file"; 1714 } 1715 } 1716 1717 TEST_F(Dex2oatTest, CompactDexGenerationFailure) { 1718 ScratchFile temp_dex; 1719 WriteBase64ToFile(kDuplicateMethodInputDex, temp_dex.GetFile()); 1720 std::string out_dir = GetScratchDir(); 1721 const std::string oat_filename = out_dir + "/base.oat"; 1722 // The dex won't pass the method verifier, only use the verify filter. 1723 GenerateOdexForTest(temp_dex.GetFilename(), 1724 oat_filename, 1725 CompilerFilter::Filter::kVerify, 1726 { }, 1727 true, // expect_success 1728 false, // use_fd 1729 [](const OatFile& o) { 1730 CHECK(o.ContainsDexCode()); 1731 }); 1732 // Open our generated oat file. 1733 std::string error_msg; 1734 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 1735 oat_filename.c_str(), 1736 oat_filename.c_str(), 1737 nullptr, 1738 nullptr, 1739 false, 1740 /*low_4gb*/false, 1741 temp_dex.GetFilename().c_str(), 1742 &error_msg)); 1743 ASSERT_TRUE(odex_file != nullptr); 1744 std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles(); 1745 ASSERT_EQ(oat_dex_files.size(), 1u); 1746 // The dexes should have failed to convert to compact dex. 1747 for (const OatDexFile* oat_dex : oat_dex_files) { 1748 std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg)); 1749 ASSERT_TRUE(dex_file != nullptr) << error_msg; 1750 ASSERT_TRUE(!dex_file->IsCompactDexFile()); 1751 } 1752 } 1753 1754 TEST_F(Dex2oatTest, CompactDexGenerationFailureMultiDex) { 1755 // Create a multidex file with only one dex that gets rejected for cdex conversion. 1756 ScratchFile apk_file; 1757 { 1758 FILE* file = fdopen(apk_file.GetFd(), "w+b"); 1759 ZipWriter writer(file); 1760 // Add vdex to zip. 1761 writer.StartEntry("classes.dex", ZipWriter::kCompress); 1762 size_t length = 0u; 1763 std::unique_ptr<uint8_t[]> bytes(DecodeBase64(kDuplicateMethodInputDex, &length)); 1764 ASSERT_GE(writer.WriteBytes(&bytes[0], length), 0); 1765 writer.FinishEntry(); 1766 writer.StartEntry("classes2.dex", ZipWriter::kCompress); 1767 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods")); 1768 ASSERT_GE(writer.WriteBytes(dex->Begin(), dex->Size()), 0); 1769 writer.FinishEntry(); 1770 writer.Finish(); 1771 ASSERT_EQ(apk_file.GetFile()->Flush(), 0); 1772 } 1773 const std::string dex_location = apk_file.GetFilename(); 1774 const std::string odex_location = GetOdexDir() + "/output.odex"; 1775 GenerateOdexForTest(dex_location, 1776 odex_location, 1777 CompilerFilter::kQuicken, 1778 { "--compact-dex-level=fast" }, 1779 true); 1780 } 1781 1782 TEST_F(Dex2oatTest, StderrLoggerOutput) { 1783 std::string dex_location = GetScratchDir() + "/Dex2OatStderrLoggerTest.jar"; 1784 std::string odex_location = GetOdexDir() + "/Dex2OatStderrLoggerTest.odex"; 1785 1786 // Test file doesn't matter. 1787 Copy(GetDexSrc1(), dex_location); 1788 1789 GenerateOdexForTest(dex_location, 1790 odex_location, 1791 CompilerFilter::kQuicken, 1792 { "--runtime-arg", "-Xuse-stderr-logger" }, 1793 true); 1794 // Look for some random part of dex2oat logging. With the stderr logger this should be captured, 1795 // even on device. 1796 EXPECT_NE(std::string::npos, output_.find("dex2oat took")); 1797 } 1798 1799 TEST_F(Dex2oatTest, VerifyCompilationReason) { 1800 std::string dex_location = GetScratchDir() + "/Dex2OatCompilationReason.jar"; 1801 std::string odex_location = GetOdexDir() + "/Dex2OatCompilationReason.odex"; 1802 1803 // Test file doesn't matter. 1804 Copy(GetDexSrc1(), dex_location); 1805 1806 GenerateOdexForTest(dex_location, 1807 odex_location, 1808 CompilerFilter::kVerify, 1809 { "--compilation-reason=install" }, 1810 true); 1811 std::string error_msg; 1812 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 1813 odex_location.c_str(), 1814 odex_location.c_str(), 1815 nullptr, 1816 nullptr, 1817 false, 1818 /*low_4gb*/false, 1819 dex_location.c_str(), 1820 &error_msg)); 1821 ASSERT_TRUE(odex_file != nullptr); 1822 ASSERT_STREQ("install", odex_file->GetCompilationReason()); 1823 } 1824 1825 TEST_F(Dex2oatTest, VerifyNoCompilationReason) { 1826 std::string dex_location = GetScratchDir() + "/Dex2OatNoCompilationReason.jar"; 1827 std::string odex_location = GetOdexDir() + "/Dex2OatNoCompilationReason.odex"; 1828 1829 // Test file doesn't matter. 1830 Copy(GetDexSrc1(), dex_location); 1831 1832 GenerateOdexForTest(dex_location, 1833 odex_location, 1834 CompilerFilter::kVerify, 1835 {}, 1836 true); 1837 std::string error_msg; 1838 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 1839 odex_location.c_str(), 1840 odex_location.c_str(), 1841 nullptr, 1842 nullptr, 1843 false, 1844 /*low_4gb*/false, 1845 dex_location.c_str(), 1846 &error_msg)); 1847 ASSERT_TRUE(odex_file != nullptr); 1848 ASSERT_EQ(nullptr, odex_file->GetCompilationReason()); 1849 } 1850 1851 TEST_F(Dex2oatTest, DontExtract) { 1852 std::unique_ptr<const DexFile> dex(OpenTestDexFile("ManyMethods")); 1853 std::string error_msg; 1854 const std::string out_dir = GetScratchDir(); 1855 const std::string dex_location = dex->GetLocation(); 1856 const std::string odex_location = out_dir + "/base.oat"; 1857 const std::string vdex_location = out_dir + "/base.vdex"; 1858 GenerateOdexForTest(dex_location, 1859 odex_location, 1860 CompilerFilter::Filter::kVerify, 1861 { "--copy-dex-files=false" }, 1862 true, // expect_success 1863 false, // use_fd 1864 [](const OatFile&) { 1865 }); 1866 { 1867 // Check the vdex doesn't have dex. 1868 std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(), 1869 /*writable*/ false, 1870 /*low_4gb*/ false, 1871 /*unquicken*/ false, 1872 &error_msg)); 1873 ASSERT_TRUE(vdex != nullptr); 1874 EXPECT_FALSE(vdex->HasDexSection()) << output_; 1875 } 1876 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 1877 odex_location.c_str(), 1878 odex_location.c_str(), 1879 nullptr, 1880 nullptr, 1881 false, 1882 /*low_4gb*/ false, 1883 dex_location.c_str(), 1884 &error_msg)); 1885 ASSERT_TRUE(odex_file != nullptr) << dex_location; 1886 std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles(); 1887 ASSERT_EQ(oat_dex_files.size(), 1u); 1888 // Verify that the oat file can still open the dex files. 1889 for (const OatDexFile* oat_dex : oat_dex_files) { 1890 std::unique_ptr<const DexFile> dex_file(oat_dex->OpenDexFile(&error_msg)); 1891 ASSERT_TRUE(dex_file != nullptr) << error_msg; 1892 } 1893 // Create a dm file and use it to verify. 1894 // Add produced artifacts to a zip file that doesn't contain the classes.dex. 1895 ScratchFile dm_file; 1896 { 1897 std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_location.c_str())); 1898 ASSERT_TRUE(vdex_file != nullptr); 1899 ASSERT_GT(vdex_file->GetLength(), 0u); 1900 FILE* file = fdopen(dm_file.GetFd(), "w+b"); 1901 ZipWriter writer(file); 1902 auto write_all_bytes = [&](File* file) { 1903 std::unique_ptr<uint8_t[]> bytes(new uint8_t[file->GetLength()]); 1904 ASSERT_TRUE(file->ReadFully(&bytes[0], file->GetLength())); 1905 ASSERT_GE(writer.WriteBytes(&bytes[0], file->GetLength()), 0); 1906 }; 1907 // Add vdex to zip. 1908 writer.StartEntry(VdexFile::kVdexNameInDmFile, ZipWriter::kCompress); 1909 write_all_bytes(vdex_file.get()); 1910 writer.FinishEntry(); 1911 writer.Finish(); 1912 ASSERT_EQ(dm_file.GetFile()->Flush(), 0); 1913 } 1914 1915 // Generate a quickened dex by using the input dm file to verify. 1916 GenerateOdexForTest(dex_location, 1917 odex_location, 1918 CompilerFilter::Filter::kQuicken, 1919 { "--dump-timings", 1920 "--dm-file=" + dm_file.GetFilename(), 1921 // Pass -Xuse-stderr-logger have dex2oat output in output_ on target. 1922 "--runtime-arg", 1923 "-Xuse-stderr-logger" }, 1924 true, // expect_success 1925 false, // use_fd 1926 [](const OatFile& o) { 1927 CHECK(o.ContainsDexCode()); 1928 }); 1929 // Check the output for "Fast verify", this is printed from --dump-timings. 1930 std::istringstream iss(output_); 1931 std::string line; 1932 bool found_fast_verify = false; 1933 const std::string kFastVerifyString = "Fast Verify"; 1934 while (std::getline(iss, line) && !found_fast_verify) { 1935 found_fast_verify = found_fast_verify || line.find(kFastVerifyString) != std::string::npos; 1936 } 1937 EXPECT_TRUE(found_fast_verify) << "Expected to find " << kFastVerifyString << "\n" << output_; 1938 } 1939 1940 // Test that dex files with quickened opcodes aren't dequickened. 1941 TEST_F(Dex2oatTest, QuickenedInput) { 1942 std::string error_msg; 1943 ScratchFile temp_dex; 1944 MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [] (DexFile* dex) { 1945 bool mutated_successfully = false; 1946 // Change the dex instructions to make an opcode that spans past the end of the code item. 1947 for (size_t i = 0; i < dex->NumClassDefs(); ++i) { 1948 const DexFile::ClassDef& def = dex->GetClassDef(i); 1949 const uint8_t* data = dex->GetClassData(def); 1950 if (data == nullptr) { 1951 continue; 1952 } 1953 ClassDataItemIterator it(*dex, data); 1954 it.SkipAllFields(); 1955 while (it.HasNextMethod()) { 1956 DexFile::CodeItem* item = const_cast<DexFile::CodeItem*>(it.GetMethodCodeItem()); 1957 if (item != nullptr) { 1958 CodeItemInstructionAccessor instructions(*dex, item); 1959 // Make a quickened instruction that doesn't run past the end of the code item. 1960 if (instructions.InsnsSizeInCodeUnits() > 2) { 1961 const_cast<Instruction&>(instructions.InstructionAt(0)).SetOpcode( 1962 Instruction::IGET_BYTE_QUICK); 1963 mutated_successfully = true; 1964 } 1965 } 1966 it.Next(); 1967 } 1968 } 1969 CHECK(mutated_successfully) 1970 << "Failed to find candidate code item with only one code unit in last instruction."; 1971 }); 1972 1973 std::string dex_location = temp_dex.GetFilename(); 1974 std::string odex_location = GetOdexDir() + "/quickened.odex"; 1975 std::string vdex_location = GetOdexDir() + "/quickened.vdex"; 1976 std::unique_ptr<File> vdex_output(OS::CreateEmptyFile(vdex_location.c_str())); 1977 // Quicken the dex 1978 { 1979 std::string input_vdex = "--input-vdex-fd=-1"; 1980 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_output->Fd()); 1981 GenerateOdexForTest(dex_location, 1982 odex_location, 1983 CompilerFilter::kQuicken, 1984 // Disable cdex since we want to compare against the original dex file 1985 // after unquickening. 1986 { input_vdex, output_vdex, kDisableCompactDex }, 1987 /* expect_success */ true, 1988 /* use_fd */ true); 1989 } 1990 // Unquicken by running the verify compiler filter on the vdex file and verify it matches. 1991 std::string odex_location2 = GetOdexDir() + "/unquickened.odex"; 1992 std::string vdex_location2 = GetOdexDir() + "/unquickened.vdex"; 1993 std::unique_ptr<File> vdex_unquickened(OS::CreateEmptyFile(vdex_location2.c_str())); 1994 { 1995 std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_output->Fd()); 1996 std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_unquickened->Fd()); 1997 GenerateOdexForTest(dex_location, 1998 odex_location2, 1999 CompilerFilter::kVerify, 2000 // Disable cdex to avoid needing to write out the shared section. 2001 { input_vdex, output_vdex, kDisableCompactDex }, 2002 /* expect_success */ true, 2003 /* use_fd */ true); 2004 } 2005 ASSERT_EQ(vdex_unquickened->Flush(), 0) << "Could not flush and close vdex file"; 2006 ASSERT_TRUE(success_); 2007 { 2008 // Check that hte vdex has one dex and compare it to the original one. 2009 std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location2.c_str(), 2010 /*writable*/ false, 2011 /*low_4gb*/ false, 2012 /*unquicken*/ false, 2013 &error_msg)); 2014 std::vector<std::unique_ptr<const DexFile>> dex_files; 2015 bool result = vdex->OpenAllDexFiles(&dex_files, &error_msg); 2016 ASSERT_TRUE(result) << error_msg; 2017 ASSERT_EQ(dex_files.size(), 1u) << error_msg; 2018 ScratchFile temp; 2019 ASSERT_TRUE(temp.GetFile()->WriteFully(dex_files[0]->Begin(), dex_files[0]->Size())); 2020 ASSERT_EQ(temp.GetFile()->Flush(), 0) << "Could not flush extracted dex"; 2021 EXPECT_EQ(temp.GetFile()->Compare(temp_dex.GetFile()), 0); 2022 } 2023 ASSERT_EQ(vdex_output->FlushCloseOrErase(), 0) << "Could not flush and close"; 2024 ASSERT_EQ(vdex_unquickened->FlushCloseOrErase(), 0) << "Could not flush and close"; 2025 } 2026 2027 // Test that compact dex generation with invalid dex files doesn't crash dex2oat. b/75970654 2028 TEST_F(Dex2oatTest, CompactDexInvalidSource) { 2029 ScratchFile invalid_dex; 2030 { 2031 FILE* file = fdopen(invalid_dex.GetFd(), "w+b"); 2032 ZipWriter writer(file); 2033 writer.StartEntry("classes.dex", ZipWriter::kAlign32); 2034 DexFile::Header header = {}; 2035 StandardDexFile::WriteMagic(header.magic_); 2036 StandardDexFile::WriteCurrentVersion(header.magic_); 2037 header.file_size_ = 4 * KB; 2038 header.data_size_ = 4 * KB; 2039 header.data_off_ = 10 * MB; 2040 header.map_off_ = 10 * MB; 2041 header.class_defs_off_ = 10 * MB; 2042 header.class_defs_size_ = 10000; 2043 ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0); 2044 writer.FinishEntry(); 2045 writer.Finish(); 2046 ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0); 2047 } 2048 const std::string dex_location = invalid_dex.GetFilename(); 2049 const std::string odex_location = GetOdexDir() + "/output.odex"; 2050 std::string error_msg; 2051 int status = GenerateOdexForTestWithStatus( 2052 {dex_location}, 2053 odex_location, 2054 CompilerFilter::kQuicken, 2055 &error_msg, 2056 { "--compact-dex-level=fast" }); 2057 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_; 2058 } 2059 2060 // Test that dex2oat with a CompactDex file in the APK fails. 2061 TEST_F(Dex2oatTest, CompactDexInZip) { 2062 CompactDexFile::Header header = {}; 2063 CompactDexFile::WriteMagic(header.magic_); 2064 CompactDexFile::WriteCurrentVersion(header.magic_); 2065 header.file_size_ = sizeof(CompactDexFile::Header); 2066 header.data_off_ = 10 * MB; 2067 header.map_off_ = 10 * MB; 2068 header.class_defs_off_ = 10 * MB; 2069 header.class_defs_size_ = 10000; 2070 // Create a zip containing the invalid dex. 2071 ScratchFile invalid_dex_zip; 2072 { 2073 FILE* file = fdopen(invalid_dex_zip.GetFd(), "w+b"); 2074 ZipWriter writer(file); 2075 writer.StartEntry("classes.dex", ZipWriter::kCompress); 2076 ASSERT_GE(writer.WriteBytes(&header, sizeof(header)), 0); 2077 writer.FinishEntry(); 2078 writer.Finish(); 2079 ASSERT_EQ(invalid_dex_zip.GetFile()->Flush(), 0); 2080 } 2081 // Create the dex file directly. 2082 ScratchFile invalid_dex; 2083 { 2084 ASSERT_GE(invalid_dex.GetFile()->WriteFully(&header, sizeof(header)), 0); 2085 ASSERT_EQ(invalid_dex.GetFile()->Flush(), 0); 2086 } 2087 std::string error_msg; 2088 int status = 0u; 2089 2090 status = GenerateOdexForTestWithStatus( 2091 { invalid_dex_zip.GetFilename() }, 2092 GetOdexDir() + "/output_apk.odex", 2093 CompilerFilter::kQuicken, 2094 &error_msg, 2095 { "--compact-dex-level=fast" }); 2096 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_; 2097 2098 status = GenerateOdexForTestWithStatus( 2099 { invalid_dex.GetFilename() }, 2100 GetOdexDir() + "/output.odex", 2101 CompilerFilter::kQuicken, 2102 &error_msg, 2103 { "--compact-dex-level=fast" }); 2104 ASSERT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) != 0) << status << " " << output_; 2105 } 2106 2107 TEST_F(Dex2oatTest, AppImageNoProfile) { 2108 ScratchFile app_image_file; 2109 const std::string out_dir = GetScratchDir(); 2110 const std::string odex_location = out_dir + "/base.odex"; 2111 GenerateOdexForTest(GetTestDexFileName("ManyMethods"), 2112 odex_location, 2113 CompilerFilter::Filter::kSpeedProfile, 2114 { "--app-image-fd=" + std::to_string(app_image_file.GetFd()) }, 2115 true, // expect_success 2116 false, // use_fd 2117 [](const OatFile&) {}); 2118 // Open our generated oat file. 2119 std::string error_msg; 2120 std::unique_ptr<OatFile> odex_file(OatFile::Open(/* zip_fd */ -1, 2121 odex_location.c_str(), 2122 odex_location.c_str(), 2123 nullptr, 2124 nullptr, 2125 false, 2126 /*low_4gb*/false, 2127 odex_location.c_str(), 2128 &error_msg)); 2129 ASSERT_TRUE(odex_file != nullptr); 2130 ImageHeader header = {}; 2131 ASSERT_TRUE(app_image_file.GetFile()->PreadFully( 2132 reinterpret_cast<void*>(&header), 2133 sizeof(header), 2134 /*offset*/ 0u)) << app_image_file.GetFile()->GetLength(); 2135 EXPECT_GT(header.GetImageSection(ImageHeader::kSectionObjects).Size(), 0u); 2136 EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtMethods).Size(), 0u); 2137 EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u); 2138 } 2139 2140 TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) { 2141 std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex"); 2142 const std::string out_dir = GetScratchDir(); 2143 const std::string odex_location = out_dir + "/base.odex"; 2144 const std::string valid_context = "PCL[" + dex_files[0]->GetLocation() + "]"; 2145 const std::string stored_context = "PCL[/system/not_real_lib.jar]"; 2146 std::string expected_stored_context = "PCL["; 2147 size_t index = 1; 2148 for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { 2149 const bool is_first = index == 1u; 2150 if (!is_first) { 2151 expected_stored_context += ":"; 2152 } 2153 expected_stored_context += "/system/not_real_lib.jar"; 2154 if (!is_first) { 2155 expected_stored_context += "!classes" + std::to_string(index) + ".dex"; 2156 } 2157 expected_stored_context += "*" + std::to_string(dex_file->GetLocationChecksum()); 2158 ++index; 2159 } 2160 expected_stored_context += + "]"; 2161 // The class path should not be valid and should fail being stored. 2162 GenerateOdexForTest(GetTestDexFileName("ManyMethods"), 2163 odex_location, 2164 CompilerFilter::Filter::kQuicken, 2165 { "--class-loader-context=" + stored_context }, 2166 true, // expect_success 2167 false, // use_fd 2168 [&](const OatFile& oat_file) { 2169 EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_; 2170 EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_; 2171 }); 2172 // The stored context should match what we expect even though it's invalid. 2173 GenerateOdexForTest(GetTestDexFileName("ManyMethods"), 2174 odex_location, 2175 CompilerFilter::Filter::kQuicken, 2176 { "--class-loader-context=" + valid_context, 2177 "--stored-class-loader-context=" + stored_context }, 2178 true, // expect_success 2179 false, // use_fd 2180 [&](const OatFile& oat_file) { 2181 EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_; 2182 }); 2183 } 2184 2185 } // namespace art 2186