Use the .dm file at runtime for verification.
Bug: 112284845
Test: 674-HelloWorld-Dm
Change-Id: Icd07f86cfb2b5428186a4c086f042890eaad249b
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 983d5c9..c2557f2 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 bb6dd85..0090d58 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1343,38 +1343,9 @@
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 3b980e0..1f486e6 100644
--- a/dex2oat/dex2oat_vdex_test.cc
+++ b/dex2oat/dex2oat_vdex_test.cc
@@ -233,8 +233,8 @@
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 0cbc77b..9337e9f 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -519,6 +519,10 @@
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 33ea2e9..c3a8c9c 100644
--- a/libartbase/base/file_utils.h
+++ b/libartbase/base/file_utils.h
@@ -126,6 +126,9 @@
// 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 454a20f..7dd584a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4740,6 +4740,7 @@
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 a0b0055..414b24e 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 9cfa781..c243cc3 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -452,6 +452,10 @@
// 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 9671679..58bb357 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 @@
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 @@
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 a66ff88..35be4fb 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -246,6 +246,9 @@
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 3c55af7..0000000
--- 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 af5626b..95e75d9 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 199ffc3..b8a61c5 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 56cb4a8..9d7dc7e 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -101,7 +101,8 @@
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 @@
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 @@
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 6221980..f03d3f2 100755
--- a/test/utils/regen-test-files
+++ b/test/utils/regen-test-files
@@ -115,6 +115,7 @@
"178-app-image-native-method",
"179-nonvirtual-jni",
"450-checker-types",
+ "674-HelloWorld-Dm",
"1900-track-alloc",
"1901-get-bytecodes",
"1902-suspend",