Merge "Relax HasSeenMethod check"
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 1505eb5..b08b055 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -937,7 +937,7 @@
     return GetOdexDir() + "/Context.odex";
   }
 
-  const char* kEmptyClassPathKey = "";
+  const char* kEmptyClassPathKey = "PCL[]";
 };
 
 TEST_F(Dex2oatClassLoaderContextTest, InvalidContext) {
@@ -961,10 +961,10 @@
 
 TEST_F(Dex2oatClassLoaderContextTest, ContextWithOtherDexFiles) {
   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Nested");
-  std::string expected_classpath_key =
-      OatFile::EncodeDexFileDependencies(MakeNonOwningPointerVector(dex_files), "");
 
   std::string context = "PCL[" + dex_files[0]->GetLocation() + "]";
+  std::string expected_classpath_key = "PCL[" +
+      dex_files[0]->GetLocation() + "*" + std::to_string(dex_files[0]->GetLocationChecksum()) + "]";
   RunTest(context.c_str(), expected_classpath_key.c_str(), true);
 }
 
@@ -974,7 +974,7 @@
 
   std::string context = "PCL[" + stripped_classpath + "]";
   // Expect an empty context because stripped dex files cannot be open.
-  RunTest(context.c_str(), /*expected_classpath_key*/ "" , /*expected_success*/ true);
+  RunTest(context.c_str(), kEmptyClassPathKey , /*expected_success*/ true);
 }
 
 TEST_F(Dex2oatClassLoaderContextTest, ContextWithStrippedDexFilesBackedByOdex) {
@@ -993,19 +993,26 @@
   Copy(GetStrippedDexSrc1(), stripped_classpath);
 
   std::string context = "PCL[" + stripped_classpath + "]";
-  std::string expected_classpath;
+  std::string expected_classpath_key;
   {
     // Open the oat file to get the expected classpath.
     OatFileAssistant oat_file_assistant(stripped_classpath.c_str(), kRuntimeISA, false);
     std::unique_ptr<OatFile> oat_file(oat_file_assistant.GetBestOatFile());
     std::vector<std::unique_ptr<const DexFile>> oat_dex_files =
         OatFileAssistant::LoadDexFiles(*oat_file, stripped_classpath.c_str());
-    expected_classpath = OatFile::EncodeDexFileDependencies(
-        MakeNonOwningPointerVector(oat_dex_files), "");
+    expected_classpath_key = "PCL[";
+    for (size_t i = 0; i < oat_dex_files.size(); i++) {
+      if (i > 0) {
+        expected_classpath_key + ":";
+      }
+      expected_classpath_key += oat_dex_files[i]->GetLocation() + "*" +
+          std::to_string(oat_dex_files[i]->GetLocationChecksum());
+    }
+    expected_classpath_key += "]";
   }
 
   RunTest(context.c_str(),
-          expected_classpath.c_str(),
+          expected_classpath_key.c_str(),
           /*expected_success*/ true,
           /*use_second_source*/ true);
 }
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 5cbcd8f..2bed1d5 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -31,8 +31,9 @@
 static constexpr char kDelegateLastClassLoaderString[] = "DLC";
 static constexpr char kClassLoaderOpeningMark = '[';
 static constexpr char kClassLoaderClosingMark = ']';
-static constexpr char kClassLoaderSep = ';';
-static constexpr char kClasspathSep = ':';
+static constexpr char kClassLoaderSeparator = ';';
+static constexpr char kClasspathSeparator = ':';
+static constexpr char kDexFileChecksumSeparator = '*';
 
 ClassLoaderContext::ClassLoaderContext()
     : special_shared_library_(false),
@@ -48,9 +49,11 @@
   }
 }
 
-// The expected format is: "ClassLoaderType1[ClasspathElem1:ClasspathElem2...]".
+// The expected format is: "ClassLoaderType1[ClasspathElem1*Checksum1:ClasspathElem2*Checksum2...]".
+// The checksum part of the format is expected only if parse_cheksums is true.
 bool ClassLoaderContext::ParseClassLoaderSpec(const std::string& class_loader_spec,
-                                              ClassLoaderType class_loader_type) {
+                                              ClassLoaderType class_loader_type,
+                                              bool parse_checksums) {
   const char* class_loader_type_str = GetClassLoaderTypeName(class_loader_type);
   size_t type_str_size = strlen(class_loader_type_str);
 
@@ -70,7 +73,26 @@
                                                    class_loader_spec.length() - type_str_size - 2);
 
   class_loader_chain_.push_back(ClassLoaderInfo(class_loader_type));
