Merge changes I16fde69b,I6c085137 into pi-dev

* changes:
  Add arg for overwriting class loader class path
  Add stored class loader context option
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 1e4ed58..fe927bb 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -428,6 +428,10 @@
   UsageError("  --class-loader-context=<string spec>: a string specifying the intended");
   UsageError("      runtime loading context for the compiled dex files.");
   UsageError("");
+  UsageError("  --stored-class-loader-context=<string spec>: a string specifying the intended");
+  UsageError("      runtime loading context that is stored in the oat file. Overrides");
+  UsageError("      --class-loader-context. Note that this ignores the classpath_dir arg.");
+  UsageError("");
   UsageError("      It describes how the class loader chain should be built in order to ensure");
   UsageError("      classes are resolved during dex2aot as they would be resolved at runtime.");
   UsageError("      This spec will be encoded in the oat file. If at runtime the dex file is");
@@ -1260,11 +1264,31 @@
       ParseInstructionSetFeatures(*args.Get(M::TargetInstructionSetFeatures), parser_options.get());
     }
     if (args.Exists(M::ClassLoaderContext)) {
-      class_loader_context_ = ClassLoaderContext::Create(*args.Get(M::ClassLoaderContext));
+      std::string class_loader_context_arg = *args.Get(M::ClassLoaderContext);
+      class_loader_context_ = ClassLoaderContext::Create(class_loader_context_arg);
       if (class_loader_context_ == nullptr) {
         Usage("Option --class-loader-context has an incorrect format: %s",
-              args.Get(M::ClassLoaderContext)->c_str());
+              class_loader_context_arg.c_str());
       }
+      if (args.Exists(M::StoredClassLoaderContext)) {
+        const std::string stored_context_arg = *args.Get(M::StoredClassLoaderContext);
+        stored_class_loader_context_ = ClassLoaderContext::Create(stored_context_arg);
+        if (stored_class_loader_context_ == nullptr) {
+          Usage("Option --stored-class-loader-context has an incorrect format: %s",
+                stored_context_arg.c_str());
+        } else if (!class_loader_context_->VerifyClassLoaderContextMatch(
+            stored_context_arg,
+            /*verify_names*/ false,
+            /*verify_checksums*/ false)) {
+          Usage(
+              "Option --stored-class-loader-context '%s' mismatches --class-loader-context '%s'",
+              stored_context_arg.c_str(),
+              class_loader_context_arg.c_str());
+        }
+      }
+    } else if (args.Exists(M::StoredClassLoaderContext)) {
+      Usage("Option --stored-class-loader-context should only be used if "
+            "--class-loader-context is also specified");
     }
 
     if (!ReadCompilerOptions(args, compiler_options_.get(), &error_msg)) {
@@ -1579,7 +1603,7 @@
 
       if (class_loader_context_ == nullptr) {
         // If no context was specified use the default one (which is an empty PathClassLoader).
-        class_loader_context_ = std::unique_ptr<ClassLoaderContext>(ClassLoaderContext::Default());
+        class_loader_context_ = ClassLoaderContext::Default();
       }
 
       DCHECK_EQ(oat_writers_.size(), 1u);
@@ -1605,8 +1629,12 @@
       }
 
       // Store the class loader context in the oat header.
-      key_value_store_->Put(OatHeader::kClassPathKey,
-                            class_loader_context_->EncodeContextForOatFile(classpath_dir_));
+      // TODO: deprecate this since store_class_loader_context should be enough to cover the users
+      // of classpath_dir as well.
+      std::string class_path_key =
+          class_loader_context_->EncodeContextForOatFile(classpath_dir_,
+                                                         stored_class_loader_context_.get());
+      key_value_store_->Put(OatHeader::kClassPathKey, class_path_key);
     }
 
     // Now that we have finalized key_value_store_, start writing the oat file.
@@ -2845,6 +2873,9 @@
   // The spec describing how the class loader should be setup for compilation.
   std::unique_ptr<ClassLoaderContext> class_loader_context_;
 
+  // The class loader context stored in the oat file. May be equal to class_loader_context_.
+  std::unique_ptr<ClassLoaderContext> stored_class_loader_context_;
+
   size_t thread_count_;
   uint64_t start_ns_;
   uint64_t start_cputime_ns_;
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 0d68f4f..5843691 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -245,6 +245,9 @@
       .Define("--class-loader-context=_")
           .WithType<std::string>()
           .IntoKey(M::ClassLoaderContext)
