Add image dependency to oat files

Change-Id: I945356f71357f1aa0092f4fe6c57eccfb029b4a6
diff --git a/src/class_linker.cc b/src/class_linker.cc
index c1acab0..f15d46f 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -736,6 +736,11 @@
   if (oat_file.get() == NULL) {
     return NULL;
   }
+  Runtime* runtime = Runtime::Current();
+  const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
+  if (oat_file->GetOatHeader().GetImageFileLocationChecksum() != image_header.GetOatChecksum()) {
+    return NULL;
+  }
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
   if (oat_dex_file == NULL) {
     return NULL;
@@ -743,7 +748,7 @@
   if (oat_dex_file->GetDexFileLocationChecksum() != dex_location_checksum) {
     return NULL;
   }
-  Runtime::Current()->GetClassLinker()->RegisterOatFile(*oat_file.release());
+  runtime->GetClassLinker()->RegisterOatFile(*oat_file.release());
   return oat_dex_file->OpenDexFile();
 }
 
@@ -819,15 +824,33 @@
       LOG(WARNING) << "Failed to compute checksum: " << dex_location;
       return NULL;
     }
+
+    Runtime* runtime = Runtime::Current();
+    const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
+    uint32_t image_checksum = image_header.GetOatChecksum();
+    bool image_check = (oat_file->GetOatHeader().GetImageFileLocationChecksum() == image_checksum);
+
     const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location);
     CHECK(oat_dex_file != NULL) << oat_filename << " " << dex_location;
