Improve checking of multidex dex checksums.

* Fall back to odex file for all multidex entries if the apk is stripped,
  not just for the main multidex entry.
* Verify the number of multidex entries has not changed.
* Improve performance by getting all checksums from the apk in one go
  and cache the results instead of repeatedly opening the apk.
* Stop referring to non-main multidex entries as "secondary" dex files.

Bug: 34604632
Test: added tests to dex_file_test and oat_file_assistant_test
Test: m test-art-host

Change-Id: I58b17ecfbc9165a5bfeffd5281ee21d108f64479
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 5c49f19..2c2c1b5 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -92,7 +92,7 @@
 ART_GTEST_class_table_test_DEX_DEPS := XandY
 ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
 ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes
-ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested
+ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex
 ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps
 ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
 ART_GTEST_image_test_DEX_DEPS := ImageLayoutA ImageLayoutB
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 02ba33c..48db7e5 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -74,7 +74,6 @@
 
 bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg) {
   CHECK(checksum != nullptr);
-  uint32_t magic;
 
   // Strip ":...", which is the location
   const char* zip_entry_name = kClassesDex;
@@ -88,7 +87,29 @@
     DCHECK_EQ(zip_entry_name[-1], kMultiDexSeparator);
   }
 
-  File fd = OpenAndReadMagic(file_part, &magic, error_msg);
+  std::vector<uint32_t> checksums;
+  if (!GetMultiDexChecksums(file_part, &checksums, error_msg)) {
+    return false;
+  }
+
+  for (size_t i = 0; i < checksums.size(); i++) {
+    if (GetMultiDexClassesDexName(i) == std::string(zip_entry_name)) {
+      *checksum = checksums[i];
+      return true;
+    }
+  }
+
+  *error_msg = StringPrintf("Failed to find entry '%s' in '%s'", zip_entry_name, file_part);
+  return false;
+}
+
+bool DexFile::GetMultiDexChecksums(const char* filename,
+                                   std::vector<uint32_t>* checksums,
+                                   std::string* error_msg) {
+  CHECK(checksums != nullptr);
+  uint32_t magic;
+
+  File fd = OpenAndReadMagic(filename, &magic, error_msg);
   if (fd.Fd() == -1) {
     DCHECK(!error_msg->empty());
     return false;
@@ -97,17 +118,25 @@
     std::unique_ptr<ZipArchive> zip_archive(
         ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
     if (zip_archive.get() == nullptr) {
-      *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", file_part,
+      *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
                                 error_msg->c_str());
       return false;
     }
-    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name, error_msg));
+
+    uint32_t i = 0;
+    std::string zip_entry_name = GetMultiDexClassesDexName(i++);
+    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
     if (zip_entry.get() == nullptr) {
-      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", file_part,
-                                zip_entry_name, error_msg->c_str());
+      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
+          zip_entry_name.c_str(), error_msg->c_str());
       return false;
     }
-    *checksum = zip_entry->GetCrc32();
+
+    do {
+      checksums->push_back(zip_entry->GetCrc32());
+      zip_entry_name = DexFile::GetMultiDexClassesDexName(i++);
+      zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
+    } while (zip_entry.get() != nullptr);
     return true;
   }
   if (IsDexMagic(magic)) {
@@ -116,7 +145,7 @@
     if (dex_file.get() == nullptr) {
       return false;
     }
-    *checksum = dex_file->GetHeader().checksum_;
+    checksums->push_back(dex_file->GetHeader().checksum_);
     return true;
   }
   *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index cf90bca..8ad61aa 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -430,6 +430,15 @@
   // Return true if the checksum could be found, false otherwise.
   static bool GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg);
 
+  // Returns the checksums of a file for comparison with GetLocationChecksum().
+  // For .dex files, this is the single header checksum.
+  // For zip files, this is the zip entry CRC32 checksum for classes.dex and
+  // each additional multidex entry classes2.dex, classes3.dex, etc.
+  // Return true if the checksums could be found, false otherwise.
+  static bool GetMultiDexChecksums(const char* filename,
+                                   std::vector<uint32_t>* checksums,
+                                   std::string* error_msg);
+
   // Opens .dex file, backed by existing memory
   static std::unique_ptr<const DexFile> Open(const uint8_t* base,
                                              size_t size,
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 9dca4c0..b6e010c 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -334,6 +334,29 @@
   EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
 }
 
+TEST_F(DexFileTest, GetMultiDexChecksums) {
+  std::string error_msg;
+  std::vector<uint32_t> checksums;
+  std::string multidex_file = GetTestDexFileName("MultiDex");
+  EXPECT_TRUE(DexFile::GetMultiDexChecksums(multidex_file.c_str(),
+                                            &checksums,
+                                            &error_msg)) << error_msg;
+
+  uint32_t checksum0 = 0;
+  EXPECT_TRUE(DexFile::GetChecksum(DexFile::GetMultiDexLocation(0, multidex_file.c_str()).c_str(),
+                                   &checksum0,
+                                   &error_msg)) << error_msg;
+
+  uint32_t checksum1 = 0;
+  EXPECT_TRUE(DexFile::GetChecksum(DexFile::GetMultiDexLocation(1, multidex_file.c_str()).c_str(),
+                                   &checksum1,
+                                   &error_msg)) << error_msg;
+
+  ASSERT_EQ(2u, checksums.size());
+  EXPECT_EQ(checksums[0], checksum0);
+  EXPECT_EQ(checksums[1], checksum1);
+}
+
 TEST_F(DexFileTest, ClassDefs) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested"));
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 77cdd28..5ae2fc5 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -38,6 +38,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status) {
   switch (status) {
     case OatFileAssistant::kOatCannotOpen:
@@ -264,7 +266,7 @@
     const OatFile& oat_file, const char* dex_location) {
   std::vector<std::unique_ptr<const DexFile>> dex_files;
 
-  // Load the primary dex file.
+  // Load the main dex file.
   std::string error_msg;
   const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(
       dex_location, nullptr, &error_msg);
@@ -280,12 +282,12 @@
   }
   dex_files.push_back(std::move(dex_file));
 
-  // Load secondary multidex files
+  // Load the rest of the multidex entries
   for (size_t i = 1; ; i++) {
-    std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location);
-    oat_dex_file = oat_file.GetOatDexFile(secondary_dex_location.c_str(), nullptr);
+    std::string multidex_dex_location = DexFile::GetMultiDexLocation(i, dex_location);
+    oat_dex_file = oat_file.GetOatDexFile(multidex_dex_location.c_str(), nullptr);
     if (oat_dex_file == nullptr) {
-      // There are no more secondary dex files to load.
+      // There are no more multidex entries to load.
       break;
     }
 
@@ -300,10 +302,10 @@
 }
 
 bool OatFileAssistant::HasOriginalDexFiles() {
-  // Ensure GetRequiredDexChecksum has been run so that
+  // Ensure GetRequiredDexChecksums has been run so that
   // has_original_dex_files_ is initialized. We don't care about the result of
-  // GetRequiredDexChecksum.
-  GetRequiredDexChecksum();
+  // GetRequiredDexChecksums.
+  GetRequiredDexChecksums();
   return has_original_dex_files_;
 }
 
