Fix image checksum verification.

Move over the separator ':' for checking subsequent dex file
checksums. The bug, introduced in
    https://android-review.googlesource.com/1091189 ,
caused rejection of oat files if the boot class path had
more than one module that was not part of the boot image.

Test: Add a new test to image_space_test.
Test: Manual fake OTA with extra logging for checksum mismatch.
Bug: 119800099
Bug: 144146443
Change-Id: I9eb8328348b30ee4769468924f9e6ac65b70d4cb
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 9ff799c..57584ed 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -3378,6 +3378,7 @@
                                   std::string(oat_checksums).c_str());
         return false;
       }
+      oat_checksums.remove_prefix(1u);
     }
   }
   if (!oat_checksums.empty()) {
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index 34df447..f3398e9 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -17,8 +17,10 @@
 #include <gtest/gtest.h>
 
 #include "android-base/stringprintf.h"
+#include "android-base/strings.h"
 
 #include "base/stl_util.h"
+#include "class_linker.h"
 #include "dexopt_test.h"
 #include "noop_compiler_callbacks.h"
 
@@ -110,6 +112,56 @@
   EXPECT_FALSE(ImageSpace::ValidateOatFile(*oat, &error_msg));
 }
 
+TEST_F(DexoptTest, Checksums) {
+  Runtime* runtime = Runtime::Current();
+  ASSERT_TRUE(runtime != nullptr);
+  ASSERT_FALSE(runtime->GetHeap()->GetBootImageSpaces().empty());
+
+  std::vector<std::string> bcp = runtime->GetBootClassPath();
+  std::vector<std::string> bcp_locations = runtime->GetBootClassPathLocations();
+  std::vector<const DexFile*> dex_files = runtime->GetClassLinker()->GetBootClassPath();
+
+  std::string error_msg;
+  auto create_and_verify = [&]() {
+    std::string checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
+        ArrayRef<gc::space::ImageSpace* const>(runtime->GetHeap()->GetBootImageSpaces()),
+        ArrayRef<const DexFile* const>(dex_files));
+    return gc::space::ImageSpace::VerifyBootClassPathChecksums(
+        checksums,
+        android::base::Join(bcp_locations, ':'),
+        runtime->GetImageLocation(),
+        ArrayRef<const std::string>(bcp_locations),
+        ArrayRef<const std::string>(bcp),
+        kRuntimeISA,
+        gc::space::ImageSpaceLoadingOrder::kSystemFirst,
+        &error_msg);
+  };
+
+  ASSERT_TRUE(create_and_verify()) << error_msg;
+
+  std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+  for (const std::string& src : { GetDexSrc1(), GetDexSrc2() }) {
+    std::vector<std::unique_ptr<const DexFile>> new_dex_files;
+    const ArtDexFileLoader dex_file_loader;
+    ASSERT_TRUE(dex_file_loader.Open(src.c_str(),
+                                     src,
+                                     /*verify=*/ true,
+                                     /*verify_checksum=*/ false,
+                                     &error_msg,
+                                     &new_dex_files))
+        << error_msg;
+
+    bcp.push_back(src);
+    bcp_locations.push_back(src);
+    for (std::unique_ptr<const DexFile>& df : new_dex_files) {
+      dex_files.push_back(df.get());
+      opened_dex_files.push_back(std::move(df));
+    }
+
+    ASSERT_TRUE(create_and_verify()) << error_msg;
+  }
+}
+
 template <bool kImage, bool kRelocate, bool kImageDex2oat>
 class ImageSpaceLoadingTest : public CommonRuntimeTest {
  protected: