Use /system/framework/framework.jar:preloaded-classes for on device dex2oat

Change-Id: I30ccbd5295a2979b9c89f00c93ad316d9b6475e9
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 7cf54b4..6397f40 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -18,8 +18,9 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 
-#include <iostream>
 #include <fstream>
+#include <iostream>
+#include <sstream>
 #include <string>
 #include <vector>
 
@@ -164,27 +165,54 @@
 
 
   // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
-  CompilerDriver::DescriptorSet* ReadImageClasses(const char* image_classes_filename) {
+  CompilerDriver::DescriptorSet* ReadImageClassesFromFile(const char* image_classes_filename) {
     UniquePtr<std::ifstream> image_classes_file(new std::ifstream(image_classes_filename, std::ifstream::in));
     if (image_classes_file.get() == NULL) {
       LOG(ERROR) << "Failed to open image classes file " << image_classes_filename;
       return NULL;
     }
+    UniquePtr<CompilerDriver::DescriptorSet> result(ReadImageClasses(*image_classes_file.get()));
+    image_classes_file->close();
+    return result.release();
+  }
 
+  CompilerDriver::DescriptorSet* ReadImageClasses(std::istream& image_classes_stream) {
     UniquePtr<CompilerDriver::DescriptorSet> image_classes(new CompilerDriver::DescriptorSet);
-    while (image_classes_file->good()) {
+    while (image_classes_stream.good()) {
       std::string dot;
-      std::getline(*image_classes_file.get(), dot);
+      std::getline(image_classes_stream, dot);
       if (StartsWith(dot, "#") || dot.empty()) {
         continue;
       }
       std::string descriptor(DotToDescriptor(dot.c_str()));
       image_classes->insert(descriptor);
     }
-    image_classes_file->close();
     return image_classes.release();
   }
 
+  // Reads the class names (java.lang.Object) and returns as set of class descriptors (Ljava/lang/Object;)
+  CompilerDriver::DescriptorSet* ReadImageClassesFromZip(const std::string& zip_filename, const char* image_classes_filename) {
+    UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_filename));
+    if (zip_archive.get() == NULL) {
+      LOG(ERROR) << "Failed to open zip file " << zip_filename;
+      return NULL;
+    }
+    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename));
+    if (zip_entry.get() == NULL) {
+      LOG(ERROR) << "Failed to find " << image_classes_filename << " within " << zip_filename;
+      return NULL;
+    }
+    UniquePtr<MemMap> image_classes_file(zip_entry->ExtractToMemMap(image_classes_filename));
+    if (image_classes_file.get() == NULL) {
+      LOG(ERROR) << "Failed to extract " << image_classes_filename << " from " << zip_filename;
+      return NULL;
+    }
+    const std::string image_classes_string(reinterpret_cast<char*>(image_classes_file->Begin()),
+                                           image_classes_file->Size());
+    std::istringstream image_classes_stream(image_classes_string);
+    return ReadImageClasses(image_classes_stream);
+  }
+
   const CompilerDriver* CreateOatFile(const std::string& boot_image_option,
                                       const std::string* host_prefix,
                                       const std::string& android_root,
@@ -558,6 +586,7 @@
   std::string oat_location;
   int oat_fd = -1;
   std::string bitcode_filename;
+  const char* image_classes_zip_filename = NULL;
   const char* image_classes_filename = NULL;
   std::string image_filename;
   std::string boot_image_filename;
@@ -632,6 +661,8 @@
       image_filename = option.substr(strlen("--image=")).data();
     } else if (option.starts_with("--image-classes=")) {
       image_classes_filename = option.substr(strlen("--image-classes=")).data();
+    } else if (option.starts_with("--image-classes-zip=")) {
+      image_classes_zip_filename = option.substr(strlen("--image-classes-zip=")).data();
     } else if (option.starts_with("--base=")) {
       const char* image_base_str = option.substr(strlen("--base=")).data();
       char* end;
@@ -735,6 +766,10 @@
     Usage("--image-classes should not be used with --boot-image");
   }
 
+  if (image_classes_zip_filename != NULL && image_classes_filename == NULL) {
+    Usage("--image-classes-zip should be used with --image-classes");
+  }
+
   if (dex_filenames.empty() && zip_fd == -1) {
     Usage("Input must be supplied with either --dex-file or --zip-fd");
   }
@@ -846,7 +881,12 @@
   // If --image-classes was specified, calculate the full list of classes to include in the image
   UniquePtr<CompilerDriver::DescriptorSet> image_classes(NULL);
   if (image_classes_filename != NULL) {
-    image_classes.reset(dex2oat->ReadImageClasses(image_classes_filename));
+    if (image_classes_zip_filename != NULL) {
+      image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
+                                                           image_classes_filename));
+    } else {
+      image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
+    }
     if (image_classes.get() == NULL) {
       LOG(ERROR) << "Failed to create list of image classes from " << image_classes_filename;
       return EXIT_FAILURE;
@@ -860,7 +900,7 @@
     if (dex_filenames.empty()) {
       UniquePtr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd));
       if (zip_archive.get() == NULL) {
-        LOG(ERROR) << "Failed to zip from file descriptor for " << zip_location;
+        LOG(ERROR) << "Failed to open zip from file descriptor for " << zip_location;
         return EXIT_FAILURE;
       }
       const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location);
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 80465f2..1e37dcd 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -206,26 +206,15 @@
   CHECK(!location.empty());
   UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex));
   if (zip_entry.get() == NULL) {
-    LOG(ERROR) << "Failed to find classes.dex within " << location;
+    LOG(ERROR) << "Failed to find classes.dex within '" << location << "'";
     return NULL;
   }
 