@@ -316,88 +318,66 @@
 }
 
 bool OatFileAssistant::DexChecksumUpToDate(const VdexFile& file, std::string* error_msg) {
-  if (file.GetHeader().GetNumberOfDexFiles() <= 0) {
-    VLOG(oat) << "Vdex does not contain any dex files";
+  const std::vector<uint32_t>* required_dex_checksums = GetRequiredDexChecksums();
+  if (required_dex_checksums == nullptr) {
+    LOG(WARNING) << "Required dex checksums not found. Assuming dex checksums are up to date.";
+    return true;
+  }
+
+  uint32_t number_of_dex_files = file.GetHeader().GetNumberOfDexFiles();
+  if (required_dex_checksums->size() != number_of_dex_files) {
+    *error_msg = StringPrintf("expected %zu dex files but found %u",
+                              required_dex_checksums->size(),
+                              number_of_dex_files);
     return false;
   }
 
-  // TODO: Use GetRequiredDexChecksum to get secondary checksums as well, not
-  // just the primary. Because otherwise we may fail to see a secondary
-  // checksum failure in the case when the original (multidex) files are
-  // stripped but we have a newer odex file.
-  const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum();
-  if (dex_checksum_pointer != nullptr) {
-    uint32_t actual_checksum = file.GetLocationChecksum(0);
-    if (*dex_checksum_pointer != actual_checksum) {
-      VLOG(oat) << "Dex checksum does not match for primary dex: " << dex_location_
-        << ". Expected: " << *dex_checksum_pointer
-        << ", Actual: " << actual_checksum;
+  for (uint32_t i = 0; i < number_of_dex_files; i++) {
+    uint32_t expected_checksum = (*required_dex_checksums)[i];
+    uint32_t actual_checksum = file.GetLocationChecksum(i);
+    if (expected_checksum != actual_checksum) {
+      std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+      *error_msg = StringPrintf("Dex checksum does not match for dex: %s."
+                                "Expected: %u, actual: %u",
+                                dex.c_str(),
+                                expected_checksum,
+                                actual_checksum);
       return false;
     }
   }
 
-  // Verify the dex checksums for any secondary multidex files
-  for (uint32_t i = 1; i < file.GetHeader().GetNumberOfDexFiles(); i++) {
-    std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
-    uint32_t expected_secondary_checksum = 0;
-    if (DexFile::GetChecksum(secondary_dex_location.c_str(),
-                             &expected_secondary_checksum,
-                             error_msg)) {
-      uint32_t actual_secondary_checksum = file.GetLocationChecksum(i);
-      if (expected_secondary_checksum != actual_secondary_checksum) {
-        VLOG(oat) << "Dex checksum does not match for secondary dex: "
-          << secondary_dex_location
-          << ". Expected: " << expected_secondary_checksum
-          << ", Actual: " << actual_secondary_checksum;
-        return false;
-      }
-    } else {
-      // If we can't get the checksum for the secondary location, we assume
-      // the dex checksum is up to date for this and all other secondary dex
-      // files.
-      break;
-    }
-  }
   return true;
 }
 
 bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* error_msg) {
-  // Note: GetOatDexFile will return null if the dex checksum doesn't match
-  // what we provide, which verifies the primary dex checksum for us.
-  const uint32_t* dex_checksum_pointer = GetRequiredDexChecksum();
-  const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(
-      dex_location_.c_str(), dex_checksum_pointer, error_msg);
-  if (oat_dex_file == nullptr) {
+  const std::vector<uint32_t>* required_dex_checksums = GetRequiredDexChecksums();
+  if (required_dex_checksums == nullptr) {
+    LOG(WARNING) << "Required dex checksums not found. Assuming dex checksums are up to date.";
+    return true;
+  }
+
+  uint32_t number_of_dex_files = file.GetOatHeader().GetDexFileCount();
+  if (required_dex_checksums->size() != number_of_dex_files) {
+    *error_msg = StringPrintf("expected %zu dex files but found %u",
+                              required_dex_checksums->size(),
+                              number_of_dex_files);
     return false;
   }
 
-  // Verify the dex checksums for any secondary multidex files
-  for (size_t i = 1; ; i++) {
-    std::string secondary_dex_location = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
-    const OatFile::OatDexFile* secondary_oat_dex_file
-      = file.GetOatDexFile(secondary_dex_location.c_str(), nullptr);
-    if (secondary_oat_dex_file == nullptr) {
-      // There are no more secondary dex files to check.
-      break;
+  for (uint32_t i = 0; i < number_of_dex_files; i++) {
+    std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+    uint32_t expected_checksum = (*required_dex_checksums)[i];
+    const OatFile::OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str(), nullptr);
+    if (oat_dex_file == nullptr) {
+      *error_msg = StringPrintf("failed to find %s in %s", dex.c_str(), file.GetLocation().c_str());
+      return false;
     }
-
-    uint32_t expected_secondary_checksum = 0;
-    if (DexFile::GetChecksum(secondary_dex_location.c_str(),
-          &expected_secondary_checksum, error_msg)) {
-      uint32_t actual_secondary_checksum
-        = secondary_oat_dex_file->GetDexFileLocationChecksum();
-      if (expected_secondary_checksum != actual_secondary_checksum) {
-        VLOG(oat) << "Dex checksum does not match for secondary dex: "
-          << secondary_dex_location
-          << ". Expected: " << expected_secondary_checksum
-          << ", Actual: " << actual_secondary_checksum;
-        return false;
-      }
-    } else {
-      // If we can't get the checksum for the secondary location, we assume
-      // the dex checksum is up to date for this and all other secondary dex
-      // files.
-      break;
+    uint32_t actual_checksum = oat_dex_file->GetDexFileLocationChecksum();
+    if (expected_checksum != actual_checksum) {
+      VLOG(oat) << "Dex checksum does not match for dex: " << dex
+        << ". Expected: " << expected_checksum
+        << ", Actual: " << actual_checksum;
+      return false;
     }
   }
   return true;
@@ -710,13 +690,16 @@
   return image_spaces[0]->GetImageLocation();
 }
 
-const uint32_t* OatFileAssistant::GetRequiredDexChecksum() {
-  if (!required_dex_checksum_attempted_) {
-    required_dex_checksum_attempted_ = true;
-    required_dex_checksum_found_ = false;
+const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums() {
+  if (!required_dex_checksums_attempted_) {
+    required_dex_checksums_attempted_ = true;
+    required_dex_checksums_found_ = false;
+    cached_required_dex_checksums_.clear();
     std::string error_msg;
-    if (DexFile::GetChecksum(dex_location_.c_str(), &cached_required_dex_checksum_, &error_msg)) {
-      required_dex_checksum_found_ = true;
+    if (DexFile::GetMultiDexChecksums(dex_location_.c_str(),
+                                      &cached_required_dex_checksums_,
+                                      &error_msg)) {
+      required_dex_checksums_found_ = true;
       has_original_dex_files_ = true;
     } else {
       // This can happen if the original dex file has been stripped from the
@@ -724,19 +707,23 @@
       VLOG(oat) << "OatFileAssistant: " << error_msg;
       has_original_dex_files_ = false;
 
-      // Get the checksum from the odex if we can.
+      // Get the checksums from the odex if we can.
       const OatFile* odex_file = odex_.GetFile();
       if (odex_file != nullptr) {
-        const OatFile::OatDexFile* odex_dex_file
-            = odex_file->GetOatDexFile(dex_location_.c_str(), nullptr);
-        if (odex_dex_file != nullptr) {
-          cached_required_dex_checksum_ = odex_dex_file->GetDexFileLocationChecksum();
-          required_dex_checksum_found_ = true;
+        required_dex_checksums_found_ = true;
+        for (size_t i = 0; i < odex_file->GetOatHeader().GetDexFileCount(); i++) {
+          std::string dex = DexFile::GetMultiDexLocation(i, dex_location_.c_str());
+          const OatFile::OatDexFile* odex_dex_file = odex_file->GetOatDexFile(dex.c_str(), nullptr);
+          if (odex_dex_file == nullptr) {
+            required_dex_checksums_found_ = false;
+            break;
+          }
+          cached_required_dex_checksums_.push_back(odex_dex_file->GetDexFileLocationChecksum());
         }
       }
     }
   }
-  return required_dex_checksum_found_ ? &cached_required_dex_checksum_ : nullptr;
+  return required_dex_checksums_found_ ? &cached_required_dex_checksums_ : nullptr;
 }
 
 const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() {
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 6d47ad2..3ede29f 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -400,13 +400,13 @@
   // the oat file assistant.
   static std::string ImageLocation();
 
-  // Gets the dex checksum required for an up-to-date oat file.
-  // Returns dex_checksum if a required checksum was located. Returns
-  // null if the required checksum was not found.
-  // The caller shouldn't clean up or free the returned pointer.
-  // This sets the has_original_dex_files_ field to true if a checksum was
-  // found for the dex_location_ dex file.
-  const uint32_t* GetRequiredDexChecksum();
+  // Gets the dex checksums required for an up-to-date oat file.
+  // Returns cached_required_dex_checksums if the required checksums were
+  // located. Returns null if the required checksums were not found.  The
+  // caller shouldn't clean up or free the returned pointer.  This sets the
+  // has_original_dex_files_ field to true if the checksums were found for the
+  // dex_location_ dex file.
+  const std::vector<uint32_t>* GetRequiredDexChecksums();
 
   // Returns the loaded image info.
   // Loads the image info if needed. Returns null if the image info failed
@@ -430,11 +430,11 @@
   // Whether we will attempt to load oat files executable.
   bool load_executable_ = false;
 
-  // Cached value of the required dex checksum.
-  // This should be accessed only by the GetRequiredDexChecksum() method.
-  uint32_t cached_required_dex_checksum_;
-  bool required_dex_checksum_attempted_ = false;
-  bool required_dex_checksum_found_;
+  // Cached value of the required dex checksums.
+  // This should be accessed only by the GetRequiredDexChecksums() method.
+  std::vector<uint32_t> cached_required_dex_checksums_;
+  bool required_dex_checksums_attempted_ = false;
+  bool required_dex_checksums_found_;
   bool has_original_dex_files_;
 
   OatFileInfo odex_;
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index f777340..6cfe3d1 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -237,16 +237,16 @@
   EXPECT_EQ(2u, dex_files.size());
 }
 
-// Case: We have a MultiDEX file where the secondary dex file is out of date.
+// Case: We have a MultiDEX file where the non-main multdex entry is out of date.
 // Expect: The status is kDex2OatNeeded.
-TEST_F(OatFileAssistantTest, MultiDexSecondaryOutOfDate) {
-  std::string dex_location = GetScratchDir() + "/MultiDexSecondaryOutOfDate.jar";
+TEST_F(OatFileAssistantTest, MultiDexNonMainOutOfDate) {
+  std::string dex_location = GetScratchDir() + "/MultiDexNonMainOutOfDate.jar";
 
   // Compile code for GetMultiDexSrc1.
   Copy(GetMultiDexSrc1(), dex_location);
   GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
 
-  // Now overwrite the dex file with GetMultiDexSrc2 so the secondary checksum
+  // Now overwrite the dex file with GetMultiDexSrc2 so the non-main checksum
   // is out of date.
   Copy(GetMultiDexSrc2(), dex_location);
 
@@ -256,6 +256,37 @@
   EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
 }
 
+// Case: We have a stripped MultiDEX file where the non-main multidex entry is
+// out of date with respect to the odex file.
+TEST_F(OatFileAssistantTest, StrippedMultiDexNonMainOutOfDate) {
+  std::string dex_location = GetScratchDir() + "/StrippedMultiDexNonMainOutOfDate.jar";
+  std::string odex_location = GetOdexDir() + "/StrippedMultiDexNonMainOutOfDate.odex";
+
+  // Compile the oat from GetMultiDexSrc1.
+  Copy(GetMultiDexSrc1(), dex_location);
+  GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+
+  // Compile the odex from GetMultiDexSrc2, which has a different non-main
+  // dex checksum.
+  Copy(GetMultiDexSrc2(), dex_location);
+  GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kInterpretOnly);
+
+  // Strip the dex file.
+  Copy(GetStrippedDexSrc1(), dex_location);
+
+  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, /*load_executable*/false);
+
+  // Because the dex file is stripped, the odex file is considered the source
+  // of truth for the dex checksums. The oat file should be considered
+  // unusable.
+  std::unique_ptr<OatFile> best_file = oat_file_assistant.GetBestOatFile();
+  ASSERT_TRUE(best_file.get() != nullptr);
+  EXPECT_EQ(best_file->GetLocation(), odex_location);
+  EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+  EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
+  EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
+}
+
 // Case: We have a MultiDEX file and up-to-date OAT file for it with relative
 // encoded dex locations.
 // Expect: The oat file status is kNoDexOptNeeded.
@@ -336,16 +367,16 @@
       oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
 }
 
-// Case: We have a MultiDEX (ODEX) VDEX file where the secondary dex file is
-// out of date and there is no corresponding ODEX file.
-TEST_F(OatFileAssistantTest, VdexMultiDexSecondaryOutOfDate) {
+// Case: We have a MultiDEX (ODEX) VDEX file where the non-main multidex entry
+// is out of date and there is no corresponding ODEX file.
+TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) {
   // This test case is only meaningful if vdex is enabled.
   if (!kIsVdexEnabled) {
     return;
   }
 
-  std::string dex_location = GetScratchDir() + "/VdexMultiDexSecondaryOutOfDate.jar";
-  std::string oat_location = GetOdexDir() + "/VdexMultiDexSecondaryOutOfDate.oat";
+  std::string dex_location = GetScratchDir() + "/VdexMultiDexNonMainOutOfDate.jar";
+  std::string oat_location = GetOdexDir() + "/VdexMultiDexNonMainOutOfDate.oat";
 
   Copy(GetMultiDexSrc1(), dex_location);
   GenerateOdexForTest(dex_location, oat_location, CompilerFilter::kSpeed);