Merge art-cache dex files into oat files
Change-Id: I5a327a4e0b678bd9dabb12de4e21ef05e3fefd0b
diff --git a/src/card_table.cc b/src/card_table.cc
index 13491d8..430918a 100644
--- a/src/card_table.cc
+++ b/src/card_table.cc
@@ -62,7 +62,8 @@
/* Set up the card table */
size_t length = heap_max_size / GC_CARD_SIZE;
/* Allocate an extra 256 bytes to allow fixed low-byte of base */
- mem_map_.reset(MemMap::Map("dalvik-card-table", NULL, length + 256, PROT_READ | PROT_WRITE));
+ mem_map_.reset(
+ MemMap::MapAnonymous("dalvik-card-table", NULL, length + 256, PROT_READ | PROT_WRITE));
byte* alloc_base = mem_map_->GetAddress();
if (alloc_base == NULL) {
return false;
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5a3887a..e3b30d7 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -733,7 +733,6 @@
}
void ClassLinker::InitFromImage() {
- const Runtime* runtime = Runtime::Current();
VLOG(startup) << "ClassLinker::InitFromImage entering";
CHECK(!init_done_);
@@ -759,17 +758,13 @@
for (int i = 0; i < dex_caches->GetLength(); i++) {
SirtRef<DexCache> dex_cache(dex_caches->Get(i));
const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
-
- std::string dex_filename;
- dex_filename += runtime->GetHostPrefix();
- dex_filename += dex_file_location;
- const DexFile* dex_file = DexFile::Open(dex_filename, runtime->GetHostPrefix());
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
+ const DexFile* dex_file = oat_dex_file->OpenDexFile();
if (dex_file == NULL) {
- LOG(FATAL) << "Failed to open dex file " << dex_filename
- << " referenced from oat file as " << dex_file_location;
+ LOG(FATAL) << "Failed to open dex file " << dex_file_location
+ << " from within oat file " << oat_file->GetLocation();
}
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file->GetDexFileChecksum());
AppendToBootClassPath(*dex_file, dex_cache);
@@ -1789,7 +1784,7 @@
SirtRef<Method> prototype(methods->Get(i));
CheckProxyMethod(klass->GetVirtualMethod(i), prototype);
}
- std::string throws_field_name = "java.lang.Class[][] ";
+ std::string throws_field_name("java.lang.Class[][] ");
throws_field_name += name->ToModifiedUtf8();
throws_field_name += ".throws";
CHECK(PrettyField(klass->GetStaticField(0)) == throws_field_name);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index f668cc9..36d4744 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -112,7 +112,7 @@
return NULL;
}
UniquePtr<File> file(OS::OpenFile(outputName.c_str(), true));
- bool success = zip_entry->Extract(*file);
+ bool success = zip_entry->ExtractToFile(*file);
if (!success) {
LOG(ERROR) << "Failed to extract classes.dex from " << sourceName.c_str();
return NULL;
diff --git a/src/dex_file.cc b/src/dex_file.cc
index ce7dde6..a45455d 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -76,15 +76,25 @@
}
}
+const std::string StripLocationPrefix(const std::string& original_location,
+ const std::string& strip_location_prefix) {
+ StringPiece location = original_location;
+ if (!location.starts_with(strip_location_prefix)) {
+ LOG(ERROR) << location << " does not start with " << strip_location_prefix;
+ return "";
+ }
+ location.remove_prefix(strip_location_prefix.size());
+ return location.ToString();
+}
+
const DexFile* DexFile::OpenFile(const std::string& filename,
const std::string& original_location,
const std::string& strip_location_prefix) {
- StringPiece location = original_location;
- if (!location.starts_with(strip_location_prefix)) {
- LOG(ERROR) << filename << " does not start with " << strip_location_prefix;
+ std::string location(StripLocationPrefix(original_location, strip_location_prefix));
+ if (location.empty()) {
return NULL;
}
- location.remove_prefix(strip_location_prefix.size());
+
int fd = open(filename.c_str(), O_RDONLY); // TODO: scoped_fd
if (fd == -1) {
PLOG(ERROR) << "open(\"" << filename << "\", O_RDONLY) failed";
@@ -98,15 +108,14 @@
return NULL;
}
size_t length = sbuf.st_size;
- UniquePtr<MemMap> map(MemMap::Map(length, PROT_READ, MAP_PRIVATE, fd, 0));
+ UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0));
if (map.get() == NULL) {
LOG(ERROR) << "mmap \"" << filename << "\" failed";
close(fd);
return NULL;
}
close(fd);
- byte* dex_file = map->GetAddress();
- return OpenMemory(dex_file, length, location.ToString(), map.release());
+ return OpenMemory(location, map.release());
}
const char* DexFile::kClassesDex = "classes.dex";
@@ -168,44 +177,10 @@
// Open classes.dex from within a .zip, .jar, .apk, ...
const DexFile* DexFile::OpenZip(const std::string& filename,
const std::string& strip_location_prefix) {
- // First, look for a ".dex" alongside the jar file. It will have
- // the same name/path except for the extension.
-
- // Example filename = dir/foo.jar
- std::string adjacent_dex_filename(filename);
- size_t found = adjacent_dex_filename.find_last_of(".");
- if (found == std::string::npos) {
- LOG(ERROR) << "No . in filename" << filename;
+ std::string location(StripLocationPrefix(filename, strip_location_prefix));
+ if (location.empty()) {
return NULL;
}
- adjacent_dex_filename.replace(adjacent_dex_filename.begin() + found,
- adjacent_dex_filename.end(),
- ".dex");
- // Example adjacent_dex_filename = dir/foo.dex
- if (OS::FileExists(adjacent_dex_filename.c_str())) {
- const DexFile* adjacent_dex_file = DexFile::OpenFile(adjacent_dex_filename,
- filename,
- strip_location_prefix);
- if (adjacent_dex_file != NULL) {
- // We don't verify anything in this case, because we aren't in
- // the cache and typically the file is in the readonly /system
- // area, so if something is wrong, there is nothing we can do.
- return adjacent_dex_file;
- }
- return NULL;
- }
-
- UniquePtr<char[]> resolved(new char[PATH_MAX]);
- char* absolute_path = realpath(filename.c_str(), resolved.get());
- if (absolute_path == NULL) {
- LOG(ERROR) << "Failed to create absolute path for " << filename
- << " when looking for classes.dex";
- return NULL;
- }
- std::string cache_path_tmp(GetArtCacheFilenameOrDie(absolute_path));
- cache_path_tmp.push_back('@');
- cache_path_tmp.append(kClassesDex);
- // Example cache_path_tmp = /data/art-cache/parent@dir@foo.jar@classes.dex
UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(filename));
if (zip_archive.get() == NULL) {
@@ -218,121 +193,32 @@
return NULL;
}
- std::string cache_path(StringPrintf("%s.%08x", cache_path_tmp.c_str(), zip_entry->GetCrc32()));
- // Example cache_path = /data/art-cache/parent@dir@foo.jar@classes.dex.1a2b3c4d
-
- bool created = false;
- while (true) {
- if (OS::FileExists(cache_path.c_str())) {
- const DexFile* cached_dex_file = DexFile::OpenFile(cache_path,
- filename,
- strip_location_prefix);
- if (cached_dex_file != NULL) {
- return cached_dex_file;
- }
- if (created) {
- // We created the dex file with the correct checksum,
- // there must be something wrong with the file itself.
- return NULL;
- }
- }
-
- // Try to open the temporary cache file, grabbing an exclusive
- // lock. If somebody else is working on it, we'll block here until
- // they complete. Because we're waiting on an external resource,
- // we go into native mode.
- // Note that self can be NULL if we're parsing the bootclasspath
- // during JNI_CreateJavaVM.
- Thread* self = Thread::Current();
- UniquePtr<ScopedThreadStateChange> state_changer;
- if (self != NULL) {
- state_changer.reset(new ScopedThreadStateChange(self, Thread::kNative));
- }
- UniquePtr<LockedFd> fd(LockedFd::CreateAndLock(cache_path_tmp, 0644));
- state_changer.reset(NULL);
- if (fd.get() == NULL) {
- PLOG(ERROR) << "Failed to lock file '" << cache_path_tmp << "'";
- return NULL;
- }
-
- // Check to see if the fd we opened and locked matches the file in
- // the filesystem. If they don't, then somebody else unlinked
- // ours and created a new file, and we need to use that one
- // instead. (If we caught them between the unlink and the create,
- // we'll get an ENOENT from the file stat.)
- struct stat fd_stat;
- int fd_stat_result = fstat(fd->GetFd(), &fd_stat);
- if (fd_stat_result == -1) {
- PLOG(ERROR) << "Failed to stat open file '" << cache_path_tmp << "'";
- return NULL;
- }
- struct stat file_stat;
- int file_stat_result = stat(cache_path_tmp.c_str(), &file_stat);
- if (file_stat_result == -1 ||
- fd_stat.st_dev != file_stat.st_dev || fd_stat.st_ino != file_stat.st_ino) {
- LOG(WARNING) << "our open cache file is stale; sleeping and retrying";
- usleep(250 * 1000); // if something is hosed, don't peg machine
- continue;
- }
-
- // We have the correct file open and locked. Extract classes.dex
- TmpFile tmp_file(cache_path_tmp);
- UniquePtr<File> file(OS::FileFromFd(cache_path_tmp.c_str(), fd->GetFd()));
- if (file.get() == NULL) {
- LOG(ERROR) << "Failed to create file for '" << cache_path_tmp << "'";
- return NULL;
- }
- bool success = zip_entry->Extract(*file);
- if (!success) {
- LOG(ERROR) << "Failed to extract classes.dex to '" << cache_path_tmp << "'";
- return NULL;
- }
-
- // TODO: restat and check length against zip_entry->GetUncompressedLength()?
-
- // Compute checksum and compare to zip. If things look okay, rename from tmp.
- off_t lseek_result = lseek(fd->GetFd(), 0, SEEK_SET);
- if (lseek_result == -1) {
- PLOG(ERROR) << "Failed to seek to start of '" << cache_path_tmp << "'";
- return NULL;
- }
- const size_t kBufSize = 32768;
- UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
- if (buf.get() == NULL) {
- LOG(ERROR) << "Failed to allocate buffer to checksum '" << cache_path_tmp << "'";
- return NULL;
- }
- uint32_t computed_crc = crc32(0L, Z_NULL, 0);
- while (true) {
- ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd->GetFd(), buf.get(), kBufSize));
- if (bytes_read == -1) {
- PLOG(ERROR) << "Problem computing CRC of '" << cache_path_tmp << "'";
- return NULL;
- }
- if (bytes_read == 0) {
- break;
- }
- computed_crc = crc32(computed_crc, buf.get(), bytes_read);
- }
- if (computed_crc != zip_entry->GetCrc32()) {
- LOG(ERROR) << "Failed to validate checksum for '" << cache_path_tmp << "'";
- return NULL;
- }
- int rename_result = rename(cache_path_tmp.c_str(), cache_path.c_str());
- if (rename_result == -1) {
- PLOG(ERROR) << "Failed to install dex cache file '" << cache_path << "'"
- << " from '" << cache_path_tmp << "'";
- unlink(cache_path.c_str());
- } else {
- created = true;
- }
+ uint32_t length = zip_entry->GetUncompressedLength();
+ UniquePtr<MemMap> map(MemMap::MapAnonymous("classes.dex extracted in memory",
+ NULL,
+ length,
+ PROT_READ | PROT_WRITE));
+ if (map.get() == NULL) {
+ LOG(ERROR) << "mmap classes.dex for \"" << filename << "\" failed";
+ return NULL;
}
- // NOTREACHED
+
+ // Extract classes.dex
+ bool success = zip_entry->ExtractToMemory(*map.get());
+ if (!success) {
+ LOG(ERROR) << "Failed to extract classes.dex from '" << filename << "' to memory";
+ return NULL;
+ }
+
+ return OpenMemory(location, map.release());
}
-const DexFile* DexFile::OpenMemory(const byte* dex_bytes, size_t length,
- const std::string& location, MemMap* mem_map) {
- UniquePtr<DexFile> dex_file(new DexFile(dex_bytes, length, location, mem_map));
+const DexFile* DexFile::OpenMemory(const byte* base,
+ size_t length,
+ const std::string& location,
+ MemMap* mem_map) {
+ CHECK_ALIGNED(base, 4); // various dex file structures must be word aligned
+ UniquePtr<DexFile> dex_file(new DexFile(base, length, location, mem_map));
if (!dex_file->Init()) {
return NULL;
} else {
@@ -399,6 +285,7 @@
method_ids_ = reinterpret_cast<const MethodId*>(b + h->method_ids_off_);
proto_ids_ = reinterpret_cast<const ProtoId*>(b + h->proto_ids_off_);
class_defs_ = reinterpret_cast<const ClassDef*>(b + h->class_defs_off_);
+ DCHECK_EQ(length_, header_->file_size_);
}
bool DexFile::IsMagicValid() {
diff --git a/src/dex_file.h b/src/dex_file.h
index 1356c8c..a0363b0 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -184,6 +184,11 @@
static const DexFile* Open(const std::string& filename,
const std::string& strip_location_prefix);
+ // Opens .dex file, backed by existing memory
+ static const DexFile* Open(const uint8_t* base, size_t length, const std::string& location) {
+ return OpenMemory(base, length, location, NULL);
+ }
+
// Closes a .dex file.
virtual ~DexFile();
@@ -619,14 +624,23 @@
static const DexFile* OpenZip(const std::string& filename,
const std::string& strip_location_prefix);
- // Opens a .dex file at the given address.
+ // Opens a .dex file at the given address backed by a MemMap
+ static const DexFile* OpenMemory(const std::string& location,
+ MemMap* mem_map) {
+ return OpenMemory(mem_map->GetAddress(),
+ mem_map->GetLength(),
+ location,
+ mem_map);
+ }
+
+ // Opens a .dex file at the given address, optionally backed by a MemMap
static const DexFile* OpenMemory(const byte* dex_file,
size_t length,
const std::string& location,
MemMap* mem_map);
- DexFile(const byte* addr, size_t length, const std::string& location, MemMap* mem_map)
- : base_(addr),
+ DexFile(const byte* base, size_t length, const std::string& location, MemMap* mem_map)
+ : base_(base),
length_(length),
location_(location),
mem_map_(mem_map),
@@ -639,9 +653,8 @@
method_ids_(0),
proto_ids_(0),
class_defs_(0) {
- CHECK(addr != NULL) << GetLocation();
- CHECK_GT(length, 0U) << GetLocation();
- CHECK(mem_map != NULL) << GetLocation();
+ CHECK(base_ != NULL) << GetLocation();
+ CHECK_GT(length_, 0U) << GetLocation();
}
// Top-level initializer that calls other Init methods.
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 2f91dcd..342453d 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -1049,6 +1049,10 @@
if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
Fail(VERIFY_ERROR_GENERIC) << "bad exception entry: startAddr=" << start
<< " endAddr=" << end << " (size=" << insns_size << ")";
+ CHECK(false) << "XXX bdc "
+ << PrettyMethod(method_)
+ << "bad exception entry: startAddr=" << start
+ << " endAddr=" << end << " (size=" << insns_size << ")";
return false;
}
if (!insn_flags_[start].IsOpcode()) {
diff --git a/src/file.h b/src/file.h
index 3353602..babcb8b 100644
--- a/src/file.h
+++ b/src/file.h
@@ -27,11 +27,11 @@
// Get the length of the file. Returns a negative value if the length cannot
// be determined (e.g. not seekable device).
- virtual off_t Length() = 0;
+ virtual off64_t Length() = 0;
// Get the current position in the file.
// Returns a negative value if position cannot be determined.
- virtual off_t Position() = 0;
+ virtual off64_t Position() = 0;
virtual int Fd() = 0;
diff --git a/src/file_linux.cc b/src/file_linux.cc
index 367dbe8..1f4be51 100644
--- a/src/file_linux.cc
+++ b/src/file_linux.cc
@@ -43,21 +43,21 @@
}
-off_t LinuxFile::Position() {
+off64_t LinuxFile::Position() {
DCHECK_GE(fd_, 0);
- return lseek(fd_, 0, SEEK_CUR);
+ return lseek64(fd_, 0, SEEK_CUR);
}
-off_t LinuxFile::Length() {
+off64_t LinuxFile::Length() {
DCHECK_GE(fd_, 0);
- off_t position = lseek(fd_, 0, SEEK_CUR);
+ off64_t position = lseek64(fd_, 0, SEEK_CUR);
if (position < 0) {
// The file is not capable of seeking. Return an error.
return -1;
}
- off_t result = lseek(fd_, 0, SEEK_END);
- lseek(fd_, position, SEEK_SET);
+ off64_t result = lseek64(fd_, 0, SEEK_END);
+ lseek64(fd_, position, SEEK_SET);
return result;
}
diff --git a/src/file_linux.h b/src/file_linux.h
index 3d381d5..51605e2 100644
--- a/src/file_linux.h
+++ b/src/file_linux.h
@@ -19,8 +19,8 @@
virtual int64_t Read(void* buffer, int64_t num_bytes);
virtual int64_t Write(const void* buffer, int64_t num_bytes);
- virtual off_t Length();
- virtual off_t Position();
+ virtual off64_t Length();
+ virtual off64_t Position();
virtual int Fd() {
return fd_;
diff --git a/src/heap_bitmap.cc b/src/heap_bitmap.cc
index 4bd191a..2adeedc 100644
--- a/src/heap_bitmap.cc
+++ b/src/heap_bitmap.cc
@@ -37,7 +37,7 @@
bool HeapBitmap::Init(const char* name, const byte* base, size_t max_size) {
CHECK(base != NULL);
size_t length = HB_OFFSET_TO_INDEX(max_size) * kWordSize;
- mem_map_.reset(MemMap::Map(name, NULL, length, PROT_READ | PROT_WRITE));
+ mem_map_.reset(MemMap::MapAnonymous(name, NULL, length, PROT_READ | PROT_WRITE));
if (mem_map_.get() == NULL) {
return false;
}
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 8a03392..f6d144e 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -84,7 +84,7 @@
size_t size = source_space_->Size();
int prot = PROT_READ | PROT_WRITE;
size_t length = RoundUp(size, kPageSize);
- image_.reset(MemMap::Map("image-writer-image", NULL, length, prot));
+ image_.reset(MemMap::MapAnonymous("image-writer-image", NULL, length, prot));
if (image_.get() == NULL) {
LOG(ERROR) << "Failed to allocate memory for image file generation";
return false;
diff --git a/src/mark_stack.cc b/src/mark_stack.cc
index a35fa2d..53a342b 100644
--- a/src/mark_stack.cc
+++ b/src/mark_stack.cc
@@ -18,7 +18,7 @@
void MarkStack::Init() {
size_t length = 64 * MB;
- mem_map_.reset(MemMap::Map("dalvik-mark-stack", NULL, length, PROT_READ | PROT_WRITE));
+ mem_map_.reset(MemMap::MapAnonymous("dalvik-mark-stack", NULL, length, PROT_READ | PROT_WRITE));
CHECK(mem_map_.get() != NULL) << "MemMap::Map() failed; aborting";
byte* addr = mem_map_->GetAddress();
base_ = reinterpret_cast<const Object**>(addr);
diff --git a/src/mem_map.cc b/src/mem_map.cc
index c5858c1..09391df 100644
--- a/src/mem_map.cc
+++ b/src/mem_map.cc
@@ -103,7 +103,7 @@
#endif
}
-MemMap* MemMap::Map(const char* name, byte* addr, size_t length, int prot) {
+MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t length, int prot) {
CHECK_NE(0U, length);
CHECK_NE(0, prot);
size_t page_aligned_size = RoundUp(length, kPageSize);
@@ -129,7 +129,7 @@
return new MemMap(actual, length, actual, page_aligned_size);
}
-MemMap* MemMap::Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start) {
+MemMap* MemMap::MapFileAtAddress(byte* addr, size_t length, int prot, int flags, int fd, off_t start) {
CHECK_NE(0U, length);
CHECK_NE(0, prot);
CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
diff --git a/src/mem_map.h b/src/mem_map.h
index fa3904d..43e1cfd 100644
--- a/src/mem_map.h
+++ b/src/mem_map.h
@@ -36,14 +36,14 @@
// a name.
//
// On success, returns returns a MemMap instance. On failure, returns a NULL;
- static MemMap* Map(const char* ashmem_name, byte* addr, size_t length, int prot);
+ static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t length, int prot);
// Map part of a file, taking care of non-page aligned offsets. The
// "start" offset is absolute, not relative.
//
// On success, returns returns a MemMap instance. On failure, returns a NULL;
- static MemMap* Map(size_t length, int prot, int flags, int fd, off_t start) {
- return Map(NULL, length, prot, flags, fd, start);
+ static MemMap* MapFile(size_t length, int prot, int flags, int fd, off_t start) {
+ return MapFileAtAddress(NULL, length, prot, flags, fd, start);
}
// Map part of a file, taking care of non-page aligned offsets. The
@@ -51,7 +51,8 @@
// requesting a specific address for the base of the mapping.
//
// On success, returns returns a MemMap instance. On failure, returns a NULL;
- static MemMap* Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start);
+ static MemMap* MapFileAtAddress(
+ byte* addr, size_t length, int prot, int flags, int fd, off_t start);
// Releases the memory mapping
~MemMap();
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 472a20c..c37c7a6 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -54,12 +54,13 @@
return false;
}
- UniquePtr<MemMap> map(MemMap::Map(requested_base,
- file->Length(),
- PROT_READ,
- MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0),
- file->Fd(),
- 0));
+ int flags = MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0);
+ UniquePtr<MemMap> map(MemMap::MapFileAtAddress(requested_base,
+ file->Length(),
+ PROT_READ,
+ flags,
+ file->Fd(),
+ 0));
if (map.get() == NULL) {
LOG(WARNING) << "Failed to map oat file " << filename;
return false;
@@ -67,7 +68,7 @@
CHECK(requested_base == 0 || requested_base == map->GetAddress()) << map->GetAddress();
DCHECK_EQ(0, memcmp(&oat_header, map->GetAddress(), sizeof(OatHeader)));
- off_t code_offset = oat_header.GetExecutableOffset();
+ off64_t code_offset = oat_header.GetExecutableOffset();
if (code_offset < file->Length()) {
byte* code_address = map->GetAddress() + code_offset;
size_t code_length = file->Length() - code_offset;
@@ -98,6 +99,14 @@
oat += sizeof(dex_file_checksum);
CHECK_LT(oat, map->GetLimit());
+ uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
+ CHECK_GT(dex_file_offset, 0U);
+ CHECK_LT(dex_file_offset, static_cast<uint32_t>(file->Length()));
+ oat += sizeof(dex_file_offset);
+ CHECK_LT(oat, map->GetLimit());
+
+ uint8_t* dex_file_pointer = map->GetAddress() + dex_file_offset;
+
uint32_t classes_offset = *reinterpret_cast<const uint32_t*>(oat);
CHECK_GT(classes_offset, 0U);
CHECK_LT(classes_offset, static_cast<uint32_t>(file->Length()));
@@ -109,6 +118,7 @@
oat_dex_files_[dex_file_location] = new OatDexFile(this,
dex_file_location,
dex_file_checksum,
+ dex_file_pointer,
classes_pointer);
}
@@ -153,14 +163,21 @@
OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
std::string dex_file_location,
uint32_t dex_file_checksum,
+ byte* dex_file_pointer,
uint32_t* classes_pointer)
: oat_file_(oat_file),
dex_file_location_(dex_file_location),
dex_file_checksum_(dex_file_checksum),
+ dex_file_pointer_(dex_file_pointer),
classes_pointer_(classes_pointer) {}
OatFile::OatDexFile::~OatDexFile() {}
+const DexFile* OatFile::OatDexFile::OpenDexFile() const {
+ size_t length = reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
+ return DexFile::Open(dex_file_pointer_, length, dex_file_location_);
+}
+
const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
uint32_t methods_offset = classes_pointer_[class_def_index];
const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
diff --git a/src/oat_file.h b/src/oat_file.h
index 7bad2a1..a4d7534 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -132,6 +132,7 @@
class OatDexFile {
public:
+ const DexFile* OpenDexFile() const;
const OatClass* GetOatClass(uint32_t class_def_index) const;
const std::string& GetDexFileLocation() const {
@@ -147,11 +148,13 @@
OatDexFile(const OatFile* oat_file,
std::string dex_file_location,
uint32_t dex_file_checksum,
+ byte* dex_file_pointer,
uint32_t* classes_pointer);
const OatFile* oat_file_;
std::string dex_file_location_;
uint32_t dex_file_checksum_;
+ const byte* dex_file_pointer_;
const uint32_t* classes_pointer_;
friend class OatFile;
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 32ba4b1..3ab2fb9 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -29,6 +29,7 @@
size_t offset = InitOatHeader();
offset = InitOatDexFiles(offset);
+ offset = InitDexFiles(offset);
offset = InitOatClasses(offset);
offset = InitOatMethods(offset);
offset = InitOatCode(offset);
@@ -64,6 +65,21 @@
return offset;
}
+size_t OatWriter::InitDexFiles(size_t offset) {
+ // calculate the offsets within OatDexFiles to the DexFiles
+ for (size_t i = 0; i != dex_files_->size(); ++i) {
+ // dex files are required to be 4 byte aligned
+ offset = RoundUp(offset, 4);
+
+ // set offset in OatDexFile to DexFile
+ oat_dex_files_[i]->dex_file_offset_ = offset;
+
+ const DexFile* dex_file = (*dex_files_)[i];
+ offset += dex_file->GetHeader().file_size_;
+ }
+ return offset;
+}
+
size_t OatWriter::InitOatClasses(size_t offset) {
// create the OatClasses
// calculate the offsets within OatDexFiles to OatClasses
@@ -305,7 +321,7 @@
}
#define DCHECK_CODE_OFFSET() \
- DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
+ DCHECK_EQ(static_cast<off64_t>(code_offset), lseek64(file->Fd(), 0, SEEK_CUR))
bool OatWriter::Write(File* file) {
if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
@@ -340,6 +356,21 @@
return false;
}
}
+ for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
+ uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
+ off64_t actual_offset = lseek64(file->Fd(), expected_offset, SEEK_SET);
+ if (static_cast<uint32_t>(actual_offset) != expected_offset) {
+ const DexFile* dex_file = (*dex_files_)[i];
+ PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
+ << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
+ return false;
+ }
+ const DexFile* dex_file = (*dex_files_)[i];
+ if (!file->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
+ PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->name();
+ return false;
+ }
+ }
for (size_t i = 0; i != oat_classes_.size(); ++i) {
if (!oat_classes_[i]->Write(file)) {
PLOG(ERROR) << "Failed to write oat classes information to " << file->name();
@@ -357,7 +388,7 @@
size_t OatWriter::WriteCode(File* file) {
uint32_t code_offset = oat_header_->GetExecutableOffset();
- off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
+ off64_t new_offset = lseek64(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != code_offset) {
PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
<< " Expected: " << code_offset << " File: " << file->name();
@@ -458,7 +489,7 @@
uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
uint32_t aligned_code_delta = aligned_code_offset - code_offset;
if (aligned_code_delta != 0) {
- off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+ off64_t new_offset = lseek64(file->Fd(), aligned_code_delta, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
<< " Expected: " << aligned_code_offset << " File: " << file->name();
@@ -564,7 +595,7 @@
compiler_->GetInstructionSet());
uint32_t aligned_code_delta = aligned_code_offset - code_offset;
if (aligned_code_delta != 0) {
- off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+ off64_t new_offset = lseek64(file->Fd(), aligned_code_delta, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
<< " Expected: " << aligned_code_offset;
@@ -605,6 +636,7 @@
dex_file_location_size_ = location.size();
dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
dex_file_checksum_ = dex_file.GetHeader().checksum_;
+ dex_file_offset_ = 0;
classes_offset_ = 0;
}
@@ -612,6 +644,7 @@
return sizeof(dex_file_location_size_)
+ dex_file_location_size_
+ sizeof(dex_file_checksum_)
+ + sizeof(dex_file_offset_)
+ sizeof(classes_offset_);
}
@@ -619,6 +652,7 @@
oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
+ oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
oat_header.UpdateChecksum(&classes_offset_, sizeof(classes_offset_));
}
@@ -635,6 +669,10 @@
PLOG(ERROR) << "Failed to write dex file checksum to " << file->name();
return false;
}
+ if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
+ PLOG(ERROR) << "Failed to write dex file offset to " << file->name();
+ return false;
+ }
if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) {
PLOG(ERROR) << "Failed to write classes offset to " << file->name();
return false;
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 97cdb50..7d454a7 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -20,11 +20,16 @@
// OatHeader fixed length with count of D OatDexFiles
//
-// OatDexFile[0] each fixed length with offset to variable sized OatClasses
+// OatDexFile[0] one variable sized OatDexFile with offsets to Dex and OatClasses
// OatDexFile[1]
// ...
// OatDexFile[D]
//
+// Dex[0] one variable sized DexFile for each OatDexFile.
+// Dex[1] these are literal copies of the input .dex files.
+// ...
+// Dex[D]
+//
// OatClasses[0] one variable sized OatClasses for each OatDexFile
// OatClasses[1] contains DexFile::NumClassDefs offsets to OatMethods for each ClassDef
// ...
@@ -60,6 +65,7 @@
size_t InitOatHeader();
size_t InitOatDexFiles(size_t offset);
+ size_t InitDexFiles(size_t offset);
size_t InitOatClasses(size_t offset);
size_t InitOatMethods(size_t offset);
size_t InitOatCode(size_t offset);
@@ -100,6 +106,7 @@
uint32_t dex_file_location_size_;
const uint8_t* dex_file_location_data_;
uint32_t dex_file_checksum_;
+ uint32_t dex_file_offset_;
uint32_t classes_offset_;
private:
diff --git a/src/oatopt.cc b/src/oatopt.cc
index 314b7ee..5862431 100644
--- a/src/oatopt.cc
+++ b/src/oatopt.cc
@@ -29,7 +29,7 @@
}
UniquePtr<File> file(OS::FileFromFd("oatopt cache file descriptor", cache_fd));
- bool success = zip_entry->Extract(*file);
+ bool success = zip_entry->ExtractToFile(*file);
if (!success) {
LOG(ERROR) << "Failed to extract classes.dex from " << zip_name;
return -1;
diff --git a/src/space.cc b/src/space.cc
index 14731f1..053d2df 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -74,7 +74,7 @@
}
size_t length = RoundUp(maximum_size, kPageSize);
int prot = PROT_READ | PROT_WRITE;
- UniquePtr<MemMap> mem_map(MemMap::Map(name_.c_str(), requested_base, length, prot));
+ UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name_.c_str(), requested_base, length, prot));
if (mem_map.get() == NULL) {
LOG(WARNING) << "Failed to allocate " << length << " bytes for space: " << name_;
return false;
@@ -114,13 +114,13 @@
LOG(WARNING) << "Invalid image header " << image_file_name;
return false;
}
- UniquePtr<MemMap> map(MemMap::Map(image_header.GetImageBaseAddr(),
- file->Length(),
- // TODO: selectively PROT_EXEC an image subset containing stubs
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_FIXED,
- file->Fd(),
- 0));
+ UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBaseAddr(),
+ file->Length(),
+ // TODO: selectively PROT_EXEC stubs
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_FIXED,
+ file->Fd(),
+ 0));
if (map.get() == NULL) {
LOG(WARNING) << "Failed to map " << image_file_name;
return false;
diff --git a/src/utils.h b/src/utils.h
index 22afd5d..606f35d 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -35,14 +35,14 @@
template<int n, typename T>
static inline bool IsAligned(T* x) {
- return IsAligned<n>(reinterpret_cast<uintptr_t>(x));
+ return IsAligned<n>(reinterpret_cast<const uintptr_t>(x));
}
#define CHECK_ALIGNED(value, alignment) \
- CHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<void*>(value)
+ CHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value)
#define DCHECK_ALIGNED(value, alignment) \
- DCHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<void*>(value)
+ DCHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value)
// Check whether an N-bit two's-complement representation can hold value.
static inline bool IsInt(int N, word value) {
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index 69bc85b..666da23 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -120,21 +120,21 @@
return data_offset;
}
-static bool CopyFdToFile(File& file, int in, size_t count) {
+static bool CopyFdToMemory(MemMap& mem_map, int in, size_t count) {
+ uint8_t* dst = mem_map.GetAddress();
std::vector<uint8_t> buf(kBufSize);
while (count != 0) {
size_t bytes_to_read = (count > kBufSize) ? kBufSize : count;
ssize_t actual = TEMP_FAILURE_RETRY(read(in, &buf[0], bytes_to_read));
if (actual != static_cast<ssize_t>(bytes_to_read)) {
- PLOG(WARNING) << "Zip: short read writing to file " << file.name();
+ PLOG(WARNING) << "Zip: short read";
return false;
}
- if (!file.WriteFully(&buf[0], bytes_to_read)) {
- PLOG(WARNING) << "Zip: failed to write to file " << file.name();
- return false;
- }
+ memcpy(dst, &buf[0], bytes_to_read);
+ dst += bytes_to_read;
count -= bytes_to_read;
}
+ DCHECK_EQ(dst, mem_map.GetLimit());
return true;
}
@@ -164,11 +164,12 @@
z_stream zstream_;
};
-static bool InflateToFile(File& out, int in, size_t uncompressed_length, size_t compressed_length) {
+static bool InflateToMemory(MemMap& mem_map, int in, size_t uncompressed_length, size_t compressed_length) {
+ uint8_t* dst = mem_map.GetAddress();
UniquePtr<uint8_t[]> read_buf(new uint8_t[kBufSize]);
UniquePtr<uint8_t[]> write_buf(new uint8_t[kBufSize]);
if (read_buf.get() == NULL || write_buf.get() == NULL) {
- LOG(WARNING) << "Zip: failed to alloctate buffer to inflate to file " << out.name();
+ LOG(WARNING) << "Zip: failed to allocate buffer to inflate";
return false;
}
@@ -218,10 +219,8 @@
if (zstream->Get().avail_out == 0 ||
(zerr == Z_STREAM_END && zstream->Get().avail_out != kBufSize)) {
size_t bytes_to_write = zstream->Get().next_out - write_buf.get();
- if (!out.WriteFully(write_buf.get(), bytes_to_write)) {
- PLOG(WARNING) << "Zip: failed to write to file " << out.name();
- return false;
- }
+ memcpy(dst, write_buf.get(), bytes_to_write);
+ dst += bytes_to_write;
zstream->Get().next_out = write_buf.get();
zstream->Get().avail_out = kBufSize;
}
@@ -236,10 +235,28 @@
return false;
}
+ DCHECK_EQ(dst, mem_map.GetLimit());
return true;
}
-bool ZipEntry::Extract(File& file) {
+bool ZipEntry::ExtractToFile(File& file) {
+ uint32_t length = GetUncompressedLength();
+ int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length));
+ if (result == -1) {
+ PLOG(WARNING) << "Zip: failed to ftruncate " << file.name() << " to length " << length;
+ return false;
+ }
+
+ UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0));
+ if (map.get() == NULL) {
+ LOG(WARNING) << "Zip: failed to mmap space for " << file.name();
+ return false;
+ }
+
+ return ExtractToMemory(*map.get());
+}
+
+bool ZipEntry::ExtractToMemory(MemMap& mem_map) {
off_t data_offset = GetDataOffset();
if (data_offset == -1) {
LOG(WARNING) << "Zip: data_offset=" << data_offset;
@@ -254,9 +271,9 @@
// for uncompressed data).
switch (GetCompressionMethod()) {
case kCompressStored:
- return CopyFdToFile(file, zip_archive_->fd_, GetUncompressedLength());
+ return CopyFdToMemory(mem_map, zip_archive_->fd_, GetUncompressedLength());
case kCompressDeflated:
- return InflateToFile(file, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength());
+ return InflateToMemory(mem_map, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength());
default:
LOG(WARNING) << "Zip: unknown compression method " << std::hex << GetCompressionMethod();
return false;
@@ -395,7 +412,7 @@
}
// It all looks good. Create a mapping for the CD.
- dir_map_.reset(MemMap::Map(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset));
+ dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset));
if (dir_map_.get() == NULL) {
return false;
}
diff --git a/src/zip_archive.h b/src/zip_archive.h
index 013a3da..e367773 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -38,9 +38,10 @@
class ZipEntry {
public:
- // Uncompress an entry, in its entirety, to an open file descriptor.
- bool Extract(File& file);
+ bool ExtractToFile(File& file);
+ bool ExtractToMemory(MemMap& mem_map);
+ uint32_t GetUncompressedLength();
uint32_t GetCrc32();
private:
@@ -58,8 +59,6 @@
uint32_t GetCompressedLength();
- uint32_t GetUncompressedLength();
-
// returns -1 on error
off_t GetDataOffset();
diff --git a/src/zip_archive_test.cc b/src/zip_archive_test.cc
index 051f096..747c219 100644
--- a/src/zip_archive_test.cc
+++ b/src/zip_archive_test.cc
@@ -24,7 +24,7 @@
ASSERT_NE(-1, tmp.GetFd());
UniquePtr<File> file(OS::FileFromFd(tmp.GetFilename(), tmp.GetFd()));
ASSERT_TRUE(file.get() != NULL);
- bool success = zip_entry->Extract(*file);
+ bool success = zip_entry->ExtractToFile(*file);
ASSERT_TRUE(success);
close(tmp.GetFd());