Keep dex files live for duration of oatdump

Not keeping the dex file live caused a dex cache with a pointer to a
stale dex file resulting in oatdump failing. This is required to
remove the dex file location test that causes the class loader 068
test to fail.

Change-Id: I5d532862ab998482c0d16d7a63c6bdc3752f031a
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 1950d56..c553a18 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -78,6 +78,21 @@
   "kClassRoots",
 };
 
+// Map is so that we don't allocate multiple dex files for the same OatDexFile.
+static std::map<const OatFile::OatDexFile*,
+                std::unique_ptr<const DexFile>> opened_dex_files;
+
+const DexFile* OpenDexFile(const OatFile::OatDexFile* oat_dex_file, std::string* error_msg) {
+  DCHECK(oat_dex_file != nullptr);
+  auto it = opened_dex_files.find(oat_dex_file);
+  if (it != opened_dex_files.end()) {
+    return it->second.get();
+  }
+  const DexFile* ret = oat_dex_file->OpenDexFile(error_msg).release();
+  opened_dex_files.emplace(oat_dex_file, std::unique_ptr<const DexFile>(ret));
+  return ret;
+}
+
 class OatSymbolizer FINAL {
  public:
   class RodataWriter FINAL : public CodeOutput {
@@ -159,8 +174,8 @@
 
   void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file, Callback callback) {
     std::string error_msg;
-    std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
-    if (dex_file.get() == nullptr) {
+    const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
+    if (dex_file == nullptr) {
       return;
     }
     for (size_t class_def_index = 0;
@@ -172,7 +187,7 @@
       switch (type) {
         case kOatClassAllCompiled:
         case kOatClassSomeCompiled:
-          WalkOatClass(oat_class, *dex_file.get(), class_def, callback);
+          WalkOatClass(oat_class, *dex_file, class_def, callback);
           break;
 
         case kOatClassNoneCompiled:
@@ -504,8 +519,8 @@
       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
       CHECK(oat_dex_file != nullptr);
       std::string error_msg;
-      std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
-      if (dex_file.get() == nullptr) {
+      const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
+      if (dex_file == nullptr) {
         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
             << "': " << error_msg;
       } else {
@@ -533,8 +548,8 @@
       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
       CHECK(oat_dex_file != nullptr);
       std::string error_msg;
-      std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
-      if (dex_file.get() == nullptr) {
+      const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
+      if (dex_file == nullptr) {
         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
             << "': " << error_msg;
         continue;
@@ -593,8 +608,8 @@
     // Create the verifier early.
 
     std::string error_msg;
-    std::unique_ptr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg));
-    if (dex_file.get() == nullptr) {
+    const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
+    if (dex_file == nullptr) {
       os << "NOT FOUND: " << error_msg << "\n\n";
       os << std::flush;
       return false;
@@ -621,7 +636,7 @@
          << " (" << oat_class.GetType() << ")\n";
       // TODO: include bitmap here if type is kOatClassSomeCompiled?
       if (options_.list_classes_) continue;
-      if (!DumpOatClass(&vios, oat_class, *(dex_file.get()), class_def, &stop_analysis)) {
+      if (!DumpOatClass(&vios, oat_class, *dex_file, class_def, &stop_analysis)) {
         success = false;
       }
       if (stop_analysis) {
@@ -638,7 +653,7 @@
     std::string error_msg;
     std::string dex_file_location = oat_dex_file.GetDexFileLocation();
 
-    std::unique_ptr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg));
+    const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
     if (dex_file == nullptr) {
       os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
       return false;
@@ -2337,21 +2352,17 @@
   ScopedObjectAccess soa(self);
   ClassLinker* class_linker = runtime->GetClassLinker();
   class_linker->RegisterOatFile(oat_file);
-  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  std::vector<const DexFile*> class_path;
   for (const OatFile::OatDexFile* odf : oat_file->GetOatDexFiles()) {
     std::string error_msg;
-    std::unique_ptr<const DexFile> dex_file = odf->OpenDexFile(&error_msg);
+    const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
     CHECK(dex_file != nullptr) << error_msg;
     class_linker->RegisterDexFile(*dex_file);
-    dex_files.push_back(std::move(dex_file));
+    class_path.push_back(dex_file);
   }
 
   // Need a class loader.
   // Fake that we're a compiler.
-  std::vector<const DexFile*> class_path;
-  for (auto& dex_file : dex_files) {
-    class_path.push_back(dex_file.get());
-  }
   jobject class_loader = class_linker->CreatePathClassLoader(self, class_path);
 
   // Use the class loader while dumping.