-    if (dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum()) {
+    bool dex_check = (dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum());
+
+    if (image_check && dex_check) {
       return oat_file->GetOatDexFile(dex_location)->OpenDexFile();
     }
-    LOG(WARNING) << ".oat file " << oat_file->GetLocation()
-                 << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
-                 << ") mismatch with " << dex_location
-                 << " (" << std::hex << dex_location_checksum << ")--- regenerating";
+    if (image_check) {
+      std::string image_file(image_header.GetImageRoot(
+          ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8());
+      LOG(WARNING) << ".oat file " << oat_file->GetLocation()
+                   << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
+                   << ") mismatch with " << image_file
+                   << " (" << std::hex << image_checksum << ")--- regenerating";
+    }
+    if (dex_check) {
+      LOG(WARNING) << ".oat file " << oat_file->GetLocation()
+                   << " checksum ( " << std::hex << oat_dex_file->GetDexFileLocationChecksum()
+                   << ") mismatch with " << dex_location
+                   << " (" << std::hex << dex_location_checksum << ")--- regenerating";
+    }
     if (TEMP_FAILURE_RETRY(unlink(oat_file->GetLocation().c_str())) != 0) {
       PLOG(FATAL) << "Couldn't remove obsolete .oat file " << oat_file->GetLocation();
     }
@@ -874,6 +897,8 @@
   ImageSpace* space = heap->GetImageSpace();
   OatFile* oat_file = OpenOat(space);
   CHECK(oat_file != NULL) << "Failed to open oat file for image";
+  CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationChecksum(), 0U);
+  CHECK(oat_file->GetOatHeader().GetImageFileLocation() == "");
   Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
   ObjectArray<DexCache>* dex_caches = dex_caches_object->AsObjectArray<DexCache>();
 
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 2b86b76..2539c92 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -19,9 +19,11 @@
 #include "class_loader.h"
 #include "class_linker.h"
 #include "dex_file.h"
+#include "image.h"
 #include "logging.h"
 #include "os.h"
 #include "runtime.h"
+#include "space.h"
 #include "zip_archive.h"
 #include "toStringArray.h"
 #include "ScopedLocalRef.h"
@@ -179,7 +181,8 @@
 
   // Always treat elements of the bootclasspath as up-to-date.  The
   // fact that code is running at all means that this should be true.
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
   const std::vector<const DexFile*>& boot_class_path = class_linker->GetBootClassPath();
   for (size_t i = 0; i < boot_class_path.size(); i++) {
     if (boot_class_path[i]->GetLocation() == filename.c_str()) {
@@ -211,6 +214,14 @@
     return JNI_TRUE;
   }
 
+  const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
+  if (oat_file->GetOatHeader().GetImageFileLocationChecksum() != image_header.GetOatChecksum()) {
+    LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
+              << " has out-of-date checksum compared to "
+              << image_header.GetImageRoot(ImageHeader::kOatLocation)->AsString()->ToModifiedUtf8();
+    return JNI_TRUE;
+  }
+
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str());
   if (oat_dex_file == NULL) {
     LOG(ERROR) << "DexFile_isDexOptNeeded cache file " << cache_location
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 1f02a44..f75aeb7 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -199,6 +199,7 @@
   }
 
   bool CreateOatFile(const std::string& boot_image_option,
+                     const std::string& host_prefix,
                      const std::vector<const DexFile*>& dex_files,
                      File* oat_file,
 #if defined(ART_USE_LLVM_COMPILER)
@@ -233,7 +234,24 @@
 
     compiler.CompileAll(class_loader->get(), dex_files);
 
-    if (!OatWriter::Create(oat_file, class_loader->get(), dex_files, compiler)) {
+    std::string image_file_location;
+    uint32_t image_file_location_checksum = 0;
+    Heap* heap = Runtime::Current()->GetHeap();
+    if (heap->GetSpaces().size() > 1) {
+      ImageSpace* image_space = heap->GetImageSpace();
+      image_file_location_checksum = image_space->GetImageHeader().GetOatChecksum();
+      image_file_location = image_space->GetImageFilename();
+      if (!host_prefix.empty() && StartsWith(image_file_location, host_prefix.c_str())) {
+        image_file_location = image_file_location.substr(host_prefix.size());
+      }
+    }
+
+    if (!OatWriter::Create(oat_file,
+                           class_loader->get(),
+                           dex_files,
+                           image_file_location_checksum,
+                           image_file_location,
+                           compiler)) {
       LOG(ERROR) << "Failed to create oat file " << oat_file->name();
       return false;
     }
@@ -687,6 +705,7 @@
   }
 
   if (!dex2oat->CreateOatFile(boot_image_option,
+                              host_prefix,
                               dex_files,
                               oat_file.get(),
 #if defined(ART_USE_LLVM_COMPILER)
diff --git a/src/image_test.cc b/src/image_test.cc
index fcea695..cf7c876 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -34,7 +34,7 @@
   ScratchFile tmp_oat;
   std::vector<const DexFile*> dex_files;
   dex_files.push_back(java_lang_dex_file_);
-  bool success_oat = OatWriter::Create(tmp_oat.GetFile(), NULL, dex_files, *compiler_.get());
+  bool success_oat = OatWriter::Create(tmp_oat.GetFile(), NULL, dex_files, 0, "", *compiler_.get());
   ASSERT_TRUE(success_oat);
 
   // Force all system classes into memory
diff --git a/src/oat.cc b/src/oat.cc
index e747a8b..d8d01df 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -27,14 +27,28 @@
   memset(this, 0, sizeof(*this));
 }
 
-OatHeader::OatHeader(InstructionSet instruction_set, const std::vector<const DexFile*>* dex_files) {
+OatHeader::OatHeader(InstructionSet instruction_set,
+                     const std::vector<const DexFile*>* dex_files,
+                     uint32_t image_file_location_checksum,
+                     const std::string& image_file_location) {
   memcpy(magic_, kOatMagic, sizeof(kOatMagic));
   memcpy(version_, kOatVersion, sizeof(kOatVersion));
+
   adler32_checksum_ = adler32(0L, Z_NULL, 0);
+
   instruction_set_ = instruction_set;
   UpdateChecksum(&instruction_set_, sizeof(instruction_set_));
+
   dex_file_count_ = dex_files->size();
   UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
+
+  image_file_location_checksum_ = image_file_location_checksum;
+  UpdateChecksum(&image_file_location_checksum_, sizeof(image_file_location_checksum_));
+
+  image_file_location_size_ = image_file_location.size();
+  UpdateChecksum(&image_file_location_size_, sizeof(image_file_location_size_));
+  UpdateChecksum(image_file_location.data(), image_file_location_size_);
+
   executable_offset_ = 0;
 }
 
@@ -81,11 +95,33 @@
   return executable_offset_;
 }
 
+uint32_t OatHeader::GetImageFileLocationChecksum() const {
+  CHECK(IsValid());
+  return image_file_location_checksum_;
+}
+
+uint32_t OatHeader::GetImageFileLocationSize() const {
+  CHECK(IsValid());
+  return image_file_location_size_;
+}
+
+const uint8_t* OatHeader::GetImageFileLocationData() const {
+  CHECK(IsValid());
+  return image_file_location_data_;
+}
+
+std::string OatHeader::GetImageFileLocation() const {
+  CHECK(IsValid());
+  return std::string(reinterpret_cast<const char*>(GetImageFileLocationData()),
+                     GetImageFileLocationSize());
+}
+
 void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
   DCHECK_ALIGNED(executable_offset, kPageSize);
   CHECK_GT(executable_offset, sizeof(OatHeader));
   DCHECK(IsValid());
   DCHECK_EQ(executable_offset_, 0U);
+
   executable_offset_ = executable_offset;
   UpdateChecksum(&executable_offset_, sizeof(executable_offset));
 }
diff --git a/src/oat.h b/src/oat.h
index 2f3cf9d..25a4373 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -28,7 +28,10 @@
 class PACKED OatHeader {
  public:
   OatHeader();
-  OatHeader(InstructionSet instruction_set, const std::vector<const DexFile*>* dex_files);
+  OatHeader(InstructionSet instruction_set,
+            const std::vector<const DexFile*>* dex_files,
+            uint32_t image_file_location_checksum,
+            const std::string& image_file_location);
 
   bool IsValid() const;
   const char* GetMagic() const;
@@ -38,6 +41,10 @@
   uint32_t GetExecutableOffset() const;
   InstructionSet GetInstructionSet() const;
   void SetExecutableOffset(uint32_t executable_offset);
+  uint32_t GetImageFileLocationChecksum() const;
+  uint32_t GetImageFileLocationSize() const;
+  const uint8_t* GetImageFileLocationData() const;
+  std::string GetImageFileLocation() const;
 
  private:
   static const uint8_t kOatMagic[4];
@@ -51,6 +58,10 @@
   uint32_t dex_file_count_;
   uint32_t executable_offset_;
 
+  uint32_t image_file_location_checksum_;
+  uint32_t image_file_location_size_;
+  uint8_t image_file_location_data_[0];  // note variable width data at end
+
   DISALLOW_COPY_AND_ASSIGN(OatHeader);
 };
 
diff --git a/src/oat_file.cc b/src/oat_file.cc
index f0c004d..e72944e 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -101,7 +101,14 @@
   const byte* oat = map->Begin();
 
   oat += sizeof(OatHeader);
-  CHECK_LE(oat, map->End()) << GetLocation();
+  oat += oat_header.GetImageFileLocationSize();
+
+  CHECK_LE(oat, map->End())
+    << reinterpret_cast<void*>(map->Begin())
+    << "+" << sizeof(OatHeader)
+    << "+" << oat_header.GetImageFileLocationSize()
+    << "<=" << reinterpret_cast<void*>(map->End())
+    << " " << GetLocation();
   for (size_t i = 0; i < oat_header.GetDexFileCount(); i++) {
     size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
     CHECK_GT(dex_file_location_size, 0U) << GetLocation();
diff --git a/src/oat_test.cc b/src/oat_test.cc
index 0ca581a..3cbd3ed 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -34,7 +34,12 @@
   }
 
   ScratchFile tmp;
-  bool success = OatWriter::Create(tmp.GetFile(), class_loader.get(), class_linker->GetBootClassPath(), *compiler_.get());
+  bool success = OatWriter::Create(tmp.GetFile(),
+                                   class_loader.get(),
+                                   class_linker->GetBootClassPath(),
+                                   42U,
+                                   "lue.art",
+                                   *compiler_.get());
   ASSERT_TRUE(success);
 
   if (compile) {  // OatWriter strips the code, regenerate to compare
@@ -44,6 +49,8 @@
   ASSERT_TRUE(oat_file.get() != NULL);
   const OatHeader& oat_header = oat_file->GetOatHeader();
   ASSERT_EQ(1U, oat_header.GetDexFileCount());
+  ASSERT_EQ(42U, oat_header.GetImageFileLocationChecksum());
+  ASSERT_EQ("lue.art", oat_header.GetImageFileLocation());
 
   const DexFile* dex_file = java_lang_dex_file_;
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file->GetLocation());
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index a1b0f9d..8e127deb 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -20,6 +20,7 @@
 #include "class_loader.h"
 #include "file.h"
 #include "os.h"
+#include "space.h"
 #include "stl_util.h"
 
 namespace art {
@@ -27,21 +28,31 @@
 bool OatWriter::Create(File* file,
                        const ClassLoader* class_loader,
                        const std::vector<const DexFile*>& dex_files,
+                       uint32_t image_file_location_checksum,
+                       const std::string& image_file_location,
                        const Compiler& compiler) {
-  OatWriter oat_writer(dex_files, class_loader, compiler);
+  OatWriter oat_writer(dex_files,
+                       image_file_location_checksum,
+                       image_file_location,
+                       class_loader,
+                       compiler);
   return oat_writer.Write(file);
 }
 
 OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
+                     uint32_t image_file_location_checksum,
+                     const std::string& image_file_location,
                      const ClassLoader* class_loader,
                      const Compiler& compiler) {
   compiler_ = &compiler;
   class_loader_ = class_loader;
+  image_file_location_checksum_ = image_file_location_checksum;
+  image_file_location_ = image_file_location;
   dex_files_ = &dex_files;
   oat_header_ = NULL;
   executable_offset_padding_length_ = 0;
 
-  size_t offset = InitOatHeader(compiler.GetInstructionSet());
+  size_t offset = InitOatHeader();
   offset = InitOatDexFiles(offset);
   offset = InitDexFiles(offset);
   offset = InitOatClasses(offset);
@@ -57,10 +68,14 @@
   STLDeleteElements(&oat_classes_);
 }
 
-size_t OatWriter::InitOatHeader(InstructionSet instruction_set) {
+size_t OatWriter::InitOatHeader() {
   // create the OatHeader
-  oat_header_ = new OatHeader(instruction_set, dex_files_);
+  oat_header_ = new OatHeader(compiler_->GetInstructionSet(),
+                              dex_files_,
+                              image_file_location_checksum_,
+                              image_file_location_);
   size_t offset = sizeof(*oat_header_);
+  offset += image_file_location_.size();
   return offset;
 }
 
@@ -361,6 +376,12 @@
     return false;
   }
 
+  if (!file->WriteFully(image_file_location_.data(),
+                        image_file_location_.size())) {
+    PLOG(ERROR) << "Failed to write oat header image file location to " << file->name();
+    return false;
+  }
+
   if (!WriteTables(file)) {
     LOG(ERROR) << "Failed to write oat tables to " << file->name();
     return false;
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 210a659..c3a8ff6 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -28,11 +28,10 @@
 #include "oat.h"
 #include "object.h"
 #include "os.h"
-#include "space.h"
 
 namespace art {
 
-// OatHeader         fixed length with count of D OatDexFiles
+// OatHeader         variable length with count of D OatDexFiles
 //
 // OatDexFile[0]     one variable sized OatDexFile with offsets to Dex and OatClasses
 // OatDexFile[1]
@@ -63,17 +62,23 @@
 class OatWriter {
  public:
   // Write an oat file. Returns true on success, false on failure.
-  static bool Create(File* file, const ClassLoader* class_loader,
-                     const std::vector<const DexFile*>& dex_files, const Compiler& compiler);
+  static bool Create(File* file,
+                     const ClassLoader* class_loader,
+                     const std::vector<const DexFile*>& dex_files,
+                     uint32_t image_file_location_checksum,
+                     const std::string& image_file_location,
+                     const Compiler& compiler);
 
  private:
 
   OatWriter(const std::vector<const DexFile*>& dex_files,
+            uint32_t image_file_location_checksum,
+            const std::string& image_file_location,
             const ClassLoader* class_loader,
             const Compiler& compiler);
   ~OatWriter();
 
-  size_t InitOatHeader(InstructionSet instruction_set);
+  size_t InitOatHeader();
   size_t InitOatDexFiles(size_t offset);
   size_t InitDexFiles(size_t offset);
   size_t InitOatClasses(size_t offset);
@@ -146,6 +151,10 @@
   // note OatFile does not take ownership of the DexFiles
   const std::vector<const DexFile*>* dex_files_;
 
+  // dependency on the image
+  uint32_t image_file_location_checksum_;
+  std::string image_file_location_;
+
   // data to write
   OatHeader* oat_header_;
   std::vector<OatDexFile*> oat_dex_files_;
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 295c74f..ae0ad57 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -85,7 +85,9 @@
 
 class OatDumper {
  public:
-  explicit OatDumper(const OatFile& oat_file) : oat_file_(oat_file),
+  explicit OatDumper(const std::string& host_prefix, const OatFile& oat_file)
+    : host_prefix_(host_prefix),
+      oat_file_(oat_file),
       oat_dex_files_(oat_file.GetOatDexFiles()),
       disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet())) {
     AddAllOffsets();
@@ -109,6 +111,17 @@
     os << "EXECUTABLE OFFSET:\n";
     os << StringPrintf("0x%08x\n\n", oat_header.GetExecutableOffset());
 
+    os << "IMAGE FILE LOCATION CHECKSUM:\n";
+    os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationChecksum());
+
+    os << "IMAGE FILE LOCATION:\n";
+    const std::string image_file_location(oat_header.GetImageFileLocation());
+    os << image_file_location;
+    if (!image_file_location.empty() && !host_prefix_.empty()) {
+      os << " (" << host_prefix_ << image_file_location << ")";
+    }
+    os << "\n\n";
+
     os << "BEGIN:\n";
     os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
 
@@ -470,6 +483,7 @@
     }
   }
 
+  const std::string host_prefix_;
   const OatFile& oat_file_;
   std::vector<const OatFile::OatDexFile*> oat_dex_files_;
   std::set<uint32_t> offsets_;
@@ -548,7 +562,7 @@
 
     stats_.oat_file_bytes = oat_file->Size();
 
-    oat_dumper_.reset(new OatDumper(*oat_file));
+    oat_dumper_.reset(new OatDumper(host_prefix_, *oat_file));
 
     os_ << "OBJECTS:\n" << std::flush;
     HeapBitmap* heap_bitmap = Runtime::Current()->GetHeap()->GetLiveBits();
@@ -1110,13 +1124,20 @@
     return EXIT_FAILURE;
   }
 
+  if (host_prefix.empty()) {
+    const char* android_product_out = getenv("ANDROID_PRODUCT_OUT");
+    if (android_product_out != NULL) {
+        host_prefix = android_product_out;
+    }
+  }
+
   if (oat_filename != NULL) {
     OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, NULL);
     if (oat_file == NULL) {
       fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
       return EXIT_FAILURE;
     }
-    OatDumper oat_dumper(*oat_file);
+    OatDumper oat_dumper(host_prefix, *oat_file);
     oat_dumper.Dump(*os);
     return EXIT_SUCCESS;
   }
@@ -1137,12 +1158,6 @@
     options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
   }
 
-  if (host_prefix.empty()) {
-    const char* android_product_out = getenv("ANDROID_PRODUCT_OUT");
-    if (android_product_out != NULL) {
-        host_prefix = android_product_out;
-    }
-  }
   if (!host_prefix.empty()) {
     options.push_back(std::make_pair("host-prefix", host_prefix.c_str()));
   }