-  Split(classpath, kClasspathSep, &class_loader_chain_.back().classpath);
+
+  if (!parse_checksums) {
+    Split(classpath, kClasspathSeparator, &class_loader_chain_.back().classpath);
+  } else {
+    std::vector<std::string> classpath_elements;
+    Split(classpath, kClasspathSeparator, &classpath_elements);
+    for (const std::string& element : classpath_elements) {
+      std::vector<std::string> dex_file_with_checksum;
+      Split(element, kDexFileChecksumSeparator, &dex_file_with_checksum);
+      if (dex_file_with_checksum.size() != 2) {
+        return false;
+      }
+      uint32_t checksum = 0;
+      if (!ParseInt(dex_file_with_checksum[1].c_str(), &checksum)) {
+        return false;
+      }
+      class_loader_chain_.back().classpath.push_back(dex_file_with_checksum[0]);
+      class_loader_chain_.back().checksums.push_back(checksum);
+    }
+  }
 
   return true;
 }
@@ -93,11 +115,11 @@
 // The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]...
 // ClassLoaderType is either "PCL" (PathClassLoader) or "DLC" (DelegateLastClassLoader).
 // ClasspathElem is the path of dex/jar/apk file.
-bool ClassLoaderContext::Parse(const std::string& spec) {
+bool ClassLoaderContext::Parse(const std::string& spec, bool parse_checksums) {
   if (spec.empty()) {
-    LOG(ERROR) << "Empty string passed to Parse";
-    return false;
+    return true;
   }
+
   // Stop early if we detect the special shared library, which may be passed as the classpath
   // for dex2oat when we want to skip the shared libraries check.
   if (spec == OatFile::kSpecialSharedLibrary) {
@@ -107,7 +129,7 @@
   }
 
   std::vector<std::string> class_loaders;
-  Split(spec, kClassLoaderSep, &class_loaders);
+  Split(spec, kClassLoaderSeparator, &class_loaders);
 
   for (const std::string& class_loader : class_loaders) {
     ClassLoaderType type = ExtractClassLoaderType(class_loader);
@@ -115,7 +137,7 @@
       LOG(ERROR) << "Invalid class loader type: " << class_loader;
       return false;
     }
-    if (!ParseClassLoaderSpec(class_loader, type)) {
+    if (!ParseClassLoaderSpec(class_loader, type, parse_checksums)) {
       LOG(ERROR) << "Invalid class loader spec: " << class_loader;
       return false;
     }
@@ -219,12 +241,33 @@
     return "";
   }
 
-  // TODO(calin): Transition period: assume we only have a classloader until
-  // the oat file assistant implements the full class loader check.
-  CHECK_EQ(1u, class_loader_chain_.size());
+  std::ostringstream out;
 
-  return OatFile::EncodeDexFileDependencies(MakeNonOwningPointerVector(
-      class_loader_chain_[0].opened_dex_files), base_dir);
+  for (size_t i = 0; i < class_loader_chain_.size(); i++) {
+    const ClassLoaderInfo& info = class_loader_chain_[i];
+    if (i > 0) {
+      out << kClassLoaderSeparator;
+    }
+    out << GetClassLoaderTypeName(info.type);
+    out << kClassLoaderOpeningMark;
+    for (size_t k = 0; k < info.opened_dex_files.size(); k++) {
+      const std::unique_ptr<const DexFile>& dex_file = info.opened_dex_files[k];
+      const std::string& location = dex_file->GetLocation();
+      if (k > 0) {
+        out << kClasspathSeparator;
+      }
+      // Find paths that were relative and convert them back from absolute.
+      if (!base_dir.empty() && location.substr(0, base_dir.length()) == base_dir) {
+        out << location.substr(base_dir.length() + 1).c_str();
+      } else {
+        out << dex_file->GetLocation().c_str();
+      }
+      out << kDexFileChecksumSeparator;
+      out << dex_file->GetLocationChecksum();
+    }
+    out << kClassLoaderClosingMark;
+  }
+  return out.str();
 }
 
 jobject ClassLoaderContext::CreateClassLoader(
@@ -281,5 +324,37 @@
       << "Dex files were not successfully opened before the call to " << calling_method
       << "attempt=" << dex_files_open_attempted_ << ", result=" << dex_files_open_result_;
 }
+
+bool ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
+    const std::string& context_spec,
+    std::vector<std::string>* out_classpath,
+    std::vector<uint32_t>* out_checksums,
+    bool* out_is_special_shared_library) {
+  ClassLoaderContext context;
+  if (!context.Parse(context_spec, /*parse_checksums*/ true)) {
+    LOG(ERROR) << "Invalid class loader context: " << context_spec;
+    return false;
+  }
+
+  *out_is_special_shared_library = context.special_shared_library_;
+  if (context.special_shared_library_) {
+    return true;
+  }
+
+  if (context.class_loader_chain_.empty()) {
+    return true;
+  }
+
+  // TODO(calin): assert that we only have a PathClassLoader until the logic for
+  // checking the context covers all case.
+  CHECK_EQ(1u, context.class_loader_chain_.size());
+  const ClassLoaderInfo& info = context.class_loader_chain_[0];
+  CHECK_EQ(kPathClassLoader, info.type);
+  DCHECK_EQ(info.classpath.size(), info.checksums.size());
+
+  *out_classpath = info.classpath;
+  *out_checksums = info.checksums;
+  return true;
+}
 }  // namespace art
 
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 4af5017..9727a3b 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -59,6 +59,8 @@
   // The compilation sources are appended to the classpath of the top class loader
   // (i.e the class loader whose parent is the BootClassLoader).
   // Should only be called if OpenDexFiles() returned true.
