Merge "Make sure VMClassLoader is initialized before eating up the RAM"
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 38f59ef..b62764f 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -16,9 +16,6 @@
 
 #include "class_loader_context.h"
 
-#include <stdlib.h>
-
-#include "android-base/file.h"
 #include "art_field-inl.h"
 #include "base/dchecked_vector.h"
 #include "base/stl_util.h"
@@ -210,19 +207,9 @@
     size_t opened_dex_files_index = info.opened_dex_files.size();
     for (const std::string& cp_elem : info.classpath) {
       // If path is relative, append it to the provided base directory.
-      std::string raw_location = cp_elem;
-      if (raw_location[0] != '/' && !classpath_dir.empty()) {
-        raw_location = classpath_dir + '/' + raw_location;
-      }
-
-      std::string location;  // the real location of the class path element.
-
-      if (!android::base::Realpath(raw_location, &location)) {
-        // If we can't get the realpath of the location there might be something wrong with the
-        // classpath (maybe the file was deleted).
-        // Do not continue in this case and return false.
-        PLOG(WARNING) << "Could not get the realpath of dex location " << raw_location;
-        return false;
+      std::string location = cp_elem;
+      if (location[0] != '/' && !classpath_dir.empty()) {
+        location = classpath_dir + '/' + location;
       }
 
       std::string error_msg;
@@ -728,15 +715,20 @@
         dex_name = info.classpath[k];
         expected_dex_name = OatFile::ResolveRelativeEncodedDexLocation(
             info.classpath[k].c_str(), expected_info.classpath[k]);
-      } else {
+      } else if (is_expected_dex_name_absolute) {
         // The runtime name is relative but the compiled name is absolute.
         // There is no expected use case that would end up here as dex files are always loaded
         // with their absolute location. However, be tolerant and do the best effort (in case
         // there are unexpected new use case...).
-        DCHECK(is_expected_dex_name_absolute);
         dex_name = OatFile::ResolveRelativeEncodedDexLocation(
             expected_info.classpath[k].c_str(), info.classpath[k]);
         expected_dex_name = expected_info.classpath[k];
+      } else {
+        // Both locations are relative. In this case there's not much we can be sure about
+        // except that the names are the same. The checksum will ensure that the files are
+        // are same. This should not happen outside testing and manual invocations.
+        dex_name = info.classpath[k];
+        expected_dex_name = expected_info.classpath[k];
       }
 
       // Compare the locations.
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index be6acde..fc3446c 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -17,17 +17,13 @@
 #include "class_loader_context.h"
 
 #include <gtest/gtest.h>
-#include <stdlib.h>
 
 #include "android-base/strings.h"
-
 #include "base/dchecked_vector.h"
 #include "base/stl_util.h"
-#include "class_loader_context.h"
 #include "class_linker.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
-#include "dex2oat_environment_test.h"
 #include "handle_scope-inl.h"
 #include "mirror/class.h"
 #include "mirror/class_loader.h"
@@ -84,6 +80,10 @@
     kEndsWith
   };
 
+  static bool IsAbsoluteLocation(const std::string& location) {
+    return !location.empty() && location[0] == '/';
+  }
+
   void VerifyOpenDexFiles(
       ClassLoaderContext* context,
       size_t index,
@@ -100,17 +100,22 @@
             info.opened_dex_files[cur_open_dex_index++];
       std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k];
 
-      std::string expected_location =
-          DexFileLoader::GetBaseLocation(expected_dex_file->GetLocation());
-      UniqueCPtr<const char[]> expected_real_location(
-          realpath(expected_location.c_str(), nullptr));
-      ASSERT_TRUE(expected_real_location != nullptr) << expected_location;
-      expected_location.assign(expected_real_location.get());
-      expected_location += DexFileLoader::GetMultiDexSuffix(expected_dex_file->GetLocation());
+      std::string expected_location = expected_dex_file->GetLocation();
 
-      ASSERT_EQ(expected_location, opened_dex_file->GetLocation());
+      const std::string& opened_location = opened_dex_file->GetLocation();
+      if (!IsAbsoluteLocation(opened_location)) {
+        // If the opened location is relative (it was open from a relative path without a
+        // classpath_dir) it might not match the expected location which is absolute in tests).
+        // So we compare the endings (the checksum will validate it's actually the same file).
+        ASSERT_EQ(0, expected_location.compare(
+            expected_location.length() - opened_location.length(),
+            opened_location.length(),
+            opened_location));
+      } else {
+        ASSERT_EQ(expected_location, opened_location);
+      }
       ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum());
-      ASSERT_EQ(info.classpath[k], opened_dex_file->GetLocation());
+      ASSERT_EQ(info.classpath[k], opened_location);
     }
   }
 
@@ -252,6 +257,7 @@
   std::string myclass_dex_name = GetTestDexFileName("MyClass");
   std::string dex_name = GetTestDexFileName("Main");
 
