Test and fix bug checking status of secondary multidex files.

We were accidentally returning 'false' instead of 'true' to indicate a native
multidex file with an up-to-date primary dex file checksum but out-of-date
secondary dex file checksum is out of date.

Bug: 21022815
Change-Id: I43d360ca9251d0df38ad7f8289f6ef339c0a3280
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 730e61d..5d4f1d3 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -30,6 +30,7 @@
   Interfaces \
   Main \
   MultiDex \
+  MultiDexModifiedSecondary \
   MyClass \
   MyClassNatives \
   Nested \
@@ -68,7 +69,7 @@
 ART_GTEST_instrumentation_test_DEX_DEPS := Instrumentation
 ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives
 ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods
-ART_GTEST_oat_file_assistant_test_DEX_DEPS := Main MainStripped MultiDex Nested
+ART_GTEST_oat_file_assistant_test_DEX_DEPS := Main MainStripped MultiDex MultiDexModifiedSecondary Nested
 ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex
 ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
 ART_GTEST_proxy_test_DEX_DEPS := Interfaces
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index d07c09c..84d9505 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -417,7 +417,7 @@
           << secondary_dex_location
           << ". Expected: " << expected_secondary_checksum
           << ", Actual: " << actual_secondary_checksum;
-        return false;
+        return true;
       }
     } else {
       // If we can't get the checksum for the secondary location, we assume
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 865fcb0..d8e3797 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -67,10 +67,23 @@
       << "Expected stripped dex file to be at: " << GetStrippedDexSrc1();
     ASSERT_FALSE(DexFile::GetChecksum(GetStrippedDexSrc1().c_str(), &checksum, &error_msg))
       << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1();
-    ASSERT_TRUE(OS::FileExists(GetMultiDexSrc1().c_str()))
-      << "Expected multidex file to be at: " << GetMultiDexSrc1();
     ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str()))
       << "Expected dex file to be at: " << GetDexSrc2();
+
+    // GetMultiDexSrc2 should have the same primary dex checksum as
+    // GetMultiDexSrc1, but a different secondary dex checksum.
+    std::vector<std::unique_ptr<const DexFile>> multi1;
+    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc1().c_str(),
+          GetMultiDexSrc1().c_str(), &error_msg, &multi1)) << error_msg;
+    ASSERT_GT(multi1.size(), 1u);
+
+    std::vector<std::unique_ptr<const DexFile>> multi2;
+    ASSERT_TRUE(DexFile::Open(GetMultiDexSrc2().c_str(),
+          GetMultiDexSrc2().c_str(), &error_msg, &multi2)) << error_msg;
+    ASSERT_GT(multi2.size(), 1u);
+
+    ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum());
+    ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum());
   }
 
   virtual void SetUpRuntimeOptions(RuntimeOptions* options) {
@@ -149,6 +162,12 @@
     return GetTestDexFileName("MultiDex");
   }
 
+  // Returns the path to a multidex file equivalent to GetMultiDexSrc2, but
+  // with the contents of the secondary dex file changed.
+  std::string GetMultiDexSrc2() {
+    return GetTestDexFileName("MultiDexModifiedSecondary");
+  }
+
   std::string GetDexSrc2() {
     return GetTestDexFileName("Nested");
   }
@@ -344,6 +363,23 @@
   EXPECT_EQ(2u, dex_files.size());
 }
 
+// Case: We have a MultiDEX file where the secondary dex file is out of date.
+// Expect: The status is kDex2OatNeeded.
+TEST_F(OatFileAssistantTest, MultiDexSecondaryOutOfDate) {
+  std::string dex_location = GetScratchDir() + "/MultiDexSecondaryOutOfDate.jar";
+
+  // Compile code for GetMultiDexSrc1.
+  Copy(GetMultiDexSrc1(), dex_location);
+  GenerateOatForTest(dex_location.c_str());
+
+  // Now overwrite the dex file with GetMultiDexSrc2 so the secondary checksum
+  // is out of date.
+  Copy(GetMultiDexSrc2(), dex_location);
+
+  OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+  EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+}
+
 // 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.
@@ -1001,9 +1037,6 @@
 // TODO: More Tests:
 //  * Test class linker falls back to unquickened dex for DexNoOat
 //  * Test class linker falls back to unquickened dex for MultiDexNoOat
-//  * Test multidex files:
-//     - Multidex with only classes2.dex out of date should have status
-//       kOutOfDate
 //  * Test using secondary isa
 //  * Test with profiling info?
 //  * Test for status of oat while oat is being generated (how?)
diff --git a/test/MultiDexModifiedSecondary/Main.java b/test/MultiDexModifiedSecondary/Main.java
new file mode 100644
index 0000000..659dba9
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/Main.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Main {
+    public static void main(String args[]) {
+      Second second = new Second();
+      System.out.println(second.getSecond());
+    }
+}
diff --git a/test/MultiDexModifiedSecondary/README.txt b/test/MultiDexModifiedSecondary/README.txt
new file mode 100644
index 0000000..4cf3a56
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/README.txt
@@ -0,0 +1,4 @@
+MultiDexModifiedSecondary is designed to result in a multidex file that has
+the same classes.dex file as MultiDex, but a different classes2.dex.
+
+This is used in the OatFileAssistantTest.MultiDexSecondaryOutOfDate gtest.
diff --git a/test/MultiDexModifiedSecondary/Second.java b/test/MultiDexModifiedSecondary/Second.java
new file mode 100644
index 0000000..3555a7f
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/Second.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class Second {
+  public String getThird() {
+    return "I Third That.";
+  }
+
+  public String getSecond() {
+    return "I Second That.";
+  }
+}
diff --git a/test/MultiDexModifiedSecondary/main.jpp b/test/MultiDexModifiedSecondary/main.jpp
new file mode 100644
index 0000000..a5d7a6c
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/main.jpp
@@ -0,0 +1,3 @@
+main:
+  @@com.android.jack.annotations.ForceInMainDex
+  class Main
diff --git a/test/MultiDexModifiedSecondary/main.list b/test/MultiDexModifiedSecondary/main.list
new file mode 100644
index 0000000..44ba78e
--- /dev/null
+++ b/test/MultiDexModifiedSecondary/main.list
@@ -0,0 +1 @@
+Main.class