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