Ignore bad profiles when --force-merge is specified

The ART profiles are cleaned lazily and may stay a long time on an
obsolete version if the corresponding apps are not used or updated. For
regular profiles this is not a problem, however for boot image profiles
they can trigger unnecessary merge errors. As such, we ignore them when
--force-merge is specified.

Test: profile tests
Bug: 139884006
Change-Id: I10d9a325d79b279c8ec4fe8d70696e9335a17099
diff --git a/profman/profile_assistant.cc b/profman/profile_assistant.cc
index 7107944..1695d8c 100644
--- a/profman/profile_assistant.cc
+++ b/profman/profile_assistant.cc
@@ -58,6 +58,12 @@
     ProfileCompilationInfo cur_info;
     if (!cur_info.Load(profile_files[i]->Fd(), /*merge_classes=*/ true, filter_fn)) {
       LOG(WARNING) << "Could not load profile file at index " << i;
+      if (options.IsForceMerge()) {
+        // If we have to merge forcefully, ignore load failures.
+        // This is useful for boot image profiles to ignore stale profiles which are
+        // cleared lazily.
+        continue;
+      }
       return kErrorBadProfiles;
     }
 
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index 1717dd1..caaff4b 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -1430,4 +1430,38 @@
   ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd),
             ProfileAssistant::kErrorDifferentVersions);
 }
+
+// Under default behaviour we will abort if we cannot load a profile during a merge
+// operation. However, if we pass --force-merge to force aggregation we should
+// ignore files we cannot load
+TEST_F(ProfileAssistantTest, ForceMergeIgnoreProfilesItCannotLoad) {
+  ScratchFile profile1;
+  ScratchFile profile2;
+
+  // Write corrupt data in the first file.
+  std::string content = "giberish";
+  ASSERT_TRUE(profile1.GetFile()->WriteFully(content.c_str(), content.length()));
+  profile1.GetFile()->ResetOffset();
+
+  ProfileCompilationInfo info2(/*for_boot_image*/ true);
+  info2.Save(profile2.GetFd());
+  profile2.GetFile()->ResetOffset();
+
+  std::vector<int> profile_fds({ GetFd(profile1)});
+  int reference_profile_fd = GetFd(profile2);
+
+  // With force-merge we should merge successfully.
+  std::vector<const std::string> extra_args({"--force-merge"});
+  ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, extra_args),
+            ProfileAssistant::kSuccess);
+
+  ProfileCompilationInfo result;
+  ASSERT_TRUE(profile2.GetFile()->ResetOffset());
+  ASSERT_TRUE(result.Load(reference_profile_fd));
+  ASSERT_TRUE(info2.Equals(result));
+
+  // Without force-merge we should fail.
+  ASSERT_EQ(ProcessProfiles(profile_fds, reference_profile_fd, extra_args),
+            ProfileAssistant::kErrorBadProfiles);
+}
 }  // namespace art