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 #ifndef ART_RUNTIME_OAT_OAT_FILE_ASSISTANT_H_ 18 #define ART_RUNTIME_OAT_OAT_FILE_ASSISTANT_H_ 19 20 #include <cstdint> 21 #include <memory> 22 #include <optional> 23 #include <sstream> 24 #include <string> 25 #include <string_view> 26 #include <utility> 27 #include <variant> 28 #include <vector> 29 30 #include "arch/instruction_set.h" 31 #include "base/compiler_filter.h" 32 #include "base/macros.h" 33 #include "base/os.h" 34 #include "base/scoped_flock.h" 35 #include "base/unix_file/fd_file.h" 36 #include "class_loader_context.h" 37 #include "oat_file.h" 38 #include "oat_file_assistant_context.h" 39 40 namespace art HIDDEN { 41 42 namespace gc { 43 namespace space { 44 class ImageSpace; 45 } // namespace space 46 } // namespace gc 47 48 // Class for assisting with oat file management. 49 // 50 // This class collects common utilities for determining the status of an oat 51 // file on the device, updating the oat file, and loading the oat file. 52 // 53 // The oat file assistant is intended to be used with dex locations not on the 54 // boot class path. See the IsInBootClassPath method for a way to check if the 55 // dex location is in the boot class path. 56 class OatFileAssistant { 57 public: 58 enum DexOptNeeded { 59 // No dexopt should (or can) be done to update the apk/jar. 60 // Matches Java: dalvik.system.DexFile.NO_DEXOPT_NEEDED = 0 61 kNoDexOptNeeded = 0, 62 63 // dex2oat should be run to update the apk/jar from scratch. 64 // Matches Java: dalvik.system.DexFile.DEX2OAT_FROM_SCRATCH = 1 65 kDex2OatFromScratch = 1, 66 67 // dex2oat should be run to update the apk/jar because the existing code 68 // is out of date with respect to the boot image. 69 // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_BOOT_IMAGE 70 kDex2OatForBootImage = 2, 71 72 // dex2oat should be run to update the apk/jar because the existing code 73 // is out of date with respect to the target compiler filter. 74 // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_FILTER 75 kDex2OatForFilter = 3, 76 }; 77 78 enum OatStatus { 79 // kOatCannotOpen - The oat file cannot be opened, because it does not 80 // exist, is unreadable, or otherwise corrupted. 81 kOatCannotOpen, 82 83 // kOatDexOutOfDate - The oat file is out of date with respect to the dex file. 84 kOatDexOutOfDate, 85 86 // kOatBootImageOutOfDate - The oat file is up to date with respect to the 87 // dex file, but is out of date with respect to the boot image. 88 kOatBootImageOutOfDate, 89 90 // kOatContextOutOfDate - The context in the oat file is out of date with 91 // respect to the class loader context. 92 kOatContextOutOfDate, 93 94 // kOatUpToDate - The oat file is completely up to date with respect to 95 // the dex file and boot image. 96 kOatUpToDate, 97 }; 98 99 // A bit field to represent the conditions where dexopt should be performed. 100 struct DexOptTrigger { 101 // Dexopt should be performed if the target compiler filter is better than the current compiler 102 // filter. See `CompilerFilter::IsBetter`. 103 bool targetFilterIsBetter : 1; 104 // Dexopt should be performed if the target compiler filter is the same as the current compiler 105 // filter. 106 bool targetFilterIsSame : 1; 107 // Dexopt should be performed if the target compiler filter is worse than the current compiler 108 // filter. See `CompilerFilter::IsBetter`. 109 bool targetFilterIsWorse : 1; 110 // Dexopt should be performed if the current oat file was compiled without a primary image, 111 // and the runtime is now running with a primary image loaded from disk. 112 bool primaryBootImageBecomesUsable : 1; 113 // Dexopt should be performed if the APK is compressed and the current oat/vdex file doesn't 114 // contain dex code. 115 bool needExtraction : 1; 116 }; 117 118 // Represents the location of the current oat file and/or vdex file. 119 enum Location { 120 // Does not exist, or an error occurs. 121 kLocationNoneOrError = 0, 122 // In the global "dalvik-cache" folder. 123 kLocationOat = 1, 124 // In the "oat" folder next to the dex file. 125 kLocationOdex = 2, 126 // In the dm file. This means the only usable file is the vdex file. 127 kLocationDm = 3, 128 // The oat and art files are in the sdm file next to the dex file. The vdex file is in the dm 129 // file next to the dex file. The sdc file is in the global "dalvik-cache" folder. 130 kLocationSdmOat = 4, 131 // The oat and art files are in the sdm file next to the dex file. The vdex file is in the dm 132 // file next to the dex file. The sdc file is next to the dex file. 133 kLocationSdmOdex = 5, 134 }; 135 136 // Represents the status of the current oat file and/or vdex file. 137 class DexOptStatus { 138 public: GetLocation()139 Location GetLocation() { return location_; } IsVdexUsable()140 bool IsVdexUsable() { return location_ != kLocationNoneOrError; } 141 142 private: 143 Location location_ = kLocationNoneOrError; 144 friend class OatFileAssistant; 145 }; 146 147 // Constructs an OatFileAssistant object to assist the oat file 148 // corresponding to the given dex location with the target instruction set. 149 // 150 // The dex_location must not be null and should remain available and 151 // unchanged for the duration of the lifetime of the OatFileAssistant object. 152 // Typically the dex_location is the absolute path to the original, 153 // un-optimized dex file. 154 // 155 // Note: Currently the dex_location must have an extension. 156 // TODO: Relax this restriction? 157 // 158 // The isa should be either the 32 bit or 64 bit variant for the current 159 // device. For example, on an arm device, use arm or arm64. An oat file can 160 // be loaded executable only if the ISA matches the current runtime. 161 // 162 // context should be the class loader context to check against, or null to skip the check. 163 // 164 // load_executable should be true if the caller intends to try and load 165 // executable code for this dex location. 166 // 167 // only_load_trusted_executable should be true if the caller intends to have 168 // only oat files from trusted locations loaded executable. See IsTrustedLocation() for 169 // details on trusted locations. 170 // 171 // runtime_options should be provided with all the required fields filled if the caller intends to 172 // use OatFileAssistant without a runtime. 173 EXPORT OatFileAssistant(const char* dex_location, 174 const InstructionSet isa, 175 ClassLoaderContext* context, 176 bool load_executable, 177 bool only_load_trusted_executable = false, 178 OatFileAssistantContext* ofa_context = nullptr); 179 180 // Similar to this(const char*, const InstructionSet, bool), however, if a valid zip_fd is 181 // provided, vdex, oat, and zip files will be read from vdex_fd, oat_fd and zip_fd respectively. 182 // Otherwise, dex_location will be used to construct necessary filenames. 183 EXPORT OatFileAssistant(const char* dex_location, 184 const InstructionSet isa, 185 ClassLoaderContext* context, 186 bool load_executable, 187 bool only_load_trusted_executable, 188 OatFileAssistantContext* ofa_context, 189 int vdex_fd, 190 int oat_fd, 191 int zip_fd); 192 193 EXPORT ~OatFileAssistant(); 194 195 // A convenient factory function that accepts ISA, class loader context, and compiler filter in 196 // strings. Returns the created instance and ClassLoaderContext on success, or returns nullptr and 197 // outputs an error message if it fails to parse the input strings. 198 // The returned ClassLoaderContext must live at least as long as the OatFileAssistant. 199 EXPORT static std::unique_ptr<OatFileAssistant> Create( 200 const std::string& filename, 201 const std::string& isa_str, 202 const std::optional<std::string>& context_str, 203 bool load_executable, 204 bool only_load_trusted_executable, 205 OatFileAssistantContext* ofa_context, 206 /*out*/ std::unique_ptr<ClassLoaderContext>* context, 207 /*out*/ std::string* error_msg); 208 209 // Returns true if the dex location refers to an element of the boot class 210 // path. 211 EXPORT bool IsInBootClassPath(); 212 213 // Return what action needs to be taken to produce up-to-date code for this 214 // dex location. If "downgrade" is set to false, it verifies if the current 215 // compiler filter is at least as good as an oat file generated with the 216 // given compiler filter otherwise, if its set to true, it checks whether 217 // the oat file generated with the target filter will be downgraded as 218 // compared to the current state. For example, if the current compiler filter is verify and the 219 // target filter is speed profile it will recommend to keep it in its current state. 220 // profile_changed should be true to indicate the profile has recently changed 221 // for this dex location. 222 // If the purpose of the dexopt is to downgrade the compiler filter, 223 // set downgrade to true. 224 // Returns a positive status code if the status refers to the oat file in 225 // the oat location. Returns a negative status code if the status refers to 226 // the oat file in the odex location. 227 // 228 // Deprecated. Use the other overload. 229 EXPORT int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, 230 bool profile_changed = false, 231 bool downgrade = false); 232 233 // Returns true if dexopt needs to be performed with respect to the given target compilation 234 // filter and dexopt trigger. Also returns the status of the current oat file and/or vdex file. 235 EXPORT bool GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, 236 const DexOptTrigger dexopt_trigger, 237 /*out*/ DexOptStatus* dexopt_status); 238 239 // Returns true if there is up-to-date code for this dex location, 240 // irrespective of the compiler filter of the up-to-date code. 241 bool IsUpToDate(); 242 243 // Returns an oat file that can be used for loading dex files. 244 // Returns null if no suitable oat file was found. 245 // 246 // After this call, no other methods of the OatFileAssistant should be 247 // called, because access to the loaded oat file has been taken away from 248 // the OatFileAssistant object. 249 std::unique_ptr<OatFile> GetBestOatFile(); 250 251 // Computes the optimization status of the given dex file. The result is 252 // returned via the two output parameters. 253 // - out_odex_location: the location of the (best) odex that will be used 254 // for loading. See GetBestInfo(). 255 // - out_compilation_filter: the level of optimizations (compiler filter) 256 // - out_compilation_reason: the optimization reason. The reason might 257 // be "unknown" if the compiler artifacts were not annotated during optimizations. 258 // - out_odex_status: a human readable refined status of the validity of the odex file. 259 // Possible values are: "up-to-date", "apk-more-recent", and "io-error-no-oat". 260 // 261 // This method will try to mimic the runtime effect of loading the dex file. 262 // For example, if there is no usable oat file, the compiler filter will be set 263 // to "run-from-apk". 264 EXPORT void GetOptimizationStatus(std::string* out_odex_location, 265 std::string* out_compilation_filter, 266 std::string* out_compilation_reason, 267 std::string* out_odex_status, 268 Location* out_location); 269 270 static void GetOptimizationStatus(const std::string& filename, 271 InstructionSet isa, 272 std::string* out_compilation_filter, 273 std::string* out_compilation_reason, 274 OatFileAssistantContext* ofa_context = nullptr); 275 276 // Open and returns an image space associated with the oat file. 277 static std::unique_ptr<gc::space::ImageSpace> OpenImageSpace(const OatFile* oat_file); 278 279 // Loads the dex files in the given oat file for the given dex location. 280 // The oat file should be up to date for the given dex location. 281 // This loads multiple dex files in the case of multidex. 282 // Returns an empty vector if no dex files for that location could be loaded 283 // from the oat file. 284 // 285 // The caller is responsible for freeing the dex_files returned, if any. The 286 // dex_files will only remain valid as long as the oat_file is valid. 287 static std::vector<std::unique_ptr<const DexFile>> LoadDexFiles( 288 const OatFile& oat_file, const char* dex_location); 289 290 // Same as `std::vector<std::unique_ptr<const DexFile>> LoadDexFiles(...)` with the difference: 291 // - puts the dex files in the given vector 292 // - returns whether or not all dex files were successfully opened 293 static bool LoadDexFiles(const OatFile& oat_file, 294 const std::string& dex_location, 295 std::vector<std::unique_ptr<const DexFile>>* out_dex_files); 296 297 // Returns whether this is an apk/zip wit a classes.dex entry, or nullopt if an error occurred. 298 EXPORT std::optional<bool> HasDexFiles(std::string* error_msg); 299 300 // If the dex file has been installed with a compiled oat file alongside 301 // it, the compiled oat file will have the extension .odex, and is referred 302 // to as the odex file. It is called odex for legacy reasons; the file is 303 // really an oat file. The odex file will often, but not always, have a 304 // patch delta of 0 and need to be relocated before use for the purposes of 305 // ASLR. The odex file is treated as if it were read-only. 306 // 307 // Returns the status of the odex file for the dex location. 308 // 309 // For testing purposes only. 310 OatStatus OdexFileStatus(); 311 312 // When the dex files is compiled on the target device, the oat file is the 313 // result. The oat file will have been relocated to some 314 // (possibly-out-of-date) offset for ASLR. 315 // 316 // Returns the status of the oat file for the dex location. 317 // 318 // For testing purposes only. 319 OatStatus OatFileStatus(); 320 GetBestStatus()321 OatStatus GetBestStatus() { 322 return GetBestInfo().Status(); 323 } 324 325 // Constructs the odex file name for the given dex location. 326 // Returns true on success, in which case odex_filename is set to the odex 327 // file name. 328 // Returns false on error, in which case error_msg describes the error and 329 // odex_filename is not changed. 330 // Neither odex_filename nor error_msg may be null. 331 EXPORT static bool DexLocationToOdexFilename(const std::string& location, 332 InstructionSet isa, 333 std::string* odex_filename, 334 std::string* error_msg); 335 336 // Constructs the oat file name for the given dex location. 337 // Returns true on success, in which case oat_filename is set to the oat 338 // file name. 339 // Returns false on error, in which case error_msg describes the error and 340 // oat_filename is not changed. 341 // Neither oat_filename nor error_msg may be null. 342 // 343 // Calling this function requires an active runtime. 344 static bool DexLocationToOatFilename(const std::string& location, 345 InstructionSet isa, 346 std::string* oat_filename, 347 std::string* error_msg); 348 349 // Same as above, but also takes `deny_art_apex_data_files` from input. 350 // 351 // Calling this function does not require an active runtime. 352 EXPORT static bool DexLocationToOatFilename(const std::string& location, 353 InstructionSet isa, 354 bool deny_art_apex_data_files, 355 std::string* oat_filename, 356 std::string* error_msg); 357 358 // Computes the dex location and vdex filename. If the data directory of the process 359 // is known, creates an absolute path in that directory and tries to infer path 360 // of a corresponding vdex file. Otherwise only creates a basename dex_location 361 // from the combined checksums. Returns true if all out-arguments have been set. 362 // 363 // Calling this function requires an active runtime. 364 static bool AnonymousDexVdexLocation(const std::vector<const DexFile::Header*>& dex_headers, 365 InstructionSet isa, 366 /* out */ std::string* dex_location, 367 /* out */ std::string* vdex_filename); 368 369 // Returns true if a filename (given as basename) is a name of a vdex for 370 // anonymous dex file(s) created by AnonymousDexVdexLocation. 371 EXPORT static bool IsAnonymousVdexBasename(const std::string& basename); 372 373 bool ClassLoaderContextIsOkay(const OatFile& oat_file, /*out*/ std::string* error_msg) const; 374 375 // Validates the boot class path checksum of an OatFile. 376 EXPORT bool ValidateBootClassPathChecksums(const OatFile& oat_file, 377 /*out*/ std::string* error_msg); 378 379 // Validates the given bootclasspath and bootclasspath checksums found in an oat header. 380 static bool ValidateBootClassPathChecksums(OatFileAssistantContext* ofa_context, 381 InstructionSet isa, 382 std::string_view oat_checksums, 383 std::string_view oat_boot_class_path, 384 /*out*/ std::string* error_msg); 385 386 private: 387 enum class OatFileType { 388 kNone, 389 kOat, 390 kSdm, 391 kVdex, 392 kDm, 393 }; 394 395 class OatFileInfo { 396 public: 397 // Empty info. Treated as kOatCannotOpen. 398 // Use constructors in subclasses to construct a real instance. OatFileInfo(OatFileAssistant * oat_file_assistant)399 explicit OatFileInfo(OatFileAssistant* oat_file_assistant) 400 : oat_file_assistant_(oat_file_assistant), filename_(""), is_oat_location_(false) {} 401 402 virtual ~OatFileInfo() = default; 403 404 // ART code is compiled with `-fno-rtti`, so we need a virtual function to return type 405 // information. GetType()406 virtual OatFileType GetType() { return OatFileType::kNone; } 407 408 // Returns a string indicating the location of the oat file, for debugging purposes only. GetLocationDebugString()409 virtual const char* GetLocationDebugString() { return "none"; } 410 411 bool IsOatLocation() const; 412 413 const std::string* Filename() const; 414 415 const char* DisplayFilename() const; 416 417 // Returns true if this oat file can be used for running code. The oat 418 // file can be used for running code as long as it is not out of date with 419 // respect to the dex code or boot image. An oat file that is out of date 420 // with respect to relocation is considered useable, because it's possible 421 // to interpret the dex code rather than run the unrelocated compiled 422 // code. 423 bool IsUseable(); 424 425 // Returns the status of this oat file. 426 // Optionally, returns `error_msg` showing why the status is not `kOatUpToDate`. 427 OatStatus Status(/*out*/ std::string* error_msg = nullptr); 428 429 // Return the DexOptNeeded value for this oat file with respect to the given target compilation 430 // filter and dexopt trigger. 431 DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, 432 const DexOptTrigger dexopt_trigger); 433 434 // Returns true if the file exists. 435 virtual bool FileExists() const; 436 437 // Returns the loaded file. 438 // Loads the file if needed. Returns null if the file failed to load. 439 // The caller shouldn't clean up or free the returned pointer. 440 // Optionally, returns `error_msg` showing why the file failed to load. 441 const OatFile* GetFile(/*out*/ std::string* error_msg = nullptr); 442 443 // Returns true if the file is opened executable. 444 bool IsExecutable(); 445 446 // Release the loaded oat file for runtime use. 447 // Returns null if the oat file hasn't been loaded or is out of date. 448 // Ensures the returned file is not loaded executable if it has unuseable 449 // compiled code. 450 // 451 // After this call, no other methods of the OatFileInfo should be 452 // called, because access to the loaded oat file has been taken away from 453 // the OatFileInfo object. 454 std::unique_ptr<OatFile> ReleaseFileForUse(); 455 456 protected: 457 // Constructs a real instance. 458 // Pass true for is_oat_location if the information associated with this 459 // OatFileInfo is for the oat location, as opposed to the odex location. OatFileInfo(OatFileAssistant * oat_file_assistant,const std::string & filename,bool is_oat_location)460 OatFileInfo(OatFileAssistant* oat_file_assistant, 461 const std::string& filename, 462 bool is_oat_location) 463 : oat_file_assistant_(oat_file_assistant), 464 filename_(filename), 465 is_oat_location_(is_oat_location) {} 466 467 // Loads the file. LoadFile(std::string * error_msg)468 virtual std::unique_ptr<OatFile> LoadFile(std::string* error_msg) const { 469 *error_msg = "Not implemented"; 470 return nullptr; 471 } 472 473 OatFileAssistant* const oat_file_assistant_; 474 const std::string filename_; 475 476 private: 477 // Returns true if the oat file is usable but at least one dexopt trigger is matched. This 478 // function should only be called if the oat file is usable. 479 bool ShouldRecompileForFilter(CompilerFilter::Filter target, 480 const DexOptTrigger dexopt_trigger); 481 482 // Release the loaded oat file. 483 // Returns null if the oat file hasn't been loaded. 484 // 485 // After this call, no other methods of the OatFileInfo should be 486 // called, because access to the loaded oat file has been taken away from 487 // the OatFileInfo object. 488 std::unique_ptr<OatFile> ReleaseFile(); 489 490 const bool is_oat_location_; 491 492 // A pair of the loaded file and the error message, if `GetFile` has been attempted. 493 // `std::nullopt` if `GetFile` has not been attempted. 494 std::optional<std::pair<std::unique_ptr<OatFile>, std::string>> file_ = std::nullopt; 495 496 // A pair of the oat status and the error message, if `Status` has been attempted. 497 // `std::nullopt` if `Status` has not been attempted. 498 std::optional<std::pair<OatStatus, std::string>> status_ = std::nullopt; 499 500 // For debugging only. 501 // If this flag is set, the file has been released to the user and the 502 // OatFileInfo object is in a bad state and should no longer be used. 503 bool file_released_ = false; 504 }; 505 506 class OatFileInfoBackedByOat : public OatFileInfo { 507 public: 508 OatFileInfoBackedByOat(OatFileAssistant* oat_file_assistant, 509 const std::string& filename, 510 bool is_oat_location, 511 bool use_fd, 512 int zip_fd = -1, 513 int vdex_fd = -1, 514 int oat_fd = -1) OatFileInfo(oat_file_assistant,filename,is_oat_location)515 : OatFileInfo(oat_file_assistant, filename, is_oat_location), 516 use_fd_(use_fd), 517 zip_fd_(zip_fd), 518 vdex_fd_(vdex_fd), 519 oat_fd_(oat_fd) {} 520 GetType()521 OatFileType GetType() override { return OatFileType::kOat; } 522 GetLocationDebugString()523 const char* GetLocationDebugString() override { 524 return IsOatLocation() ? "odex in dalvik-cache" : "odex next to the dex file"; 525 } 526 527 bool FileExists() const override; 528 529 protected: 530 std::unique_ptr<OatFile> LoadFile(std::string* error_msg) const override; 531 532 private: 533 const bool use_fd_; 534 const int zip_fd_; 535 const int vdex_fd_; 536 const int oat_fd_; 537 }; 538 539 class OatFileInfoBackedBySdm : public OatFileInfo { 540 public: OatFileInfoBackedBySdm(OatFileAssistant * oat_file_assistant,const std::string & sdm_filename,bool is_oat_location,const std::string & dm_filename,const std::string & sdc_filename)541 OatFileInfoBackedBySdm(OatFileAssistant* oat_file_assistant, 542 const std::string& sdm_filename, 543 bool is_oat_location, 544 const std::string& dm_filename, 545 const std::string& sdc_filename) 546 : OatFileInfo(oat_file_assistant, sdm_filename, is_oat_location), 547 dm_filename_(dm_filename), 548 sdc_filename_(sdc_filename) {} 549 GetType()550 OatFileType GetType() override { return OatFileType::kSdm; } 551 GetLocationDebugString()552 const char* GetLocationDebugString() override { 553 return IsOatLocation() ? "sdm with sdc in dalvik-cache" : "sdm with sdc next to the dex file"; 554 } 555 556 bool FileExists() const override; 557 558 protected: 559 std::unique_ptr<OatFile> LoadFile(std::string* error_msg) const override; 560 561 private: 562 const std::string dm_filename_; 563 const std::string sdc_filename_; 564 }; 565 566 class OatFileInfoBackedByVdex : public OatFileInfo { 567 public: 568 OatFileInfoBackedByVdex(OatFileAssistant* oat_file_assistant, 569 const std::string& filename, 570 bool is_oat_location, 571 bool use_fd, 572 int zip_fd = -1, 573 int vdex_fd = -1) OatFileInfo(oat_file_assistant,filename,is_oat_location)574 : OatFileInfo(oat_file_assistant, filename, is_oat_location), 575 use_fd_(use_fd), 576 zip_fd_(zip_fd), 577 vdex_fd_(vdex_fd) {} 578 GetType()579 OatFileType GetType() override { return OatFileType::kVdex; } 580 GetLocationDebugString()581 const char* GetLocationDebugString() override { 582 return IsOatLocation() ? "vdex in dalvik-cache" : "vdex next to the dex file"; 583 } 584 585 bool FileExists() const override; 586 587 protected: 588 std::unique_ptr<OatFile> LoadFile(std::string* error_msg) const override; 589 590 private: 591 const bool use_fd_; 592 const int zip_fd_; 593 const int vdex_fd_; 594 }; 595 596 class OatFileInfoBackedByDm : public OatFileInfo { 597 public: OatFileInfoBackedByDm(OatFileAssistant * oat_file_assistant,const std::string & filename)598 OatFileInfoBackedByDm(OatFileAssistant* oat_file_assistant, const std::string& filename) 599 : OatFileInfo(oat_file_assistant, filename, /*is_oat_location=*/false) {} 600 GetType()601 OatFileType GetType() override { return OatFileType::kDm; } 602 GetLocationDebugString()603 const char* GetLocationDebugString() override { return "dm"; } 604 605 protected: 606 std::unique_ptr<OatFile> LoadFile(std::string* error_msg) const override; 607 }; 608 609 // Return info for the best oat file. 610 OatFileInfo& GetBestInfo(); 611 612 // Returns true when vdex/oat/odex files should be read from file descriptors. 613 // The method checks the value of zip_fd_, and if the value is valid, returns 614 // true. This is required to have a deterministic behavior around how different 615 // files are being read. 616 bool UseFdToReadFiles(); 617 618 // Returns true if the dex checksums in the given oat file are up to date 619 // with respect to the dex location. If the dex checksums are not up to 620 // date, error_msg is updated with a message describing the problem. 621 bool DexChecksumUpToDate(const OatFile& file, std::string* error_msg); 622 623 // Return the status for a given opened oat file with respect to the dex 624 // location. 625 OatStatus GivenOatFileStatus(const OatFile& file, /*out*/ std::string* error_msg); 626 627 // Gets the dex checksum required for an up-to-date oat file. 628 // Returns cached result from GetMultiDexChecksum. 629 bool GetRequiredDexChecksum(std::optional<uint32_t>* checksum, std::string* error); 630 631 // Returns whether there is at least one boot image usable. 632 bool IsPrimaryBootImageUsable(); 633 634 // Returns the trigger for the deprecated overload of `GetDexOptNeeded`. 635 // 636 // Deprecated. Do not use in new code. 637 DexOptTrigger GetDexOptTrigger(CompilerFilter::Filter target_compiler_filter, 638 bool profile_changed, 639 bool downgrade); 640 641 // Returns the pointer to the owned or unowned instance of OatFileAssistantContext. GetOatFileAssistantContext()642 OatFileAssistantContext* GetOatFileAssistantContext() { 643 if (std::holds_alternative<OatFileAssistantContext*>(ofa_context_)) { 644 return std::get<OatFileAssistantContext*>(ofa_context_); 645 } else { 646 return std::get<std::unique_ptr<OatFileAssistantContext>>(ofa_context_).get(); 647 } 648 } 649 650 // The runtime options taken from the active runtime or the input. 651 // 652 // All member functions should get runtime options from this variable rather than referencing the 653 // active runtime. This is to allow OatFileAssistant to function without an active runtime. GetRuntimeOptions()654 const OatFileAssistantContext::RuntimeOptions& GetRuntimeOptions() { 655 return GetOatFileAssistantContext()->GetRuntimeOptions(); 656 } 657 658 // Returns whether the zip file only contains uncompressed dex. 659 bool ZipFileOnlyContainsUncompressedDex(); 660 661 // Returns the location of the given oat file. 662 Location GetLocation(OatFileInfo& info); 663 664 std::string dex_location_; 665 666 // The class loader context to check against, or null representing that the check should be 667 // skipped. 668 ClassLoaderContext* context_; 669 670 // In a properly constructed OatFileAssistant object, isa_ should be either 671 // the 32 or 64 bit variant for the current device. 672 const InstructionSet isa_ = InstructionSet::kNone; 673 674 // Whether we will attempt to load oat files executable. 675 bool load_executable_ = false; 676 677 // Whether only oat files from trusted locations are loaded executable. 678 const bool only_load_trusted_executable_ = false; 679 680 // Cached value of whether the potential zip file only contains uncompressed dex. 681 // This should be accessed only by the ZipFileOnlyContainsUncompressedDex() method. 682 bool zip_file_only_contains_uncompressed_dex_ = true; 683 684 // Cached value of the required dex checksums. 685 // This should be accessed only by the GetRequiredDexChecksums() method. 686 std::optional<uint32_t> cached_required_dex_checksums_; 687 std::optional<std::string> cached_required_dex_checksums_error_; 688 bool required_dex_checksums_attempted_ = false; 689 690 // Empty oat file info, used as a placeholder. 691 OatFileInfo empty_info_ = OatFileInfo(this); 692 693 // Oat file info candidates, ordered by precedence. 694 std::vector<std::unique_ptr<OatFileInfo>> info_list_; 695 696 // File descriptor corresponding to apk, dex file, or zip. 697 int zip_fd_; 698 699 // Owned or unowned instance of OatFileAssistantContext. 700 std::variant<std::unique_ptr<OatFileAssistantContext>, OatFileAssistantContext*> ofa_context_; 701 702 friend class OatFileAssistantTest; 703 704 DISALLOW_COPY_AND_ASSIGN(OatFileAssistant); 705 }; 706 707 std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status); 708 709 } // namespace art 710 711 #endif // ART_RUNTIME_OAT_OAT_FILE_ASSISTANT_H_ 712