+      .Define("--stored-class-loader-context=_")
+          .WithType<std::string>()
+          .IntoKey(M::StoredClassLoaderContext)
       .Define("--compact-dex-level=_")
           .WithType<CompactDexLevel>()
           .WithValueMap({{"none", CompactDexLevel::kCompactDexLevelNone},
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 01f9d94..1a913a9 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -88,6 +88,7 @@
 DEX2OAT_OPTIONS_KEY (Unit,                           ForceDeterminism)
 DEX2OAT_OPTIONS_KEY (std::string,                    ClasspathDir)
 DEX2OAT_OPTIONS_KEY (std::string,                    ClassLoaderContext)
+DEX2OAT_OPTIONS_KEY (std::string,                    StoredClassLoaderContext)
 DEX2OAT_OPTIONS_KEY (std::string,                    DirtyImageObjects)
 DEX2OAT_OPTIONS_KEY (std::vector<std::string>,       RuntimeOptions)
 DEX2OAT_OPTIONS_KEY (std::string,                    CompilationReason)
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index c890f8b..bc8468e 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -2125,4 +2125,49 @@
   EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u);
 }
 
+TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) {
+  std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("MultiDex");
+  const std::string out_dir = GetScratchDir();
+  const std::string odex_location = out_dir + "/base.odex";
+  const std::string valid_context = "PCL[" + dex_files[0]->GetLocation() + "]";
+  const std::string stored_context = "PCL[/system/not_real_lib.jar]";
+  std::string expected_stored_context = "PCL[";
+  size_t index = 1;
+  for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+    const bool is_first = index == 1u;
+    if (!is_first) {
+      expected_stored_context += ":";
+    }
+    expected_stored_context += "/system/not_real_lib.jar";
+    if (!is_first) {
+      expected_stored_context += "!classes" + std::to_string(index) + ".dex";
+    }
+    expected_stored_context += "*" + std::to_string(dex_file->GetLocationChecksum());
+    ++index;
+  }
+  expected_stored_context +=    + "]";
+  // The class path should not be valid and should fail being stored.
+  GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+                      odex_location,
+                      CompilerFilter::Filter::kQuicken,
+                      { "--class-loader-context=" + stored_context },
+                      true,  // expect_success
+                      false,  // use_fd
+                      [&](const OatFile& oat_file) {
+    EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_;
+    EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_;
+  });
+  // The stored context should match what we expect even though it's invalid.
+  GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+                      odex_location,
+                      CompilerFilter::Filter::kQuicken,
+                      { "--class-loader-context=" + valid_context,
+                        "--stored-class-loader-context=" + stored_context },
+                      true,  // expect_success
+                      false,  // use_fd
+                      [&](const OatFile& oat_file) {
+    EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_;
+  });
+}
+
 }  // namespace art
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index e646520..4afc44c 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -254,6 +254,7 @@
     // This will allow the context to VerifyClassLoaderContextMatch which expects or multidex
     // location in the class paths.
     // Note that this will also remove the paths that could not be opened.
+    info.original_classpath = std::move(info.classpath);
     info.classpath.clear();
     info.checksums.clear();
     for (size_t k = opened_dex_files_index; k < info.opened_dex_files.size(); k++) {
@@ -294,20 +295,26 @@
 }
 
 std::string ClassLoaderContext::EncodeContextForDex2oat(const std::string& base_dir) const {
-  return EncodeContext(base_dir, /*for_dex2oat*/ true);
+  return EncodeContext(base_dir, /*for_dex2oat*/ true, /*stored_context*/ nullptr);
 }
 
-std::string ClassLoaderContext::EncodeContextForOatFile(const std::string& base_dir) const {
-  return EncodeContext(base_dir, /*for_dex2oat*/ false);
+std::string ClassLoaderContext::EncodeContextForOatFile(const std::string& base_dir,
+                                                        ClassLoaderContext* stored_context) const {
+  return EncodeContext(base_dir, /*for_dex2oat*/ false, stored_context);
 }
 
 std::string ClassLoaderContext::EncodeContext(const std::string& base_dir,
-                                              bool for_dex2oat) const {
+                                              bool for_dex2oat,
+                                              ClassLoaderContext* stored_context) const {
   CheckDexFilesOpened("EncodeContextForOatFile");
   if (special_shared_library_) {
     return OatFile::kSpecialSharedLibrary;
   }
 
+  if (stored_context != nullptr) {
+    DCHECK_EQ(class_loader_chain_.size(), stored_context->class_loader_chain_.size());
+  }
+
   std::ostringstream out;
   if (class_loader_chain_.empty()) {
     // We can get in this situation if the context was created with a class path containing the
@@ -326,6 +333,15 @@
     out << GetClassLoaderTypeName(info.type);
     out << kClassLoaderOpeningMark;
     std::set<std::string> seen_locations;
+    SafeMap<std::string, std::string> remap;
+    if (stored_context != nullptr) {
+      DCHECK_EQ(info.original_classpath.size(),
+                stored_context->class_loader_chain_[i].classpath.size());
+      for (size_t k = 0; k < info.original_classpath.size(); ++k) {
+        // Note that we don't care if the same name appears twice.
+        remap.Put(info.original_classpath[k], stored_context->class_loader_chain_[i].classpath[k]);
+      }
+    }
     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];
       if (for_dex2oat) {
@@ -337,7 +353,14 @@
           continue;
         }
       }
-      const std::string& location = dex_file->GetLocation();
+      std::string location = dex_file->GetLocation();
+      // If there is a stored class loader remap, fix up the multidex strings.
+      if (!remap.empty()) {
+        std::string base_dex_location = DexFileLoader::GetBaseLocation(location);
+        auto it = remap.find(base_dex_location);
+        CHECK(it != remap.end()) << base_dex_location;
+        location = it->second + DexFileLoader::GetMultiDexSuffix(location);
+      }
       if (k > 0) {
         out << kClasspathSeparator;
       }
@@ -345,7 +368,7 @@
       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 << location.c_str();
       }
       // dex2oat does not need the checksums.
       if (!for_dex2oat) {
@@ -649,12 +672,16 @@
   return !location.empty() && location[0] == '/';
 }
 
-bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec) const {
-  DCHECK(dex_files_open_attempted_);
-  DCHECK(dex_files_open_result_);
+bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec,
+                                                       bool verify_names,
+                                                       bool verify_checksums) const {
+  if (verify_names || verify_checksums) {
+    DCHECK(dex_files_open_attempted_);
+    DCHECK(dex_files_open_result_);
+  }
 
   ClassLoaderContext expected_context;
-  if (!expected_context.Parse(context_spec, /*parse_checksums*/ true)) {
+  if (!expected_context.Parse(context_spec, verify_checksums)) {
     LOG(WARNING) << "Invalid class loader context: " << context_spec;
     return false;
   }
@@ -693,8 +720,14 @@
       return false;
     }
 
-    DCHECK_EQ(info.classpath.size(), info.checksums.size());
-    DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size());
+    if (verify_checksums) {
+      DCHECK_EQ(info.classpath.size(), info.checksums.size());
+      DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size());
+    }
+
+    if (!verify_names) {
+      continue;
+    }
 
     for (size_t k = 0; k < info.classpath.size(); k++) {
       // Compute the dex location that must be compared.
@@ -766,4 +799,3 @@
 }
 
 }  // namespace art
-
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 692a6cd..1c83007 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -84,9 +84,12 @@
   // (so that it can be read and verified at runtime against the actual class
   // loader hierarchy).
   // Should only be called if OpenDexFiles() returned true.
+  // If stored context is non-null, the stored names are overwritten by the class path from the
+  // stored context.
   // E.g. if the context is PCL[a.dex:b.dex] this will return
   // "PCL[a.dex*a_checksum*b.dex*a_checksum]".
-  std::string EncodeContextForOatFile(const std::string& base_dir) const;
+  std::string EncodeContextForOatFile(const std::string& base_dir,
+                                      ClassLoaderContext* stored_context = nullptr) const;
 
   // Encodes the context as a string suitable to be passed to dex2oat.
   // This is the same as EncodeContextForOatFile but without adding the checksums
@@ -104,7 +107,11 @@
   //    - the class loader from the same position have the same classpath
   //      (the order and checksum of the dex files matches)
   // This should be called after OpenDexFiles().
-  bool VerifyClassLoaderContextMatch(const std::string& context_spec) const;
+  // Names are only verified if verify_names is true.
+  // Checksums are only verified if verify_checksums is true.
+  bool VerifyClassLoaderContextMatch(const std::string& context_spec,
+                                     bool verify_names = true,
+                                     bool verify_checksums = true) const;
 
   // Creates the class loader context from the given string.
   // The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]...
@@ -146,6 +153,8 @@
     // The list of class path elements that this loader loads.
     // Note that this list may contain relative paths.
     std::vector<std::string> classpath;
+    // Original opened class path (ignoring multidex).
+    std::vector<std::string> original_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;
@@ -198,7 +207,9 @@
   // location). Otherwise, for oat files, the encoding adds all the dex files (including multidex)
   // together with their checksums.
   // Should only be called if OpenDexFiles() returned true.
-  std::string EncodeContext(const std::string& base_dir, bool for_dex2oat) const;
+  std::string EncodeContext(const std::string& base_dir,
+                            bool for_dex2oat,
+                            ClassLoaderContext* stored_context) const;
 
   // Extracts the class loader type from the given spec.
   // Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not