oat_file_assistant.cc revision 9b994ea841eaaefbdda652251894a74db9cefcc8
1/* 2 * Copyright (C) 2014 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 "oat_file_assistant.h" 18 19#include <fcntl.h> 20#ifdef __linux__ 21#include <sys/sendfile.h> 22#else 23#include <sys/socket.h> 24#endif 25#include <sys/types.h> 26#include <sys/stat.h> 27#include <unistd.h> 28 29#include <set> 30 31#include "base/logging.h" 32#include "base/stringprintf.h" 33#include "class_linker.h" 34#include "gc/heap.h" 35#include "gc/space/image_space.h" 36#include "image.h" 37#include "oat.h" 38#include "os.h" 39#include "profiler.h" 40#include "runtime.h" 41#include "ScopedFd.h" 42#include "utils.h" 43 44namespace art { 45 46OatFileAssistant::OatFileAssistant(const char* dex_location, 47 const InstructionSet isa, 48 bool load_executable) 49 : OatFileAssistant(dex_location, nullptr, isa, load_executable, nullptr) { } 50 51OatFileAssistant::OatFileAssistant(const char* dex_location, 52 const char* oat_location, 53 const InstructionSet isa, 54 bool load_executable) 55 : OatFileAssistant(dex_location, oat_location, isa, load_executable, nullptr) { } 56 57OatFileAssistant::OatFileAssistant(const char* dex_location, 58 const InstructionSet isa, 59 bool load_executable, 60 const char* package_name) 61 : OatFileAssistant(dex_location, nullptr, isa, load_executable, package_name) { } 62 63OatFileAssistant::OatFileAssistant(const char* dex_location, 64 const char* oat_location, 65 const InstructionSet isa, 66 bool load_executable, 67 const char* package_name) 68 : dex_location_(dex_location), isa_(isa), 69 package_name_(package_name), load_executable_(load_executable) { 70 if (load_executable_ && isa != kRuntimeISA) { 71 LOG(WARNING) << "OatFileAssistant: Load executable specified, " 72 << "but isa is not kRuntimeISA. Will not attempt to load executable."; 73 load_executable_ = false; 74 } 75 76 // If the user gave a target oat location, save that as the cached oat 77 // location now so we won't try to construct the default location later. 78 if (oat_location != nullptr) { 79 cached_oat_file_name_ = std::string(oat_location); 80 cached_oat_file_name_attempted_ = true; 81 cached_oat_file_name_found_ = true; 82 } 83 84 // If there is no package name given, we will not be able to find any 85 // profiles associated with this dex location. Preemptively mark that to 86 // be the case, rather than trying to find and load the profiles later. 87 // Similarly, if profiling is disabled. 88 if (package_name == nullptr 89 || !Runtime::Current()->GetProfilerOptions().IsEnabled()) { 90 profile_load_attempted_ = true; 91 profile_load_succeeded_ = false; 92 old_profile_load_attempted_ = true; 93 old_profile_load_succeeded_ = false; 94 } 95} 96 97OatFileAssistant::~OatFileAssistant() { 98 // Clean up the lock file. 99 if (flock_.HasFile()) { 100 TEMP_FAILURE_RETRY(unlink(flock_.GetFile()->GetPath().c_str())); 101 } 102} 103 104bool OatFileAssistant::IsInBootClassPath() { 105 // Note: We check the current boot class path, regardless of the ISA 106 // specified by the user. This is okay, because the boot class path should 107 // be the same for all ISAs. 108 // TODO: Can we verify the boot class path is the same for all ISAs? 109 Runtime* runtime = Runtime::Current(); 110 ClassLinker* class_linker = runtime->GetClassLinker(); 111 const auto& boot_class_path = class_linker->GetBootClassPath(); 112 for (size_t i = 0; i < boot_class_path.size(); i++) { 113 if (boot_class_path[i]->GetLocation() == std::string(dex_location_)) { 114 VLOG(oat) << "Dex location " << dex_location_ << " is in boot class path"; 115 return true; 116 } 117 } 118 return false; 119} 120 121bool OatFileAssistant::Lock(std::string* error_msg) { 122 CHECK(error_msg != nullptr); 123 CHECK(!flock_.HasFile()) << "OatFileAssistant::Lock already acquired"; 124 125 if (OatFileName() == nullptr) { 126 *error_msg = "Failed to determine lock file"; 127 return false; 128 } 129 std::string lock_file_name = *OatFileName() + ".flock"; 130 131 if (!flock_.Init(lock_file_name.c_str(), error_msg)) { 132 TEMP_FAILURE_RETRY(unlink(lock_file_name.c_str())); 133 return false; 134 } 135 return true; 136} 137 138OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded() { 139 // TODO: If the profiling code is ever restored, it's worth considering 140 // whether we should check to see if the profile is out of date here. 141 142 if (OatFileIsUpToDate() || OdexFileIsUpToDate()) { 143 return kNoDexOptNeeded; 144 } 145 146 if (OdexFileNeedsRelocation()) { 147 return kPatchOatNeeded; 148 } 149 150 if (OatFileNeedsRelocation()) { 151 return kSelfPatchOatNeeded; 152 } 153 154 return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded; 155} 156 157bool OatFileAssistant::MakeUpToDate(std::string* error_msg) { 158 switch (GetDexOptNeeded()) { 159 case kNoDexOptNeeded: return true; 160 case kDex2OatNeeded: return GenerateOatFile(error_msg); 161 case kPatchOatNeeded: return RelocateOatFile(OdexFileName(), error_msg); 162 case kSelfPatchOatNeeded: return RelocateOatFile(OatFileName(), error_msg); 163 } 164 UNREACHABLE(); 165} 166 167std::unique_ptr<OatFile> OatFileAssistant::GetBestOatFile() { 168 if (OatFileIsUpToDate()) { 169 oat_file_released_ = true; 170 return std::move(cached_oat_file_); 171 } 172 173 if (OdexFileIsUpToDate()) { 174 oat_file_released_ = true; 175 return std::move(cached_odex_file_); 176 } 177 178 if (load_executable_) { 179 VLOG(oat) << "Oat File Assistant: No relocated oat file found," 180 << " attempting to fall back to interpreting oat file instead."; 181 182 if (!OatFileIsOutOfDate()) { 183 load_executable_ = false; 184 ClearOatFileCache(); 185 if (!OatFileIsOutOfDate()) { 186 oat_file_released_ = true; 187 return std::move(cached_oat_file_); 188 } 189 } 190 191 if (!OdexFileIsOutOfDate()) { 192 load_executable_ = false; 193 ClearOdexFileCache(); 194 if (!OdexFileIsOutOfDate()) { 195 oat_file_released_ = true; 196 return std::move(cached_odex_file_); 197 } 198 } 199 } 200 201 return std::unique_ptr<OatFile>(); 202} 203 204std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles( 205 const OatFile& oat_file, const char* dex_location) { 206 std::vector<std::unique_ptr<const DexFile>> dex_files; 207 208 // Load the primary dex file. 209 std::string error_msg; 210 const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile( 211 dex_location, nullptr, false); 212 if (oat_dex_file == nullptr) { 213 LOG(WARNING) << "Attempt to load out-of-date oat file " 214 << oat_file.GetLocation() << " for dex location " << dex_location; 215 return std::vector<std::unique_ptr<const DexFile>>(); 216 } 217 218 std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error_msg); 219 if (dex_file.get() == nullptr) { 220 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg; 221 return std::vector<std::unique_ptr<const DexFile>>(); 222 } 223 dex_files.push_back(std::move(dex_file)); 224 225 // Load secondary multidex files 226 for (size_t i = 1; ; i++) { 227 std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location); 228 oat_dex_file = oat_file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false); 229 if (oat_dex_file == nullptr) { 230 // There are no more secondary dex files to load. 231 break; 232 } 233 234 dex_file = oat_dex_file->OpenDexFile(&error_msg); 235 if (dex_file.get() == nullptr) { 236 LOG(WARNING) << "Failed to open dex file from oat dex file: " << error_msg; 237 return std::vector<std::unique_ptr<const DexFile>>(); 238 } 239 dex_files.push_back(std::move(dex_file)); 240 } 241 return dex_files; 242} 243 244bool OatFileAssistant::HasOriginalDexFiles() { 245 // Ensure GetRequiredDexChecksum has been run so that 246 // has_original_dex_files_ is initialized. We don't care about the result of 247 // GetRequiredDexChecksum. 248 GetRequiredDexChecksum(); 249 return has_original_dex_files_; 250} 251 252const std::string* OatFileAssistant::OdexFileName() { 253 if (!cached_odex_file_name_attempted_) { 254 CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location"; 255 cached_odex_file_name_attempted_ = true; 256 257 std::string error_msg; 258 cached_odex_file_name_found_ = DexFilenameToOdexFilename( 259 dex_location_, isa_, &cached_odex_file_name_, &error_msg); 260 if (!cached_odex_file_name_found_) { 261 // If we can't figure out the odex file, we treat it as if the odex 262 // file was inaccessible. 263 LOG(WARNING) << "Failed to determine odex file name: " << error_msg; 264 } 265 } 266 return cached_odex_file_name_found_ ? &cached_odex_file_name_ : nullptr; 267} 268 269bool OatFileAssistant::OdexFileExists() { 270 return GetOdexFile() != nullptr; 271} 272 273OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() { 274 if (OdexFileIsOutOfDate()) { 275 return kOatOutOfDate; 276 } 277 if (OdexFileIsUpToDate()) { 278 return kOatUpToDate; 279 } 280 return kOatNeedsRelocation; 281} 282 283bool OatFileAssistant::OdexFileIsOutOfDate() { 284 if (!odex_file_is_out_of_date_attempted_) { 285 odex_file_is_out_of_date_attempted_ = true; 286 const OatFile* odex_file = GetOdexFile(); 287 if (odex_file == nullptr) { 288 cached_odex_file_is_out_of_date_ = true; 289 } else { 290 cached_odex_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*odex_file); 291 } 292 } 293 return cached_odex_file_is_out_of_date_; 294} 295 296bool OatFileAssistant::OdexFileNeedsRelocation() { 297 return OdexFileStatus() == kOatNeedsRelocation; 298} 299 300bool OatFileAssistant::OdexFileIsUpToDate() { 301 if (!odex_file_is_up_to_date_attempted_) { 302 odex_file_is_up_to_date_attempted_ = true; 303 const OatFile* odex_file = GetOdexFile(); 304 if (odex_file == nullptr) { 305 cached_odex_file_is_up_to_date_ = false; 306 } else { 307 cached_odex_file_is_up_to_date_ = GivenOatFileIsUpToDate(*odex_file); 308 } 309 } 310 return cached_odex_file_is_up_to_date_; 311} 312 313const std::string* OatFileAssistant::OatFileName() { 314 if (!cached_oat_file_name_attempted_) { 315 cached_oat_file_name_attempted_ = true; 316 317 // Compute the oat file name from the dex location. 318 CHECK(dex_location_ != nullptr) << "OatFileAssistant: null dex location"; 319 320 // TODO: The oat file assistant should be the definitive place for 321 // determining the oat file name from the dex location, not 322 // GetDalvikCacheFilename. 323 std::string cache_dir = StringPrintf("%s%s", 324 DalvikCacheDirectory().c_str(), GetInstructionSetString(isa_)); 325 std::string error_msg; 326 cached_oat_file_name_found_ = GetDalvikCacheFilename(dex_location_, 327 cache_dir.c_str(), &cached_oat_file_name_, &error_msg); 328 if (!cached_oat_file_name_found_) { 329 // If we can't determine the oat file name, we treat the oat file as 330 // inaccessible. 331 LOG(WARNING) << "Failed to determine oat file name for dex location " 332 << dex_location_ << ": " << error_msg; 333 } 334 } 335 return cached_oat_file_name_found_ ? &cached_oat_file_name_ : nullptr; 336} 337 338bool OatFileAssistant::OatFileExists() { 339 return GetOatFile() != nullptr; 340} 341 342OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() { 343 if (OatFileIsOutOfDate()) { 344 return kOatOutOfDate; 345 } 346 if (OatFileIsUpToDate()) { 347 return kOatUpToDate; 348 } 349 return kOatNeedsRelocation; 350} 351 352bool OatFileAssistant::OatFileIsOutOfDate() { 353 if (!oat_file_is_out_of_date_attempted_) { 354 oat_file_is_out_of_date_attempted_ = true; 355 const OatFile* oat_file = GetOatFile(); 356 if (oat_file == nullptr) { 357 cached_oat_file_is_out_of_date_ = true; 358 } else { 359 cached_oat_file_is_out_of_date_ = GivenOatFileIsOutOfDate(*oat_file); 360 } 361 } 362 return cached_oat_file_is_out_of_date_; 363} 364 365bool OatFileAssistant::OatFileNeedsRelocation() { 366 return OatFileStatus() == kOatNeedsRelocation; 367} 368 369bool OatFileAssistant::OatFileIsUpToDate() { 370 if (!oat_file_is_up_to_date_attempted_) { 371 oat_file_is_up_to_date_attempted_ = true; 372 const OatFile* oat_file = GetOatFile(); 373 if (oat_file == nullptr) { 374 cached_oat_file_is_up_to_date_ = false; 375 } else { 376 cached_oat_file_is_up_to_date_ = GivenOatFileIsUpToDate(*oat_file); 377 } 378 } 379 return cached_oat_file_is_up_to_date_; 380} 381 382OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) { 383 // TODO: This could cause GivenOatFileIsOutOfDate to be called twice, which 384 // is more work than we need to do. If performance becomes a concern, and 385 // this method is actually called, this should be fixed. 386 if (GivenOatFileIsOutOfDate(file)) { 387 return kOatOutOfDate; 388 } 389 if (GivenOatFileIsUpToDate(file)) { 390 return kOatUpToDate; 391 } 392 return kOatNeedsRelocation; 393} 394 395bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) { 396 // Verify the dex checksum. 397 // Note: GetOatDexFile will return null if the dex checksum doesn't match 398 // what we provide, which verifies the primary dex checksum for us. 399 const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum(); 400 const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile( 401 dex_location_, dex_checksum_pointer, false); 402 if (oat_dex_file == nullptr) { 403 return true; 404 } 405 406 // Verify the dex checksums for any secondary multidex files 407 for (size_t i = 1; ; i++) { 408 std::string secondary_dex_location 409 = DexFile::GetMultiDexLocation(i, dex_location_); 410 const OatFile::OatDexFile* secondary_oat_dex_file 411 = file.GetOatDexFile(secondary_dex_location.c_str(), nullptr, false); 412 if (secondary_oat_dex_file == nullptr) { 413 // There are no more secondary dex files to check. 414 break; 415 } 416 417 std::string error_msg; 418 uint32_t expected_secondary_checksum = 0; 419 if (DexFile::GetChecksum(secondary_dex_location.c_str(), 420 &expected_secondary_checksum, &error_msg)) { 421 uint32_t actual_secondary_checksum 422 = secondary_oat_dex_file->GetDexFileLocationChecksum(); 423 if (expected_secondary_checksum != actual_secondary_checksum) { 424 VLOG(oat) << "Dex checksum does not match for secondary dex: " 425 << secondary_dex_location 426 << ". Expected: " << expected_secondary_checksum 427 << ", Actual: " << actual_secondary_checksum; 428 return true; 429 } 430 } else { 431 // If we can't get the checksum for the secondary location, we assume 432 // the dex checksum is up to date for this and all other secondary dex 433 // files. 434 break; 435 } 436 } 437 438 // Verify the image checksum 439 const ImageInfo* image_info = GetImageInfo(); 440 if (image_info == nullptr) { 441 VLOG(oat) << "No image for oat image checksum to match against."; 442 return true; 443 } 444 445 if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) { 446 VLOG(oat) << "Oat image checksum does not match image checksum."; 447 return true; 448 } 449 450 // The checksums are all good; the dex file is not out of date. 451 return false; 452} 453 454bool OatFileAssistant::GivenOatFileNeedsRelocation(const OatFile& file) { 455 return GivenOatFileStatus(file) == kOatNeedsRelocation; 456} 457 458bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) { 459 if (GivenOatFileIsOutOfDate(file)) { 460 return false; 461 } 462 463 if (file.IsPic()) { 464 return true; 465 } 466 467 const ImageInfo* image_info = GetImageInfo(); 468 if (image_info == nullptr) { 469 VLOG(oat) << "No image to check oat relocation against."; 470 return false; 471 } 472 473 // Verify the oat_data_begin recorded for the image in the oat file matches 474 // the actual oat_data_begin for boot.oat in the image. 475 const OatHeader& oat_header = file.GetOatHeader(); 476 uintptr_t oat_data_begin = oat_header.GetImageFileLocationOatDataBegin(); 477 if (oat_data_begin != image_info->oat_data_begin) { 478 VLOG(oat) << file.GetLocation() << 479 ": Oat file image oat_data_begin (" << oat_data_begin << ")" 480 << " does not match actual image oat_data_begin (" 481 << image_info->oat_data_begin << ")"; 482 return false; 483 } 484 485 // Verify the oat_patch_delta recorded for the image in the oat file matches 486 // the actual oat_patch_delta for the image. 487 int32_t oat_patch_delta = oat_header.GetImagePatchDelta(); 488 if (oat_patch_delta != image_info->patch_delta) { 489 VLOG(oat) << file.GetLocation() << 490 ": Oat file image patch delta (" << oat_patch_delta << ")" 491 << " does not match actual image patch delta (" 492 << image_info->patch_delta << ")"; 493 return false; 494 } 495 return true; 496} 497 498bool OatFileAssistant::ProfileExists() { 499 return GetProfile() != nullptr; 500} 501 502bool OatFileAssistant::OldProfileExists() { 503 return GetOldProfile() != nullptr; 504} 505 506// TODO: The IsProfileChangeSignificant implementation was copied from likely 507// bit-rotted code. 508bool OatFileAssistant::IsProfileChangeSignificant() { 509 ProfileFile* profile = GetProfile(); 510 if (profile == nullptr) { 511 return false; 512 } 513 514 ProfileFile* old_profile = GetOldProfile(); 515 if (old_profile == nullptr) { 516 return false; 517 } 518 519 // TODO: The following code to compare two profile files should live with 520 // the rest of the profiler code, not the oat file assistant code. 521 522 // A change in profile is considered significant if X% (change_thr property) 523 // of the top K% (compile_thr property) samples has changed. 524 const ProfilerOptions& options = Runtime::Current()->GetProfilerOptions(); 525 const double top_k_threshold = options.GetTopKThreshold(); 526 const double change_threshold = options.GetTopKChangeThreshold(); 527 std::set<std::string> top_k, old_top_k; 528 profile->GetTopKSamples(top_k, top_k_threshold); 529 old_profile->GetTopKSamples(old_top_k, top_k_threshold); 530 std::set<std::string> diff; 531 std::set_difference(top_k.begin(), top_k.end(), old_top_k.begin(), 532 old_top_k.end(), std::inserter(diff, diff.end())); 533 534 // TODO: consider using the usedPercentage instead of the plain diff count. 535 double change_percent = 100.0 * static_cast<double>(diff.size()) 536 / static_cast<double>(top_k.size()); 537 std::set<std::string>::iterator end = diff.end(); 538 for (std::set<std::string>::iterator it = diff.begin(); it != end; it++) { 539 VLOG(oat) << "Profile new in topK: " << *it; 540 } 541 542 if (change_percent > change_threshold) { 543 VLOG(oat) << "Oat File Assistant: Profile for " << dex_location_ 544 << "has changed significantly: (top " 545 << top_k_threshold << "% samples changed in proportion of " 546 << change_percent << "%)"; 547 return true; 548 } 549 return false; 550} 551 552// TODO: The CopyProfileFile implementation was copied from likely bit-rotted 553// code. 554void OatFileAssistant::CopyProfileFile() { 555 if (!ProfileExists()) { 556 return; 557 } 558 559 std::string profile_name = ProfileFileName(); 560 std::string old_profile_name = OldProfileFileName(); 561 562 ScopedFd src(open(old_profile_name.c_str(), O_RDONLY)); 563 if (src.get() == -1) { 564 PLOG(WARNING) << "Failed to open profile file " << old_profile_name 565 << ". My uid:gid is " << getuid() << ":" << getgid(); 566 return; 567 } 568 569 struct stat stat_src; 570 if (fstat(src.get(), &stat_src) == -1) { 571 PLOG(WARNING) << "Failed to get stats for profile file " << old_profile_name 572 << ". My uid:gid is " << getuid() << ":" << getgid(); 573 return; 574 } 575 576 // Create the copy with rw------- (only accessible by system) 577 ScopedFd dst(open(profile_name.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0600)); 578 if (dst.get() == -1) { 579 PLOG(WARNING) << "Failed to create/write prev profile file " << profile_name 580 << ". My uid:gid is " << getuid() << ":" << getgid(); 581 return; 582 } 583 584#ifdef __linux__ 585 if (sendfile(dst.get(), src.get(), nullptr, stat_src.st_size) == -1) { 586#else 587 off_t len; 588 if (sendfile(dst.get(), src.get(), 0, &len, nullptr, 0) == -1) { 589#endif 590 PLOG(WARNING) << "Failed to copy profile file " << old_profile_name 591 << " to " << profile_name << ". My uid:gid is " << getuid() 592 << ":" << getgid(); 593 } 594} 595 596bool OatFileAssistant::RelocateOatFile(const std::string* input_file, 597 std::string* error_msg) { 598 CHECK(error_msg != nullptr); 599 600 if (input_file == nullptr) { 601 *error_msg = "Patching of oat file for dex location " 602 + std::string(dex_location_) 603 + " not attempted because the input file name could not be determined."; 604 return false; 605 } 606 const std::string& input_file_name = *input_file; 607 608 if (OatFileName() == nullptr) { 609 *error_msg = "Patching of oat file for dex location " 610 + std::string(dex_location_) 611 + " not attempted because the oat file name could not be determined."; 612 return false; 613 } 614 const std::string& oat_file_name = *OatFileName(); 615 616 const ImageInfo* image_info = GetImageInfo(); 617 Runtime* runtime = Runtime::Current(); 618 if (image_info == nullptr) { 619 *error_msg = "Patching of oat file " + oat_file_name 620 + " not attempted because no image location was found."; 621 return false; 622 } 623 624 if (!runtime->IsDex2OatEnabled()) { 625 *error_msg = "Patching of oat file " + oat_file_name 626 + " not attempted because dex2oat is disabled"; 627 return false; 628 } 629 630 std::vector<std::string> argv; 631 argv.push_back(runtime->GetPatchoatExecutable()); 632 argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(isa_))); 633 argv.push_back("--input-oat-file=" + input_file_name); 634 argv.push_back("--output-oat-file=" + oat_file_name); 635 argv.push_back("--patched-image-location=" + image_info->location); 636 637 std::string command_line(Join(argv, ' ')); 638 if (!Exec(argv, error_msg)) { 639 // Manually delete the file. This ensures there is no garbage left over if 640 // the process unexpectedly died. 641 TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str())); 642 return false; 643 } 644 645 // Mark that the oat file has changed and we should try to reload. 646 ClearOatFileCache(); 647 return true; 648} 649 650bool OatFileAssistant::GenerateOatFile(std::string* error_msg) { 651 CHECK(error_msg != nullptr); 652 653 if (OatFileName() == nullptr) { 654 *error_msg = "Generation of oat file for dex location " 655 + std::string(dex_location_) 656 + " not attempted because the oat file name could not be determined."; 657 return false; 658 } 659 const std::string& oat_file_name = *OatFileName(); 660 661 Runtime* runtime = Runtime::Current(); 662 if (!runtime->IsDex2OatEnabled()) { 663 *error_msg = "Generation of oat file " + oat_file_name 664 + " not attempted because dex2oat is disabled"; 665 return false; 666 } 667 668 std::vector<std::string> args; 669 args.push_back("--dex-file=" + std::string(dex_location_)); 670 args.push_back("--oat-file=" + oat_file_name); 671 672 // dex2oat ignores missing dex files and doesn't report an error. 673 // Check explicitly here so we can detect the error properly. 674 // TODO: Why does dex2oat behave that way? 675 if (!OS::FileExists(dex_location_)) { 676 *error_msg = "Dex location " + std::string(dex_location_) + " does not exists."; 677 return false; 678 } 679 680 if (!Dex2Oat(args, error_msg)) { 681 // Manually delete the file. This ensures there is no garbage left over if 682 // the process unexpectedly died. 683 TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str())); 684 return false; 685 } 686 687 // Mark that the oat file has changed and we should try to reload. 688 ClearOatFileCache(); 689 return true; 690} 691 692bool OatFileAssistant::Dex2Oat(const std::vector<std::string>& args, 693 std::string* error_msg) { 694 Runtime* runtime = Runtime::Current(); 695 std::string image_location = ImageLocation(); 696 if (image_location.empty()) { 697 *error_msg = "No image location found for Dex2Oat."; 698 return false; 699 } 700 701 ClassLinker* linker = runtime->GetClassLinker(); 702 CHECK(linker != nullptr) << "ClassLinker is not created yet"; 703 const OatFile* primary_oat_file = linker->GetPrimaryOatFile(); 704 const bool debuggable = primary_oat_file != nullptr && primary_oat_file->IsDebuggable(); 705 706 std::vector<std::string> argv; 707 argv.push_back(runtime->GetCompilerExecutable()); 708 argv.push_back("--runtime-arg"); 709 argv.push_back("-classpath"); 710 argv.push_back("--runtime-arg"); 711 argv.push_back(runtime->GetClassPathString()); 712 if (debuggable) { 713 argv.push_back("--debuggable"); 714 } 715 runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv); 716 717 if (!runtime->IsVerificationEnabled()) { 718 argv.push_back("--compiler-filter=verify-none"); 719 } 720 721 if (runtime->MustRelocateIfPossible()) { 722 argv.push_back("--runtime-arg"); 723 argv.push_back("-Xrelocate"); 724 } else { 725 argv.push_back("--runtime-arg"); 726 argv.push_back("-Xnorelocate"); 727 } 728 729 if (!kIsTargetBuild) { 730 argv.push_back("--host"); 731 } 732 733 argv.push_back("--boot-image=" + image_location); 734 735 std::vector<std::string> compiler_options = runtime->GetCompilerOptions(); 736 argv.insert(argv.end(), compiler_options.begin(), compiler_options.end()); 737 738 argv.insert(argv.end(), args.begin(), args.end()); 739 740 std::string command_line(Join(argv, ' ')); 741 return Exec(argv, error_msg); 742} 743 744bool OatFileAssistant::DexFilenameToOdexFilename(const std::string& location, 745 InstructionSet isa, std::string* odex_filename, std::string* error_msg) { 746 CHECK(odex_filename != nullptr); 747 CHECK(error_msg != nullptr); 748 749 // The odex file name is formed by replacing the dex_location extension with 750 // .odex and inserting an oat/<isa> directory. For example: 751 // location = /foo/bar/baz.jar 752 // odex_location = /foo/bar/oat/<isa>/baz.odex 753 754 // Find the directory portion of the dex location and add the oat/<isa> 755 // directory. 756 size_t pos = location.rfind('/'); 757 if (pos == std::string::npos) { 758 *error_msg = "Dex location " + location + " has no directory."; 759 return false; 760 } 761 std::string dir = location.substr(0, pos+1); 762 dir += "oat/" + std::string(GetInstructionSetString(isa)); 763 764 // Find the file portion of the dex location. 765 std::string file; 766 if (pos == std::string::npos) { 767 file = location; 768 } else { 769 file = location.substr(pos+1); 770 } 771 772 // Get the base part of the file without the extension. 773 pos = file.rfind('.'); 774 if (pos == std::string::npos) { 775 *error_msg = "Dex location " + location + " has no extension."; 776 return false; 777 } 778 std::string base = file.substr(0, pos); 779 780 *odex_filename = dir + "/" + base + ".odex"; 781 return true; 782} 783 784std::string OatFileAssistant::DalvikCacheDirectory() { 785 // Note: We don't cache this, because it will only be called once by 786 // OatFileName, and we don't care about the performance of the profiling 787 // code, which isn't used in practice. 788 789 // TODO: The work done in GetDalvikCache is overkill for what we need. 790 // Ideally a new API for getting the DalvikCacheDirectory the way we want 791 // (without existence testing, creation, or death) is provided with the rest 792 // of the GetDalvikCache family of functions. Until such an API is in place, 793 // we use GetDalvikCache to avoid duplicating the logic for determining the 794 // dalvik cache directory. 795 std::string result; 796 bool have_android_data; 797 bool dalvik_cache_exists; 798 bool is_global_cache; 799 GetDalvikCache("", false, &result, &have_android_data, &dalvik_cache_exists, &is_global_cache); 800 return result; 801} 802 803std::string OatFileAssistant::ProfileFileName() { 804 if (package_name_ != nullptr) { 805 return DalvikCacheDirectory() + std::string("profiles/") + package_name_; 806 } 807 return ""; 808} 809 810std::string OatFileAssistant::OldProfileFileName() { 811 std::string profile_name = ProfileFileName(); 812 if (profile_name.empty()) { 813 return ""; 814 } 815 return profile_name + "@old"; 816} 817 818std::string OatFileAssistant::ImageLocation() { 819 Runtime* runtime = Runtime::Current(); 820 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace(); 821 if (image_space == nullptr) { 822 return ""; 823 } 824 return image_space->GetImageLocation(); 825} 826 827const uint32_t* OatFileAssistant::GetRequiredDexChecksum() { 828 if (!required_dex_checksum_attempted_) { 829 required_dex_checksum_attempted_ = true; 830 required_dex_checksum_found_ = false; 831 std::string error_msg; 832 CHECK(dex_location_ != nullptr) << "OatFileAssistant provided no dex location"; 833 if (DexFile::GetChecksum(dex_location_, &cached_required_dex_checksum_, &error_msg)) { 834 required_dex_checksum_found_ = true; 835 has_original_dex_files_ = true; 836 } else { 837 // This can happen if the original dex file has been stripped from the 838 // apk. 839 VLOG(oat) << "OatFileAssistant: " << error_msg; 840 has_original_dex_files_ = false; 841 842 // Get the checksum from the odex if we can. 843 const OatFile* odex_file = GetOdexFile(); 844 if (odex_file != nullptr) { 845 const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile( 846 dex_location_, nullptr, false); 847 if (odex_dex_file != nullptr) { 848 cached_required_dex_checksum_ = odex_dex_file->GetDexFileLocationChecksum(); 849 required_dex_checksum_found_ = true; 850 } 851 } 852 } 853 } 854 return required_dex_checksum_found_ ? &cached_required_dex_checksum_ : nullptr; 855} 856 857const OatFile* OatFileAssistant::GetOdexFile() { 858 CHECK(!oat_file_released_) << "OdexFile called after oat file released."; 859 if (!odex_file_load_attempted_) { 860 odex_file_load_attempted_ = true; 861 if (OdexFileName() != nullptr) { 862 const std::string& odex_file_name = *OdexFileName(); 863 std::string error_msg; 864 cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(), 865 odex_file_name.c_str(), nullptr, nullptr, load_executable_, 866 dex_location_, &error_msg)); 867 if (cached_odex_file_.get() == nullptr) { 868 VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file " 869 << odex_file_name << ": " << error_msg; 870 } 871 } 872 } 873 return cached_odex_file_.get(); 874} 875 876void OatFileAssistant::ClearOdexFileCache() { 877 odex_file_load_attempted_ = false; 878 cached_odex_file_.reset(); 879 odex_file_is_out_of_date_attempted_ = false; 880 odex_file_is_up_to_date_attempted_ = false; 881} 882 883const OatFile* OatFileAssistant::GetOatFile() { 884 CHECK(!oat_file_released_) << "OatFile called after oat file released."; 885 if (!oat_file_load_attempted_) { 886 oat_file_load_attempted_ = true; 887 if (OatFileName() != nullptr) { 888 const std::string& oat_file_name = *OatFileName(); 889 std::string error_msg; 890 cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(), 891 oat_file_name.c_str(), nullptr, nullptr, load_executable_, 892 dex_location_, &error_msg)); 893 if (cached_oat_file_.get() == nullptr) { 894 VLOG(oat) << "OatFileAssistant test for existing oat file " 895 << oat_file_name << ": " << error_msg; 896 } 897 } 898 } 899 return cached_oat_file_.get(); 900} 901 902void OatFileAssistant::ClearOatFileCache() { 903 oat_file_load_attempted_ = false; 904 cached_oat_file_.reset(); 905 oat_file_is_out_of_date_attempted_ = false; 906 oat_file_is_up_to_date_attempted_ = false; 907} 908 909const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() { 910 if (!image_info_load_attempted_) { 911 image_info_load_attempted_ = true; 912 913 Runtime* runtime = Runtime::Current(); 914 const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace(); 915 if (image_space != nullptr) { 916 cached_image_info_.location = image_space->GetImageLocation(); 917 918 if (isa_ == kRuntimeISA) { 919 const ImageHeader& image_header = image_space->GetImageHeader(); 920 cached_image_info_.oat_checksum = image_header.GetOatChecksum(); 921 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()); 922 cached_image_info_.patch_delta = image_header.GetPatchDelta(); 923 } else { 924 std::unique_ptr<ImageHeader> image_header( 925 gc::space::ImageSpace::ReadImageHeaderOrDie( 926 cached_image_info_.location.c_str(), isa_)); 927 cached_image_info_.oat_checksum = image_header->GetOatChecksum(); 928 cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()); 929 cached_image_info_.patch_delta = image_header->GetPatchDelta(); 930 } 931 } 932 image_info_load_succeeded_ = (image_space != nullptr); 933 } 934 return image_info_load_succeeded_ ? &cached_image_info_ : nullptr; 935} 936 937ProfileFile* OatFileAssistant::GetProfile() { 938 if (!profile_load_attempted_) { 939 CHECK(package_name_ != nullptr) 940 << "pakage_name_ is nullptr: " 941 << "profile_load_attempted_ should have been true"; 942 profile_load_attempted_ = true; 943 std::string profile_name = ProfileFileName(); 944 if (!profile_name.empty()) { 945 profile_load_succeeded_ = cached_profile_.LoadFile(profile_name); 946 } 947 } 948 return profile_load_succeeded_ ? &cached_profile_ : nullptr; 949} 950 951ProfileFile* OatFileAssistant::GetOldProfile() { 952 if (!old_profile_load_attempted_) { 953 CHECK(package_name_ != nullptr) 954 << "pakage_name_ is nullptr: " 955 << "old_profile_load_attempted_ should have been true"; 956 old_profile_load_attempted_ = true; 957 std::string old_profile_name = OldProfileFileName(); 958 if (!old_profile_name.empty()) { 959 old_profile_load_succeeded_ = cached_old_profile_.LoadFile(old_profile_name); 960 } 961 } 962 return old_profile_load_succeeded_ ? &cached_old_profile_ : nullptr; 963} 964 965} // namespace art 966 967