+
   std::unique_ptr<ClassLoaderContext> context =
       ClassLoaderContext::Create(
           "PCL[" + multidex_name + ":" + myclass_dex_name + "];" +
@@ -272,42 +278,6 @@
   VerifyOpenDexFiles(context.get(), 1, &all_dex_files1);
 }
 
-class ScratchSymLink {
- public:
-  explicit ScratchSymLink(const std::string& file) {
-    // Use a temporary scratch file to get a unique name for the link.
-    ScratchFile scratchFile;
-    scratch_link_name_ = scratchFile.GetFilename() + ".link.jar";
-    CHECK_EQ(0, symlink(file.c_str(), scratch_link_name_.c_str()));
-  }
-
-  ~ScratchSymLink() {
-    CHECK_EQ(0, unlink(scratch_link_name_.c_str()));
-  }
-
-  const std::string& GetFilename() { return scratch_link_name_; }
-
- private:
-  std::string scratch_link_name_;
-};
-
-TEST_F(ClassLoaderContextTest, OpenValidDexFilesSymLink) {
-  std::string myclass_dex_name = GetTestDexFileName("MyClass");
-  // Now replace the dex location with a symlink.
-  ScratchSymLink link(myclass_dex_name);
-
-  std::unique_ptr<ClassLoaderContext> context =
-      ClassLoaderContext::Create("PCL[" + link.GetFilename() + "]");
-
-  ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, /*classpath_dir*/ ""));
-
-  VerifyContextSize(context.get(), 1);
-
-  std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass");
-
-  VerifyOpenDexFiles(context.get(), 0, &myclass_dex_files);
-}
-
 static std::string CreateRelativeString(const std::string& in, const char* cwd) {
   int cwd_len = strlen(cwd);
   if (!android::base::StartsWith(in, cwd) || (cwd_len < 1)) {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 378ce2c..b8a13da 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -99,28 +99,7 @@
       << " vdex_fd=" << vdex_fd;;
   }
 
-  // Try to get the realpath for the dex location.
-  //
-  // This is OK with respect to dalvik cache naming scheme because we never
-  // generate oat files starting from symlinks which go into dalvik cache.
-  // (recall that the oat files in dalvik cache are encoded by replacing '/'
-  // with '@' in the path).
-  // The boot image oat files (which are symlinked in dalvik-cache) are not
-  // loaded via the oat file assistant.
-  //
-  // The only case when the dex location may resolve to a different path
-  // is for secondary dex files (e.g. /data/user/0 symlinks to /data/data and
-  // the app is free to create its own internal layout). Related to this it is
-  // worthwhile to mention that installd resolves the secondary dex location
-  // before calling dex2oat.
-  UniqueCPtr<const char[]> dex_location_real(realpath(dex_location, nullptr));
-  if (dex_location_real != nullptr) {
-    dex_location_.assign(dex_location_real.get());
-  } else {
-    // If we can't get the realpath of the location there's not much point in trying to move on.
-    PLOG(ERROR) << "Could not get the realpath of dex_location " << dex_location;
-    return;
-  }
+  dex_location_.assign(dex_location);
 
   if (load_executable_ && isa != kRuntimeISA) {
     LOG(WARNING) << "OatFileAssistant: Load executable specified, "
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 65d01a4..7694f45 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -351,50 +351,6 @@
   EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
 }
 
-// Case: We have a DEX file and up-to-date OAT file for it. We load the dex file
-// via a symlink.
-// Expect: The status is kNoDexOptNeeded.
-TEST_F(OatFileAssistantTest, OatUpToDateSymLink) {
-  if (IsExecutedAsRoot()) {
-    // We cannot simulate non writable locations when executed as root: b/38000545.
-    LOG(ERROR) << "Test skipped because it's running as root";
-    return;
-  }
-
-  std::string real = GetScratchDir() + "/real";
-  ASSERT_EQ(0, mkdir(real.c_str(), 0700));
-  std::string link = GetScratchDir() + "/link";
-  ASSERT_EQ(0, symlink(real.c_str(), link.c_str()));
-
-  std::string dex_location = real + "/OatUpToDate.jar";
-
-  Copy(GetDexSrc1(), dex_location);
-  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
-  // Update the dex location to point to the symlink.
-  dex_location = link + "/OatUpToDate.jar";
-
-  // For the use of oat location by making the dex parent not writable.
-  ScopedNonWritable scoped_non_writable(dex_location);
-  ASSERT_TRUE(scoped_non_writable.IsSuccessful());
-
-  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
-
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
-  EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
-  EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
-      oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
-
-  EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
-  EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
-  EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
-  EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
 // Case: We have a DEX file and up-to-date (ODEX) VDEX file for it, but no
 // ODEX file.
 TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) {