ART: Store classpath information into oat file

Store a "dependency list" of class-path dex-files into the key-value
store of an oat file. The list is made up of dex locations and
corresponding checksums.

Add tests for encoding, decoding and checking the list.

Bug: 19781184
Change-Id: Ie700dd37e6e086db599c95d329ac1f1d2ff0b758
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index f2213e9..a88553c 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -20,9 +20,15 @@
 
 #include <gtest/gtest.h>
 
+#include "common_runtime_test.h"
+#include "scoped_thread_state_change.h"
+
 namespace art {
 
-TEST(OatFileTest, ResolveRelativeEncodedDexLocation) {
+class OatFileTest : public CommonRuntimeTest {
+};
+
+TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation) {
   EXPECT_EQ(std::string("/data/app/foo/base.apk"),
       OatFile::ResolveRelativeEncodedDexLocation(
         nullptr, "/data/app/foo/base.apk"));
@@ -56,4 +62,54 @@
         "/data/app/foo/base.apk", "o/base.apk"));
 }
 
+static std::vector<const DexFile*> ToConstDexFiles(
+    const std::vector<std::unique_ptr<const DexFile>>& in) {
+  std::vector<const DexFile*> ret;
+  for (auto& d : in) {
+    ret.push_back(d.get());
+  }
+  return ret;
+}
+
+TEST_F(OatFileTest, DexFileDependencies) {
+  std::string error_msg;
+
+  // No dependencies.
+  EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies(nullptr, &error_msg)) << error_msg;
+  EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies("", &error_msg)) << error_msg;
+
+  // Ill-formed dependencies.
+  EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc", &error_msg));
+  EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc*123*def", &error_msg));
+  EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc*def*", &error_msg));
+
+  // Unsatisfiable dependency.
+  EXPECT_FALSE(OatFile::CheckStaticDexFileDependencies("abc*123*", &error_msg));
+
+  // Load some dex files to be able to do a real test.
+  ScopedObjectAccess soa(Thread::Current());
+
+  std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Main");
+  std::vector<const DexFile*> dex_files_const1 = ToConstDexFiles(dex_files1);
+  std::string encoding1 = OatFile::EncodeDexFileDependencies(dex_files_const1);
+  EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies(encoding1.c_str(), &error_msg))
+      << error_msg << " " << encoding1;
+  std::vector<std::string> split1;
+  EXPECT_TRUE(OatFile::GetDexLocationsFromDependencies(encoding1.c_str(), &split1));
+  ASSERT_EQ(split1.size(), 1U);
+  EXPECT_EQ(split1[0], dex_files_const1[0]->GetLocation());
+
+  std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex");
+  EXPECT_GT(dex_files2.size(), 1U);
+  std::vector<const DexFile*> dex_files_const2 = ToConstDexFiles(dex_files2);
+  std::string encoding2 = OatFile::EncodeDexFileDependencies(dex_files_const2);
+  EXPECT_TRUE(OatFile::CheckStaticDexFileDependencies(encoding2.c_str(), &error_msg))
+      << error_msg << " " << encoding2;
+  std::vector<std::string> split2;
+  EXPECT_TRUE(OatFile::GetDexLocationsFromDependencies(encoding2.c_str(), &split2));
+  ASSERT_EQ(split2.size(), 2U);
+  EXPECT_EQ(split2[0], dex_files_const2[0]->GetLocation());
+  EXPECT_EQ(split2[1], dex_files_const2[1]->GetLocation());
+}
+
 }  // namespace art