check_vintf: write all error messages before exiting.

Allow developers to see all error messages instead of
fixing them one by one.

Test: m check-vintf-all
Test: m check-vintf-all with the following change:
    - manually use health 1.0 HAL instead of 2.1
      (both incompatible and unused)
    - manually use vibrator HIDL 1.3 HAL instead of AIDL
      (unused 1.3 HAL)
    See error message for both.

Bug: 153370844

Change-Id: I8f77d1aae5df2cb309e72d1e18d3fdb3b7ed76da
(cherry picked from commit af3bb3b018b6395947a9feca0cf216673e8afed7)
Merged-In: I8f77d1aae5df2cb309e72d1e18d3fdb3b7ed76da
diff --git a/check_vintf.cpp b/check_vintf.cpp
index 8ef1ca8..ce32730 100644
--- a/check_vintf.cpp
+++ b/check_vintf.cpp
@@ -20,6 +20,7 @@
 
 #include <iostream>
 #include <map>
+#include <optional>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -347,6 +348,30 @@
     return EX_USAGE;
 }
 
+// If |result| is already an error, don't do anything. Otherwise, set it to
+// an error with |errorCode|. Return reference to Error object for appending
+// additional error messages.
+android::base::Error& SetErrorCode(std::optional<android::base::Error>* retError,
+                                   int errorCode = 0) {
+    if (!retError->has_value()) {
+        retError->emplace(errorCode);
+    } else {
+        // Use existing error code.
+        // There should already been an error message appended. Add a new line char for
+        // additional messages.
+        (**retError) << "\n";
+    }
+    return **retError;
+}
+
+// If |other| is an error, add it to |retError|.
+template <typename T>
+void AddResult(std::optional<android::base::Error>* retError,
+               const android::base::Result<T>& other) {
+    if (other.ok()) return;
+    SetErrorCode(retError, other.error().code()) << other.error();
+}
+
 android::base::Result<void> checkAllFiles(const Dirmap& dirmap, const Properties& props,
                                           std::shared_ptr<StaticRuntimeInfo> runtimeInfo) {
     auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
@@ -362,30 +387,39 @@
             .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(runtimeInfo))
             .build();
 
-    std::string error;
-    int compatibleResult = vintfObject->checkCompatibility(&error, flags);
+    std::optional<android::base::Error> retError = std::nullopt;
+
+    std::string compatibleError;
+    int compatibleResult = vintfObject->checkCompatibility(&compatibleError, flags);
     if (compatibleResult == INCOMPATIBLE) {
-        return android::base::Error() << error;
-    }
-    if (compatibleResult != COMPATIBLE) {
-        return android::base::Error(-compatibleResult) << error;
+        SetErrorCode(&retError) << compatibleError;
+    } else if (compatibleResult != COMPATIBLE) {
+        SetErrorCode(&retError, -compatibleResult) << compatibleError;
     }
 
     auto hasFcmExt = vintfObject->hasFrameworkCompatibilityMatrixExtensions();
-    if (!hasFcmExt.has_value()) {
-        return hasFcmExt.error();
-    }
+    AddResult(&retError, hasFcmExt);
+
     auto deviceManifest = vintfObject->getDeviceHalManifest();
+    Level targetFcm = Level::UNSPECIFIED;
     if (deviceManifest == nullptr) {
-        return android::base::Error(-NAME_NOT_FOUND) << "No device HAL manifest";
+        SetErrorCode(&retError, -NAME_NOT_FOUND) << "No device HAL manifest";
+    } else {
+        targetFcm = deviceManifest->level();
     }
-    auto targetFcm = deviceManifest->level();
-    if (*hasFcmExt || (targetFcm != Level::UNSPECIFIED && targetFcm >= Level::R)) {
+
+    if (hasFcmExt.value_or(false) || (targetFcm != Level::UNSPECIFIED && targetFcm >= Level::R)) {
         auto hidlMetadata = HidlInterfaceMetadata::all();
-        return vintfObject->checkUnusedHals(hidlMetadata);
+        AddResult(&retError, vintfObject->checkUnusedHals(hidlMetadata));
+    } else {
+        LOG(INFO) << "Skip checking unused HALs.";
     }
-    LOG(INFO) << "Skip checking unused HALs.";
-    return {};
+
+    if (retError.has_value()) {
+        return *retError;
+    } else {
+        return {};
+    }
 }
 
 int checkDirmaps(const Dirmap& dirmap, const Properties& props) {