+  // If the context is empty, this method only creates a single PathClassLoader with the
+  // given compilation_sources.
   jobject CreateClassLoader(const std::vector<const DexFile*>& compilation_sources) const;
 
   // Encodes the context as a string suitable to be added in oat files.
@@ -80,6 +82,17 @@
   // class loader for the source dex files.
   static std::unique_ptr<ClassLoaderContext> Create(const std::string& spec);
 
+  // Decodes the class loader context stored in the oat file with EncodeContextForOatFile.
+  // Returns true if the format matches, or false otherwise. If the return is true, the out
+  // arguments will contain the classpath dex files, their checksums and whether or not the
+  // context is a special shared library.
+  // The method asserts that the context is made out of only one PathClassLoader.
+  static bool DecodePathClassLoaderContextFromOatFileKey(
+      const std::string& context_spec,
+      std::vector<std::string>* out_classpath,
+      std::vector<uint32_t>* out_checksums,
+      bool* out_is_special_shared_library);
+
  private:
   enum ClassLoaderType {
     kInvalidClassLoader = 0,
@@ -93,6 +106,9 @@
     // The list of class path elements that this loader loads.
     // Note that this list may contain relative paths.
     std::vector<std::string> classpath;
+    // The list of class path elements checksums.
+    // May be empty if the checksums are not given when the context is created.
+    std::vector<uint32_t> checksums;
     // After OpenDexFiles is called this holds the opened dex files.
     std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
     // After OpenDexFiles, in case some of the dex files were opened from their oat files
@@ -104,13 +120,14 @@
 
   // Reads the class loader spec in place and returns true if the spec is valid and the
   // compilation context was constructed.
-  bool Parse(const std::string& spec);
+  bool Parse(const std::string& spec, bool parse_checksums = false);
 
   // Attempts to parse a single class loader spec for the given class_loader_type.
   // If successful the class loader spec will be added to the chain.
   // Returns whether or not the operation was successful.
   bool ParseClassLoaderSpec(const std::string& class_loader_spec,
-                            ClassLoaderType class_loader_type);
+                            ClassLoaderType class_loader_type,
+                            bool parse_checksums = false);
 
   // Extracts the class loader type from the given spec.
   // Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 4643e78..03eb0e4 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -230,6 +230,42 @@
   }
 }
 
