Merge art-cache dex files into oat files

Change-Id: I5a327a4e0b678bd9dabb12de4e21ef05e3fefd0b
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() {