Create vdex file for dex loaded with InMemoryDexClassLoader
Previous CL introduced a background verification thread for dex bytecode
loaded with InMemoryDexClassLoader. Extend the logic to collect the
results of class verification into an instance of VerifierDeps and dump
it into a vdex file in the app's data folder.
The background thread does not collect full VerifierDeps (e.g.
assignability dependencies, etc), just a bit vector of whether a class
was successfully verified or not.
The vdex format is extended to include boot classpath checksums and the
class loader context it was created for. These are optional and
currently left empty for regular vdex files.
The generated vdex files are treated as a cache with a limited capacity,
currently capped at 8 files. The least recently used file (in terms of
atime reported by stat()) is unlinked if the cache is full and a new
vdex is about to be generated.
Bug: 72131483
Test: art/tools/run-libcore-tests.sh
Test: art/test.py -b -r -t 692 -t 693
Change-Id: I26080d894d34d8f35f00c7925db569f22f008d2c
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f122e57..b5e7ce8 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -19,6 +19,7 @@
#include <sstream>
#include <sys/stat.h>
+#include "zlib.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -31,6 +32,7 @@
#include "base/string_view_cpp20.h"
#include "base/utils.h"
#include "class_linker.h"
+#include "class_loader_context.h"
#include "compiler_filter.h"
#include "dex/art_dex_file_loader.h"
#include "dex/dex_file_loader.h"
@@ -42,12 +44,14 @@
#include "runtime.h"
#include "scoped_thread_state_change-inl.h"
#include "vdex_file.h"
-#include "class_loader_context.h"
namespace art {
using android::base::StringPrintf;
+static constexpr const char* kAnonymousDexPrefix = "Anonymous-DexFile@";
+static constexpr const char* kVdexExtension = ".vdex";
+
std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status) {
switch (status) {
case OatFileAssistant::kOatCannotOpen:
@@ -429,6 +433,54 @@
return kOatUpToDate;
}
+bool OatFileAssistant::AnonymousDexVdexLocation(const std::vector<const DexFile::Header*>& headers,
+ InstructionSet isa,
+ /* out */ uint32_t* location_checksum,
+ /* out */ std::string* dex_location,
+ /* out */ std::string* vdex_filename) {
+ uint32_t checksum = adler32(0L, Z_NULL, 0);
+ for (const DexFile::Header* header : headers) {
+ checksum = adler32_combine(checksum,
+ header->checksum_,
+ header->file_size_ - DexFile::kNumNonChecksumBytes);
+ }
+ *location_checksum = checksum;
+
+ const std::string& data_dir = Runtime::Current()->GetProcessDataDirectory();
+ if (data_dir.empty() || Runtime::Current()->IsZygote()) {
+ *dex_location = StringPrintf("%s%u", kAnonymousDexPrefix, checksum);
+ return false;
+ }
+ *dex_location = StringPrintf("%s/%s%u.jar", data_dir.c_str(), kAnonymousDexPrefix, checksum);
+
+ std::string odex_filename;
+ std::string error_msg;
+ if (!DexLocationToOdexFilename(*dex_location, isa, &odex_filename, &error_msg)) {
+ LOG(WARNING) << "Could not get odex filename for " << *dex_location << ": " << error_msg;
+ return false;
+ }
+
+ *vdex_filename = GetVdexFilename(odex_filename);
+ return true;
+}
+
+bool OatFileAssistant::IsAnonymousVdexBasename(const std::string& basename) {
+ DCHECK(basename.find('/') == std::string::npos);
+ // `basename` must have format: <kAnonymousDexPrefix><checksum><kVdexExtension>
+ if (basename.size() < strlen(kAnonymousDexPrefix) + strlen(kVdexExtension) + 1 ||
+ !android::base::StartsWith(basename.c_str(), kAnonymousDexPrefix) ||
+ !android::base::EndsWith(basename, kVdexExtension)) {
+ return false;
+ }
+ // Check that all characters between the prefix and extension are decimal digits.
+ for (size_t i = strlen(kAnonymousDexPrefix); i < basename.size() - strlen(kVdexExtension); ++i) {
+ if (!std::isdigit(basename[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
static bool DexLocationToOdexNames(const std::string& location,
InstructionSet isa,
std::string* odex_filename,