+TEST_F(ClassLoaderContextTest, CreateClassLoaderWithEmptyContext) {
+  std::unique_ptr<ClassLoaderContext> context =
+      ClassLoaderContext::Create("");
+  ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, ""));
+
+  std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex");
+
+  std::vector<const DexFile*> compilation_sources_raw =
+      MakeNonOwningPointerVector(compilation_sources);
+  jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw);
+  ASSERT_TRUE(jclass_loader != nullptr);
+
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<2> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
+      soa.Decode<mirror::ClassLoader>(jclass_loader));
+
+  ASSERT_TRUE(class_loader->GetClass() ==
+      soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader));
+  ASSERT_TRUE(class_loader->GetParent()->GetClass() ==
+      soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader));
+
+
+  std::vector<const DexFile*> class_loader_dex_files = GetDexFiles(jclass_loader);
+
+  // The compilation sources should be the only files present in the class loader
+  ASSERT_EQ(compilation_sources.size(), class_loader_dex_files.size());
+  for (size_t i = 0; i < compilation_sources.size(); i++) {
+    ASSERT_EQ(compilation_sources[i]->GetLocation(),
+        class_loader_dex_files[i]->GetLocation());
+    ASSERT_EQ(compilation_sources[i]->GetLocationChecksum(),
+        class_loader_dex_files[i]->GetLocationChecksum());
+  }
+}
+
 TEST_F(ClassLoaderContextTest, RemoveSourceLocations) {
   std::unique_ptr<ClassLoaderContext> context =
       ClassLoaderContext::Create("PCL[a.dex]");
@@ -256,10 +292,46 @@
   std::vector<std::unique_ptr<const DexFile>> dex1 = OpenTestDexFiles("Main");
   std::vector<std::unique_ptr<const DexFile>> dex2 = OpenTestDexFiles("MyClass");
   std::string encoding = context->EncodeContextForOatFile("");
-  std::string expected_encoding =
-      dex1[0]->GetLocation() + "*" + std::to_string(dex1[0]->GetLocationChecksum()) + "*" +
-      dex2[0]->GetLocation() + "*" + std::to_string(dex2[0]->GetLocationChecksum()) + "*";
+  std::string expected_encoding = "PCL[" +
+      dex1[0]->GetLocation() + "*" + std::to_string(dex1[0]->GetLocationChecksum()) + ":" +
+      dex2[0]->GetLocation() + "*" + std::to_string(dex2[0]->GetLocationChecksum()) + "]";
   ASSERT_EQ(expected_encoding, context->EncodeContextForOatFile(""));
 }
 
+TEST_F(ClassLoaderContextTest, DecodeOatFileKey) {
+  std::string oat_file_encoding = "PCL[a.dex*123:b.dex*456]";
+  std::vector<std::string> classpath;
+  std::vector<uint32_t> checksums;
+  bool is_special_shared_library;
+  bool result = ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
+      oat_file_encoding,
+      &classpath,
+      &checksums,
+      &is_special_shared_library);
+  ASSERT_TRUE(result);
+  ASSERT_FALSE(is_special_shared_library);
+  ASSERT_EQ(2u, classpath.size());
+  ASSERT_EQ(2u, checksums.size());
+  ASSERT_EQ("a.dex", classpath[0]);
+  ASSERT_EQ(123u, checksums[0]);
+  ASSERT_EQ("b.dex", classpath[1]);
+  ASSERT_EQ(456u, checksums[1]);
+}
+
+TEST_F(ClassLoaderContextTest, DecodeOatFileKeySpecialLibrary) {
+  std::string oat_file_encoding = "&";
+  std::vector<std::string> classpath;
+  std::vector<uint32_t> checksums;
+  bool is_special_shared_library;
+  bool result = ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
+      oat_file_encoding,
+      &classpath,
+      &checksums,
+      &is_special_shared_library);
+  ASSERT_TRUE(result);
+  ASSERT_TRUE(is_special_shared_library);
+  ASSERT_TRUE(classpath.empty());
+  ASSERT_TRUE(checksums.empty());
+}
+
 }  // namespace art
diff --git a/runtime/oat.h b/runtime/oat.h
index 521cc40..5e61907 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,8 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '1', '2', '7', '\0' };  // .bss ArtMethod* section.
+  // Last oat version changed reason: update classpath key format.
+  static constexpr uint8_t kOatVersion[] = { '1', '2', '8', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 2ed30df..1c1189d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1574,28 +1574,6 @@
   return GetOatHeader().GetCompilerFilter();
 }
 
-static constexpr char kDexClassPathEncodingSeparator = '*';
-
-std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files,
-                                               const std::string& base_dir) {
-  std::ostringstream out;
-
-  for (const DexFile* dex_file : dex_files) {
-    const std::string& location = dex_file->GetLocation();
-    // Find paths that were relative and convert them back from absolute.
-    if (!base_dir.empty() && location.substr(0, base_dir.length()) == base_dir) {
-      out << location.substr(base_dir.length() + 1).c_str();
-    } else {
-      out << dex_file->GetLocation().c_str();
-    }
-    out << kDexClassPathEncodingSeparator;
-    out << dex_file->GetLocationChecksum();
-    out << kDexClassPathEncodingSeparator;
-  }
-
-  return out.str();
-}
-
 OatFile::OatClass OatFile::FindOatClass(const DexFile& dex_file,
                                         uint16_t class_def_idx,
                                         bool* found) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 6393e09..b112b84 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -296,11 +296,6 @@
   static std::string ResolveRelativeEncodedDexLocation(
       const char* abs_dex_location, const std::string& rel_dex_location);
 