-  uint32_t length = zip_entry->GetUncompressedLength();
-  std::string name("classes.dex extracted in memory from ");
-  name += location;
-  UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(), NULL, length, PROT_READ | PROT_WRITE));
+  UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex));
   if (map.get() == NULL) {
-    LOG(ERROR) << "mmap classes.dex for \"" << location << "\" failed";
+    LOG(ERROR) << "Failed to extract '" << kClassesDex << "' from '" << location << "'";
     return NULL;
   }
-
-  // Extract classes.dex
-  bool success = zip_entry->ExtractToMemory(*map.get());
-  if (!success) {
-    LOG(ERROR) << "Failed to extract classes.dex from '" << location << "' to memory";
-    return NULL;
-  }
-
   const DexFile* dex_file = OpenMemory(location, zip_entry->GetCrc32(), map.release());
   if (dex_file == NULL) {
     LOG(ERROR) << "Failed to open dex file '" << location << "' from memory";
diff --git a/src/gc/heap.cc b/src/gc/heap.cc
index 9ec1f21..7bd8687 100644
--- a/src/gc/heap.cc
+++ b/src/gc/heap.cc
@@ -109,7 +109,10 @@
   std::string base_option_string(StringPrintf("--base=0x%x", ART_BASE_ADDRESS));
   arg_vector.push_back(strdup(base_option_string.c_str()));
 
-  if (!kIsTargetBuild) {
+  if (kIsTargetBuild) {
+    arg_vector.push_back(strdup("--image-classes-zip=/system/framework/framework.jar"));
+    arg_vector.push_back(strdup("--image-classes=preloaded-classes"));
+  } else {
     arg_vector.push_back(strdup("--host"));
   }
 
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index c9e9c0a..9cf7a09 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -121,8 +121,8 @@
   return data_offset;
 }
 
-static bool CopyFdToMemory(MemMap& mem_map, int in, size_t count) {
-  uint8_t* dst = mem_map.Begin();
+static bool CopyFdToMemory(uint8_t* begin, size_t size, int in, size_t count) {
+  uint8_t* dst = begin;
   std::vector<uint8_t> buf(kBufSize);
   while (count != 0) {
     size_t bytes_to_read = (count > kBufSize) ? kBufSize : count;
@@ -135,7 +135,7 @@
     dst += bytes_to_read;
     count -= bytes_to_read;
   }
-  DCHECK_EQ(dst, mem_map.End());
+  DCHECK_EQ(dst, begin + size);
   return true;
 }
 
@@ -165,8 +165,9 @@
   z_stream zstream_;
 };
 
-static bool InflateToMemory(MemMap& mem_map, int in, size_t uncompressed_length, size_t compressed_length) {
-  uint8_t* dst = mem_map.Begin();
+static bool InflateToMemory(uint8_t* begin, size_t size,
+                            int in, size_t uncompressed_length, size_t compressed_length) {
+  uint8_t* dst = begin;
   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) {
@@ -236,7 +237,7 @@
     return false;
   }
 
-  DCHECK_EQ(dst, mem_map.End());
+  DCHECK_EQ(dst, begin + size);
   return true;
 }
 
@@ -254,10 +255,10 @@
     return false;
   }
 
-  return ExtractToMemory(*map.get());
+  return ExtractToMemory(map->Begin(), map->Size());
 }
 
-bool ZipEntry::ExtractToMemory(MemMap& mem_map) {
+bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size) {
   off_t data_offset = GetDataOffset();
   if (data_offset == -1) {
     LOG(WARNING) << "Zip: data_offset=" << data_offset;
@@ -272,15 +273,38 @@
   // for uncompressed data).
   switch (GetCompressionMethod()) {
     case kCompressStored:
-      return CopyFdToMemory(mem_map, zip_archive_->fd_, GetUncompressedLength());
+      return CopyFdToMemory(begin, size, zip_archive_->fd_, GetUncompressedLength());
     case kCompressDeflated:
-      return InflateToMemory(mem_map, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength());
+      return InflateToMemory(begin, size, zip_archive_->fd_,
+                             GetUncompressedLength(), GetCompressedLength());
     default:
       LOG(WARNING) << "Zip: unknown compression method " << std::hex << GetCompressionMethod();
       return false;
   }
 }
 
+MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename) {
+  std::string name(entry_filename);
+  name += " extracted in memory from ";
+  name += entry_filename;
+  UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(),
+                                             NULL,
+                                             GetUncompressedLength(),
+                                             PROT_READ | PROT_WRITE));
+  if (map.get() == NULL) {
+    LOG(ERROR) << "Zip: mmap for '" << entry_filename << "' failed";
+    return NULL;
+  }
+
+  bool success = ExtractToMemory(map->Begin(), map->Size());
+  if (!success) {
+    LOG(ERROR) << "Zip: Failed to extract '" << entry_filename << "' to memory";
+    return NULL;
+  }
+
+  return map.release();
+}
+
 static void SetCloseOnExec(int fd) {
   // This dance is more portable than Linux's O_CLOEXEC open(2) flag.
   int flags = fcntl(fd, F_GETFD);
diff --git a/src/zip_archive.h b/src/zip_archive.h
index 54835cf..ef31486 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -37,7 +37,8 @@
 class ZipEntry {
  public:
   bool ExtractToFile(File& file);
-  bool ExtractToMemory(MemMap& mem_map);
+  bool ExtractToMemory(uint8_t* begin, size_t size);
+  MemMap* ExtractToMemMap(const char* entry_filename);
 
   uint32_t GetUncompressedLength();
   uint32_t GetCrc32();