diff options
author | 2021-10-12 14:13:25 +0100 | |
---|---|---|
committer | 2021-10-20 07:59:43 +0000 | |
commit | 327cfcf2dfe281de4ac8178da69e1e562881870d (patch) | |
tree | 7655b166c3b46d38077ef84f02234e3a122eb403 | |
parent | 685d0ef479966811ec103340ef9696f056649285 (diff) |
Use the .dm file at runtime for verification.
Bug: 112284845
Test: 674-HelloWorld-Dm
Change-Id: Icd07f86cfb2b5428186a4c086f042890eaad249b
-rw-r--r-- | TEST_MAPPING | 6 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 35 | ||||
-rw-r--r-- | dex2oat/dex2oat_vdex_test.cc | 4 | ||||
-rw-r--r-- | libartbase/base/file_utils.cc | 4 | ||||
-rw-r--r-- | libartbase/base/file_utils.h | 3 | ||||
-rw-r--r-- | runtime/class_linker.cc | 1 | ||||
-rw-r--r-- | runtime/oat_file_assistant.cc | 40 | ||||
-rw-r--r-- | runtime/oat_file_assistant.h | 4 | ||||
-rw-r--r-- | runtime/vdex_file.cc | 36 | ||||
-rw-r--r-- | runtime/vdex_file.h | 3 | ||||
-rw-r--r-- | test/674-HelloWorld-Dm/Android.bp | 40 | ||||
-rw-r--r-- | test/674-HelloWorld-Dm/expected-stdout.txt | 1 | ||||
-rw-r--r-- | test/674-HelloWorld-Dm/run | 8 | ||||
-rwxr-xr-x | test/etc/run-test-jar | 17 | ||||
-rwxr-xr-x | test/utils/regen-test-files | 1 |
15 files changed, 115 insertions, 88 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index 983d5c9b7d..c2557f23f8 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1046,9 +1046,6 @@ "name": "art-run-test-673-checker-throw-vmethod[com.google.android.art.apex]" }, { - "name": "art-run-test-674-HelloWorld-Dm[com.google.android.art.apex]" - }, - { "name": "art-run-test-676-proxy-jit-at-first-use[com.google.android.art.apex]" }, { @@ -2245,9 +2242,6 @@ "name": "art-run-test-673-checker-throw-vmethod" }, { - "name": "art-run-test-674-HelloWorld-Dm" - }, - { "name": "art-run-test-676-proxy-jit-at-first-use" }, { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index bb6dd8554d..0090d58100 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1343,38 +1343,9 @@ class Dex2Oat final { if (dm_file_ != nullptr) { DCHECK(input_vdex_file_ == nullptr); - std::string error_msg; - static const char* kDexMetadata = "DexMetadata"; - std::unique_ptr<ZipEntry> zip_entry(dm_file_->Find(VdexFile::kVdexNameInDmFile, &error_msg)); - if (zip_entry == nullptr) { - LOG(INFO) << "No " << VdexFile::kVdexNameInDmFile << " file in DexMetadata archive. " - << "Not doing fast verification."; - } else { - MemMap input_file = zip_entry->MapDirectlyOrExtract( - VdexFile::kVdexNameInDmFile, - kDexMetadata, - &error_msg, - alignof(VdexFile)); - if (!input_file.IsValid()) { - LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg; - } else { - input_vdex_file_ = std::make_unique<VdexFile>(std::move(input_file)); - if (!input_vdex_file_->IsValid()) { - // Ideally we would do this validation at the framework level but the framework - // has not knowledge of the .vdex format and adding new APIs just for it is - // overkill. - // TODO(calin): include this in dex2oat metrics. - LOG(WARNING) << "The dex metadata .vdex is not valid. Ignoring it."; - input_vdex_file_ = nullptr; - } else { - if (input_vdex_file_->HasDexSection()) { - LOG(ERROR) << "The dex metadata is not allowed to contain dex files"; - android_errorWriteLog(0x534e4554, "178055795"); // Report to SafetyNet. - return false; - } - VLOG(verifier) << "Doing fast verification with vdex from DexMetadata archive"; - } - } + input_vdex_file_ = VdexFile::OpenFromDm(dm_file_location_, *dm_file_); + if (input_vdex_file_ != nullptr) { + VLOG(verifier) << "Doing fast verification with vdex from DexMetadata archive"; } } diff --git a/dex2oat/dex2oat_vdex_test.cc b/dex2oat/dex2oat_vdex_test.cc index 3b980e0784..1f486e6aec 100644 --- a/dex2oat/dex2oat_vdex_test.cc +++ b/dex2oat/dex2oat_vdex_test.cc @@ -233,8 +233,8 @@ TEST_F(Dex2oatVdexTest, VerifyPublicSdkStubsWithDexFiles) { extra_args.push_back("--dm-file=" + dm_file); // Recompile again with the .dm file which contains a vdex with code. - // The compilation should fail. - ASSERT_FALSE(RunDex2oat( + // The compilation will pass, but dex2oat will not use the vdex file. + ASSERT_TRUE(RunDex2oat( dex_file->GetLocation(), GetOdex(dex_file, "v2"), /*public_sdk=*/ nullptr, diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc index 0cbc77b6c5..9337e9f949 100644 --- a/libartbase/base/file_utils.cc +++ b/libartbase/base/file_utils.cc @@ -519,6 +519,10 @@ std::string GetVdexFilename(const std::string& oat_location) { return ReplaceFileExtension(oat_location, "vdex"); } +std::string GetDmFilename(const std::string& dex_location) { + return ReplaceFileExtension(dex_location, "dm"); +} + std::string GetSystemOdexFilenameForApex(std::string_view location, InstructionSet isa) { DCHECK(LocationIsOnApex(location)); std::string dir = GetAndroidRoot() + "/framework/oat/" + GetInstructionSetString(isa); diff --git a/libartbase/base/file_utils.h b/libartbase/base/file_utils.h index 33ea2e9e4a..c3a8c9c096 100644 --- a/libartbase/base/file_utils.h +++ b/libartbase/base/file_utils.h @@ -126,6 +126,9 @@ std::string GetSystemImageFilename(const char* location, InstructionSet isa); // Returns the vdex filename for the given oat filename. std::string GetVdexFilename(const std::string& oat_filename); +// Returns the dm filename for the given dex location. +std::string GetDmFilename(const std::string& dex_location); + // Returns the odex location on /system for a DEX file on /apex. The caller must make sure that // `location` is on /apex. std::string GetSystemOdexFilenameForApex(std::string_view location, InstructionSet isa); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 454a20fa11..7dd584afc8 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4740,6 +4740,7 @@ bool ClassLinker::VerifyClassUsingOatFile(Thread* self, if (oat_file != nullptr) { ClassStatus vdex_status = oat_file->GetVdexFile()->ComputeClassStatus(self, klass); if (vdex_status >= ClassStatus::kVerifiedNeedsAccessChecks) { + VLOG(verifier) << "Vdex verification success for " << klass->PrettyClass(); oat_file_class_status = vdex_status; return true; } diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index a0b0055e36..414b24e419 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -34,6 +34,7 @@ #include "base/string_view_cpp20.h" #include "base/systrace.h" #include "base/utils.h" +#include "base/zip_archive.h" #include "class_linker.h" #include "class_loader_context.h" #include "dex/art_dex_file_loader.h" @@ -53,6 +54,7 @@ using android::base::StringPrintf; static constexpr const char* kAnonymousDexPrefix = "Anonymous-DexFile@"; static constexpr const char* kVdexExtension = ".vdex"; +static constexpr const char* kDmExtension = ".dm"; std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status) { switch (status) { @@ -107,6 +109,8 @@ OatFileAssistant::OatFileAssistant(const char* dex_location, oat_(this, /*is_oat_location=*/ true), vdex_for_odex_(this, /*is_oat_location=*/ false), vdex_for_oat_(this, /*is_oat_location=*/ true), + dm_for_odex_(this, /*is_oat_location=*/ false), + dm_for_oat_(this, /*is_oat_location=*/ true), zip_fd_(zip_fd) { CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location"; CHECK(!load_executable || context != nullptr) << "Loading executable without a context"; @@ -141,6 +145,13 @@ OatFileAssistant::OatFileAssistant(const char* dex_location, DupCloexec(zip_fd), DupCloexec(vdex_fd), DupCloexec(oat_fd)); + + std::string dm_file_name = GetDmFilename(dex_location_); + dm_for_odex_.Reset(dm_file_name, + UseFdToReadFiles(), + DupCloexec(zip_fd), + DupCloexec(vdex_fd), + DupCloexec(oat_fd)); } else { LOG(WARNING) << "Failed to determine odex file name: " << error_msg; } @@ -152,6 +163,8 @@ OatFileAssistant::OatFileAssistant(const char* dex_location, oat_.Reset(oat_file_name, /*use_fd=*/ false); std::string vdex_file_name = GetVdexFilename(oat_file_name); vdex_for_oat_.Reset(vdex_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd); + std::string dm_file_name = GetDmFilename(dex_location); + dm_for_oat_.Reset(dm_file_name, UseFdToReadFiles(), zip_fd, vdex_fd, oat_fd); } else { LOG(WARNING) << "Failed to determine oat file name for dex location " << dex_location_ << ": " << error_msg; @@ -702,8 +715,12 @@ OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() { // If the odex is not useable, and we have a useable vdex, return the vdex // instead. - if (!odex_.IsUseable() && vdex_for_odex_.IsUseable()) { - return vdex_for_odex_; + if (!odex_.IsUseable()) { + if (vdex_for_odex_.IsUseable()) { + return vdex_for_odex_; + } else if (dm_for_odex_.IsUseable()) { + return dm_for_odex_; + } } return odex_; } @@ -729,6 +746,12 @@ OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() { if (vdex_for_odex_.IsUseable()) { return vdex_for_odex_; } + if (dm_for_oat_.IsUseable()) { + return dm_for_oat_; + } + if (dm_for_odex_.IsUseable()) { + return dm_for_odex_; + } // We got into the worst situation here: // - the oat location is not useable @@ -873,6 +896,19 @@ const OatFile* OatFileAssistant::OatFileInfo::GetFile() { oat_file_assistant_->dex_location_, &error_msg)); } + } else if (android::base::EndsWith(filename_, kDmExtension)) { + executable = false; + // Check to see if there is a vdex file we can make use of. + std::unique_ptr<ZipArchive> dm_file(ZipArchive::Open(filename_.c_str(), &error_msg)); + if (dm_file != nullptr) { + std::unique_ptr<VdexFile> vdex(VdexFile::OpenFromDm(filename_, *dm_file)); + if (vdex != nullptr) { + file_.reset(OatFile::OpenFromVdex(zip_fd_, + std::move(vdex), + oat_file_assistant_->dex_location_, + &error_msg)); + } + } } else { if (executable && oat_file_assistant_->only_load_trusted_executable_) { executable = LocationIsTrusted(filename_, /*trust_art_apex_data_files=*/ true); diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 9cfa781cff..c243cc3a54 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -452,6 +452,10 @@ class OatFileAssistant { // it is out of date). OatFileInfo vdex_for_oat_; + // The vdex-only file next to the apk. + OatFileInfo dm_for_odex_; + OatFileInfo dm_for_oat_; + // File descriptor corresponding to apk, dex file, or zip. int zip_fd_; diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index 967167961c..58bb357fb9 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -23,12 +23,14 @@ #include <unordered_set> #include <android-base/logging.h> +#include <log/log.h> #include "base/bit_utils.h" #include "base/leb128.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/unix_file/fd_file.h" +#include "base/zip_archive.h" #include "class_linker.h" #include "class_loader_context.h" #include "dex/art_dex_file_loader.h" @@ -166,6 +168,37 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, return vdex; } +std::unique_ptr<VdexFile> VdexFile::OpenFromDm(const std::string& filename, + const ZipArchive& archive) { + std::string error_msg; + std::unique_ptr<ZipEntry> zip_entry(archive.Find(VdexFile::kVdexNameInDmFile, &error_msg)); + if (zip_entry == nullptr) { + LOG(INFO) << "No " << VdexFile::kVdexNameInDmFile << " file in DexMetadata archive. " + << "Not doing fast verification."; + return nullptr; + } + MemMap input_file = zip_entry->MapDirectlyOrExtract( + filename.c_str(), + VdexFile::kVdexNameInDmFile, + &error_msg, + alignof(VdexFile)); + if (!input_file.IsValid()) { + LOG(WARNING) << "Could not open vdex file in DexMetadata archive: " << error_msg; + return nullptr; + } + std::unique_ptr<VdexFile> vdex_file = std::make_unique<VdexFile>(std::move(input_file)); + if (!vdex_file->IsValid()) { + LOG(WARNING) << "The dex metadata .vdex is not valid. Ignoring it."; + return nullptr; + } + if (vdex_file->HasDexSection()) { + LOG(ERROR) << "The dex metadata is not allowed to contain dex files"; + android_errorWriteLog(0x534e4554, "178055795"); // Report to SafetyNet. + return nullptr; + } + return vdex_file; +} + const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor, uint32_t dex_file_index) const { DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End())); if (cursor == nullptr) { @@ -506,6 +539,9 @@ ClassStatus VdexFile::ComputeClassStatus(Thread* self, Handle<mirror::Class> cls DCHECK(destination->IsResolved() && source->IsResolved()); if (!destination->IsAssignableFrom(source.Get())) { + VLOG(verifier) << "Vdex checking failed for " << cls->PrettyClass() + << ": expected " << destination->PrettyClass() + << " to be assignable from " << source->PrettyClass(); // An implicit assignability check is failing in the code, return that the // class is not verified. return ClassStatus::kResolved; diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h index a66ff88fb2..35be4fb1ac 100644 --- a/runtime/vdex_file.h +++ b/runtime/vdex_file.h @@ -246,6 +246,9 @@ class VdexFile { error_msg); } + static std::unique_ptr<VdexFile> OpenFromDm(const std::string& filename, + const ZipArchive& archive); + const uint8_t* Begin() const { return mmap_.Begin(); } const uint8_t* End() const { return mmap_.End(); } size_t Size() const { return mmap_.Size(); } diff --git a/test/674-HelloWorld-Dm/Android.bp b/test/674-HelloWorld-Dm/Android.bp deleted file mode 100644 index 3c55af76f3..0000000000 --- a/test/674-HelloWorld-Dm/Android.bp +++ /dev/null @@ -1,40 +0,0 @@ -// Generated by `regen-test-files`. Do not edit manually. - -// Build rules for ART run-test `674-HelloWorld-Dm`. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "art_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["art_license"], -} - -// Test's Dex code. -java_test { - name: "art-run-test-674-HelloWorld-Dm", - defaults: ["art-run-test-defaults"], - test_config_template: ":art-run-test-target-template", - srcs: ["src/**/*.java"], - data: [ - ":art-run-test-674-HelloWorld-Dm-expected-stdout", - ":art-run-test-674-HelloWorld-Dm-expected-stderr", - ], -} - -// Test's expected standard output. -genrule { - name: "art-run-test-674-HelloWorld-Dm-expected-stdout", - out: ["art-run-test-674-HelloWorld-Dm-expected-stdout.txt"], - srcs: ["expected-stdout.txt"], - cmd: "cp -f $(in) $(out)", -} - -// Test's expected standard error. -genrule { - name: "art-run-test-674-HelloWorld-Dm-expected-stderr", - out: ["art-run-test-674-HelloWorld-Dm-expected-stderr.txt"], - srcs: ["expected-stderr.txt"], - cmd: "cp -f $(in) $(out)", -} diff --git a/test/674-HelloWorld-Dm/expected-stdout.txt b/test/674-HelloWorld-Dm/expected-stdout.txt index af5626b4a1..95e75d98db 100644 --- a/test/674-HelloWorld-Dm/expected-stdout.txt +++ b/test/674-HelloWorld-Dm/expected-stdout.txt @@ -1 +1,2 @@ Hello, world! +Hello, world! diff --git a/test/674-HelloWorld-Dm/run b/test/674-HelloWorld-Dm/run index 199ffc31e1..b8a61c55ee 100644 --- a/test/674-HelloWorld-Dm/run +++ b/test/674-HelloWorld-Dm/run @@ -14,4 +14,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -exec ${RUN} --dm "${@}" +${RUN} --dex2oat-dm "${@}" +return_status1=$? + +${RUN} --runtime-dm "${@}" +return_status2=$? + +(exit ${return_status1}) && (exit ${return_status2}) diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 56cb4a8c0c..9d7dc7e573 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -101,7 +101,8 @@ VDEX_ARGS="" EXTERNAL_LOG_TAGS="n" # if y respect externally set ANDROID_LOG_TAGS. DRY_RUN="n" # if y prepare to run the test but don't run it. TEST_VDEX="n" -TEST_DM="n" +TEST_DEX2OAT_DM="n" +TEST_RUNTIME_DM="n" TEST_IS_NDEBUG="n" APP_IMAGE="y" SECONDARY_APP_IMAGE="y" @@ -479,8 +480,11 @@ while true; do elif [ "x$1" = "x--vdex" ]; then TEST_VDEX="y" shift - elif [ "x$1" = "x--dm" ]; then - TEST_DM="y" + elif [ "x$1" = "x--dex2oat-dm" ]; then + TEST_DEX2OAT_DM="y" + shift + elif [ "x$1" = "x--runtime-dm" ]; then + TEST_RUNTIME_DM="y" shift elif [ "x$1" = "x--vdex-filter" ]; then shift @@ -1085,10 +1089,13 @@ function write_dex2oat_cmdlines { else vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --input-vdex=$DEX_LOCATION/oat/$ISA/$name.vdex" fi - elif [ "$TEST_DM" = "y" ]; then + elif [ "$TEST_DEX2OAT_DM" = "y" ]; then + vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --dump-timings --dm-file=$DEX_LOCATION/oat/$ISA/$name.dm" dex2oat_cmdline="${dex2oat_cmdline} --copy-dex-files=false --output-vdex=$DEX_LOCATION/oat/$ISA/primary.vdex" dm_cmdline="zip -qj $DEX_LOCATION/oat/$ISA/$name.dm $DEX_LOCATION/oat/$ISA/primary.vdex" - vdex_cmdline="${dex2oat_cmdline} ${VDEX_ARGS} --dump-timings --dm-file=$DEX_LOCATION/oat/$ISA/$name.dm" + elif [ "$TEST_RUNTIME_DM" = "y" ]; then + dex2oat_cmdline="${dex2oat_cmdline} --copy-dex-files=false --output-vdex=$DEX_LOCATION/oat/$ISA/primary.vdex" + dm_cmdline="zip -qj $DEX_LOCATION/$name.dm $DEX_LOCATION/oat/$ISA/primary.vdex" fi } diff --git a/test/utils/regen-test-files b/test/utils/regen-test-files index 6221980586..f03d3f2819 100755 --- a/test/utils/regen-test-files +++ b/test/utils/regen-test-files @@ -115,6 +115,7 @@ known_failing_tests = [ "178-app-image-native-method", "179-nonvirtual-jni", "450-checker-types", + "674-HelloWorld-Dm", "1900-track-alloc", "1901-get-bytecodes", "1902-suspend", |