-  // Create a dependency list (dex locations and checksums) for the given dex files.
-  // Removes dex file paths prefixed with base_dir to convert them back to relative paths.
-  static std::string EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files,
-                                               const std::string& base_dir);
-
   // Finds the associated oat class for a dex_file and descriptor. Returns an invalid OatClass on
   // error and sets found to false.
   static OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found);
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 630945a..b166961 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -28,6 +28,7 @@
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "class_linker.h"
+#include "class_loader_context.h"
 #include "dex_file-inl.h"
 #include "dex_file_tracking_registrar.h"
 #include "gc/scoped_gc_critical_section.h"
@@ -421,38 +422,47 @@
   }
 }
 
-static bool AreSharedLibrariesOk(const std::string& shared_libraries,
-                                 std::vector<const DexFile*>& dex_files) {
-  // If no shared libraries, we expect no dex files.
-  if (shared_libraries.empty()) {
-    return dex_files.empty();
-  }
-  // If we find the special shared library, skip the shared libraries check.
-  if (shared_libraries.compare(OatFile::kSpecialSharedLibrary) == 0) {
-    return true;
-  }
-  // Shared libraries is a series of dex file paths and their checksums, each separated by '*'.
-  std::vector<std::string> shared_libraries_split;
-  Split(shared_libraries, '*', &shared_libraries_split);
-
-  // Sanity check size of dex files and split shared libraries. Should be 2x as many entries in
-  // the split shared libraries since it contains pairs of filename/checksum.
-  if (dex_files.size() * 2 != shared_libraries_split.size()) {
+static bool AreSharedLibrariesOk(const std::string& context_spec,
+                                 std::vector<const DexFile*>& dex_files,
+                                 std::string* error_msg) {
+  std::vector<std::string> classpath;
+  std::vector<uint32_t> checksums;
+  bool is_special_shared_library;
+  if (!ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
+          context_spec, &classpath, &checksums, &is_special_shared_library)) {
+    *error_msg = "Could not decode the class loader context from the oat file key.";
     return false;
   }
 
+  DCHECK_EQ(classpath.size(), checksums.size());
+
+  // The classpath size should match the number of dex files.
+  if (classpath.size() != dex_files.size()) {
+    *error_msg = "The number of loaded dex files does not match the number of files "
+        "specified in the context. Expected=" + std::to_string(classpath.size()) +
+        ", found=" + std::to_string(dex_files.size());
+    return false;
+  }
+
+  // If we find the special shared library, skip the shared libraries check.
+  if (is_special_shared_library) {
+    return true;
+  }
+
   // Check that the loaded dex files have the same order and checksums as the shared libraries.
   for (size_t i = 0; i < dex_files.size(); ++i) {
+    const std::string& dex_location = dex_files[i]->GetLocation();
+    uint32_t dex_location_checksum = dex_files[i]->GetLocationChecksum();
     std::string absolute_library_path =
-        OatFile::ResolveRelativeEncodedDexLocation(dex_files[i]->GetLocation().c_str(),
-                                                   shared_libraries_split[i * 2]);
-    if (dex_files[i]->GetLocation() != absolute_library_path) {
+        OatFile::ResolveRelativeEncodedDexLocation(dex_location.c_str(), classpath[i]);
+    if (dex_location != absolute_library_path) {
+      *error_msg = "SharedLibraryCheck: expected=" + absolute_library_path + ", found=" +
+          dex_location;
       return false;
     }
-    char* end;
-    size_t shared_lib_checksum = strtoul(shared_libraries_split[i * 2 + 1].c_str(), &end, 10);
-    uint32_t dex_checksum = dex_files[i]->GetLocationChecksum();
-    if (*end != '\0' || dex_checksum != shared_lib_checksum) {
+    if (dex_location_checksum  != checksums[i]) {
+      *error_msg = "SharedLibraryCheck: checksum mismatch for " + dex_location + ". Expected=" +
+          std::to_string(checksums[i]) + ", found=" + std::to_string(dex_location_checksum);
       return false;
     }
   }
@@ -586,7 +596,7 @@
   // Exit if shared libraries are ok. Do a full duplicate classes check otherwise.
   const std::string
       shared_libraries(oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
-  if (AreSharedLibrariesOk(shared_libraries, dex_files_loaded)) {
+  if (AreSharedLibrariesOk(shared_libraries, dex_files_loaded, error_msg)) {
     return false;
   }