Support for fragmented manifests.

Bug: 66917623
Test: vintf_object_test (host + device)
Test: libvintf_test (host + device)
Test: boot device which is depending on fragments
Change-Id: Iab0c1e3a2031029c155c08a1cec7079537756a43
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 604f7cb..38ef0df 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -161,11 +161,33 @@
     return OK;
 }
 
+// Load and combine all of the manifests in a directory
+status_t VintfObject::AddDirectoryManifests(const std::string& directory, HalManifest* manifest,
+                                            std::string* error) {
+    std::vector<std::string> fileNames;
+    status_t err = details::gFetcher->listFiles(directory, &fileNames, error);
+    // if the directory isn't there, that's okay
+    if (err == NAME_NOT_FOUND) return OK;
+    if (err != OK) return err;
+
+    for (const std::string& file : fileNames) {
+        // Only adds HALs because all other things are added by libvintf
+        // itself for now.
+        HalManifest fragmentManifest;
+        err = FetchOneHalManifest(directory + file, &fragmentManifest, error);
+        if (err != OK) return err;
+
+        manifest->addAllHals(&fragmentManifest);
+    }
+
+    return OK;
+}
+
 // Priority for loading vendor manifest:
-// 1. /vendor/etc/vintf/manifest.xml + ODM manifest
-// 2. /vendor/etc/vintf/manifest.xml
-// 3. ODM manifest
-// 4. /vendor/manifest.xml
+// 1. /vendor/etc/vintf/manifest.xml + device fragments + ODM manifest (optional) + odm fragments
+// 2. /vendor/etc/vintf/manifest.xml + device fragments
+// 3. ODM manifest (optional) + odm fragments
+// 4. /vendor/manifest.xml (legacy, no fragments)
 // where:
 // A + B means adding <hal> tags from B to A (so that <hal>s from B can override A)
 status_t VintfObject::FetchDeviceHalManifest(HalManifest* out, std::string* error) {
@@ -174,6 +196,13 @@
         return vendorStatus;
     }
 
+    if (vendorStatus == OK) {
+        status_t fragmentStatus = AddDirectoryManifests(kVendorManifestFragmentDir, out, error);
+        if (fragmentStatus != OK) {
+            return fragmentStatus;
+        }
+    }
+
     HalManifest odmManifest;
     status_t odmStatus = FetchOdmHalManifest(&odmManifest, error);
     if (odmStatus != OK && odmStatus != NAME_NOT_FOUND) {
@@ -184,13 +213,13 @@
         if (odmStatus == OK) {
             out->addAllHals(&odmManifest);
         }
-        return OK;
+        return AddDirectoryManifests(kOdmManifestFragmentDir, out, error);
     }
 
     // vendorStatus != OK, "out" is not changed.
     if (odmStatus == OK) {
         *out = std::move(odmManifest);
-        return OK;
+        return AddDirectoryManifests(kOdmManifestFragmentDir, out, error);
     }
 
     // Use legacy /vendor/manifest.xml
@@ -265,7 +294,7 @@
     HalManifest etcManifest;
     if (etcManifest.fetchAllInformation(kSystemManifest, error) == OK) {
         *out = std::move(etcManifest);
-        return OK;
+        return AddDirectoryManifests(kSystemManifestFragmentDir, out, error);
     }
     return out->fetchAllInformation(kSystemLegacyManifest, error);
 }
@@ -551,6 +580,10 @@
 const std::string kVendorMatrix = kVendorVintfDir + "compatibility_matrix.xml";
 const std::string kOdmManifest = kOdmVintfDir + "manifest.xml";
 
+const std::string kVendorManifestFragmentDir = kVendorVintfDir + "manifest/";
+const std::string kSystemManifestFragmentDir = kSystemVintfDir + "manifest/";
+const std::string kOdmManifestFragmentDir = kOdmVintfDir + "manifest/";
+
 const std::string kVendorLegacyManifest = "/vendor/manifest.xml";
 const std::string kVendorLegacyMatrix = "/vendor/compatibility_matrix.xml";
 const std::string kSystemLegacyManifest = "/system/manifest.xml";
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index 56581f8..38b20b3 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -154,6 +154,8 @@
         std::string* error = nullptr);
     static std::vector<Named<CompatibilityMatrix>> GetAllFrameworkMatrixLevels(
         std::string* error = nullptr);
+    static status_t AddDirectoryManifests(const std::string& directory, HalManifest* manifests,
+                                          std::string* error = nullptr);
     static status_t FetchDeviceHalManifest(HalManifest* out, std::string* error = nullptr);
     static status_t FetchDeviceMatrix(CompatibilityMatrix* out, std::string* error = nullptr);
     static status_t FetchOdmHalManifest(HalManifest* out, std::string* error = nullptr);
@@ -193,6 +195,9 @@
 extern const std::string kSystemManifest;
 extern const std::string kVendorMatrix;
 extern const std::string kOdmManifest;
+extern const std::string kVendorManifestFragmentDir;
+extern const std::string kSystemManifestFragmentDir;
+extern const std::string kOdmManifestFragmentDir;
 extern const std::string kVendorLegacyManifest;
 extern const std::string kVendorLegacyMatrix;
 extern const std::string kSystemLegacyManifest;
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 48623b8..2baeee3 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -282,6 +282,13 @@
                       const std::string& productModel) {
     MockFileFetcher* fetcher = static_cast<MockFileFetcher*>(gFetcher);
 
+    ON_CALL(*fetcher, listFiles(StrEq(kVendorManifestFragmentDir), _, _))
+        .WillByDefault(Return(::android::OK));
+    ON_CALL(*fetcher, listFiles(StrEq(kSystemManifestFragmentDir), _, _))
+        .WillByDefault(Return(::android::OK));
+    ON_CALL(*fetcher, listFiles(StrEq(kOdmManifestFragmentDir), _, _))
+        .WillByDefault(Return(::android::OK));
+
     if (!productModel.empty()) {
         ON_CALL(*fetcher, fetch(StrEq(kOdmLegacyVintfDir + "manifest_" + productModel + ".xml"), _))
             .WillByDefault(Return(::android::NAME_NOT_FOUND));
@@ -929,6 +936,10 @@
                 };
                 return ::android::OK;
             }));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kVendorManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kOdmManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
         expectFetch(kSystemVintfDir + "compatibility_matrix.1.xml", systemMatrixLevel1);
         expectFetch(kSystemVintfDir + "compatibility_matrix.2.xml", systemMatrixLevel2);
         expectSystemMatrix(0);
@@ -1033,6 +1044,10 @@
                 }
                 return ::android::OK;
             }));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kVendorManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
+        EXPECT_CALL(fetcher(), listFiles(StrEq(kOdmManifestFragmentDir), _, _))
+            .WillOnce(Return(::android::OK));
         size_t i = 1;
         for (const auto& content : systemMatrixRegexXmls) {
             expectFetchRepeatedly(kSystemVintfDir + getFileName(i), content);