Merge "Add product manifest and fragments."
diff --git a/VintfObject.cpp b/VintfObject.cpp
index e66bcbe..2badd18 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -339,12 +339,40 @@
     return out->fetchAllInformation(getFileSystem().get(), kVendorLegacyMatrix, error);
 }
 
+// Priority:
+// 1. /system/etc/vintf/manifest.xml
+//    + /system/etc/vintf/manifest/*.xml if they exist
+//    + /product/etc/vintf/manifest.xml if it exists
+//    + /product/etc/vintf/manifest/*.xml if they exist
+// 2. (deprecated) /system/manifest.xml
 status_t VintfObject::fetchFrameworkHalManifest(HalManifest* out, std::string* error) {
-    HalManifest etcManifest;
-    if (etcManifest.fetchAllInformation(getFileSystem().get(), kSystemManifest, error) == OK) {
-        *out = std::move(etcManifest);
-        return addDirectoryManifests(kSystemManifestFragmentDir, out, error);
+    auto systemEtcStatus = fetchOneHalManifest(kSystemManifest, out, error);
+    if (systemEtcStatus == OK) {
+        auto dirStatus = addDirectoryManifests(kSystemManifestFragmentDir, out, error);
+        if (dirStatus != OK) {
+            return dirStatus;
+        }
+
+        HalManifest productManifest;
+        auto productStatus = fetchOneHalManifest(kProductManifest, &productManifest, error);
+        if (productStatus != OK && productStatus != NAME_NOT_FOUND) {
+            return productStatus;
+        }
+        if (productStatus == OK) {
+            if (!out->addAll(&productManifest, error)) {
+                if (error) {
+                    error->insert(0, "Cannot add " + kProductManifest + ":");
+                }
+                return UNKNOWN_ERROR;
+            }
+        }
+
+        return addDirectoryManifests(kProductManifestFragmentDir, out, error);
+    } else {
+        LOG(WARNING) << "Cannot fetch " << kSystemManifest << ": "
+                     << (error ? *error : strerror(-systemEtcStatus));
     }
+
     return out->fetchAllInformation(getFileSystem().get(), kSystemLegacyManifest, error);
 }
 
@@ -590,10 +618,12 @@
 const std::string kVendorMatrix = kVendorVintfDir + "compatibility_matrix.xml";
 const std::string kOdmManifest = kOdmVintfDir + "manifest.xml";
 const std::string kProductMatrix = kProductVintfDir + "compatibility_matrix.xml";
+const std::string kProductManifest = kProductVintfDir + "manifest.xml";
 
 const std::string kVendorManifestFragmentDir = kVendorVintfDir + "manifest/";
 const std::string kSystemManifestFragmentDir = kSystemVintfDir + "manifest/";
 const std::string kOdmManifestFragmentDir = kOdmVintfDir + "manifest/";
+const std::string kProductManifestFragmentDir = kProductVintfDir + "manifest/";
 
 const std::string kVendorLegacyManifest = "/vendor/manifest.xml";
 const std::string kVendorLegacyMatrix = "/vendor/compatibility_matrix.xml";
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index ceabf61..2b0616a 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -375,9 +375,11 @@
 extern const std::string kVendorMatrix;
 extern const std::string kOdmManifest;
 extern const std::string kProductMatrix;
+extern const std::string kProductManifest;
 extern const std::string kVendorManifestFragmentDir;
 extern const std::string kSystemManifestFragmentDir;
 extern const std::string kOdmManifestFragmentDir;
+extern const std::string kProductManifestFragmentDir;
 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 f97d81f..0ae2946 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -368,6 +368,8 @@
             .WillByDefault(Return(::android::OK));
         ON_CALL(fetcher(), listFiles(StrEq(kOdmManifestFragmentDir), _, _))
             .WillByDefault(Return(::android::OK));
+        ON_CALL(fetcher(), listFiles(StrEq(kProductManifestFragmentDir), _, _))
+            .WillByDefault(Return(::android::OK));
 
         if (!productModel.empty()) {
             ON_CALL(fetcher(),
@@ -415,6 +417,8 @@
             .WillByDefault(Return(::android::OK));
         // Don't fetch product matrix unless otherwise specified.
         ON_CALL(fetcher(), fetch(StrEq(kProductMatrix), _)).WillByDefault(Return(NAME_NOT_FOUND));
+        // Don't fetch product manifest unless otherwise specified.
+        ON_CALL(fetcher(), fetch(StrEq(kProductManifest), _)).WillByDefault(Return(NAME_NOT_FOUND));
     }
 
     void setFakeProperties() {
@@ -452,6 +456,7 @@
 
     void expectSystemManifest(size_t times = 1) {
         EXPECT_CALL(fetcher(), fetch(StrEq(kSystemManifest), _)).Times(times);
+        EXPECT_CALL(fetcher(), fetch(StrEq(kProductManifest), _)).Times(times);
     }
 
     void expectVendorMatrix(size_t times = 1) {
@@ -1426,6 +1431,138 @@
     EXPECT_TRUE(checkCompatibility({vendorManifestRequire2}, &error)) << error;
 }
 
+const std::string systemEtcManifest =
+    "<manifest version=\"1.0\" type=\"framework\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <fqname>@1.0::ISystemEtc/default</fqname>\n"
+    "    </hal>\n"
+    "</manifest>\n";
+
+const std::string systemEtcManifestFrag =
+    "<manifest version=\"1.0\" type=\"framework\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <fqname>@1.0::ISystemEtcFragment/default</fqname>\n"
+    "    </hal>\n"
+    "</manifest>\n";
+
+const std::string productEtcManifest =
+    "<manifest version=\"1.0\" type=\"framework\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <fqname>@1.0::IProductEtc/default</fqname>\n"
+    "    </hal>\n"
+    "</manifest>\n";
+
+const std::string productEtcManifestFrag =
+    "<manifest version=\"1.0\" type=\"framework\">\n"
+    "    <hal format=\"hidl\">\n"
+    "        <name>android.hardware.foo</name>\n"
+    "        <transport>hwbinder</transport>\n"
+    "        <fqname>@1.0::IProductEtcFragment/default</fqname>\n"
+    "    </hal>\n"
+    "</manifest>\n";
+
+using FrameworkManifestTestParam =
+    std::tuple<bool /* Existence of /system/etc/vintf/manifest.xml */,
+               bool /* Existence of /system/etc/vintf/manifest/fragment.xml */,
+               bool /* Existence of /product/etc/vintf/manifest.xml */,
+               bool /* Existence of /product/etc/vintf/manifest/fragment.xml */>;
+class FrameworkManifestTest : public VintfObjectTestBase,
+                              public ::testing::WithParamInterface<FrameworkManifestTestParam> {
+   protected:
+    virtual void SetUp() {
+        VintfObjectTestBase::SetUp();
+        setFakeProperties();
+    }
+
+    // Set the existence of /system/etc/vintf/manifest.xml
+    void expectSystemManifest(bool exists) {
+        if (exists) {
+            expectFetchRepeatedly(kSystemManifest, systemEtcManifest);
+        } else {
+            expectFileNotExist(StrEq(kSystemManifest));
+        }
+        expectFileNotExist(StrEq(kSystemLegacyManifest));
+    }
+    // Set the existence of /system/etc/vintf/manifest/fragment.xml
+    void expectSystemManifestFragment(bool exists) {
+        if (exists) {
+            EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemManifestFragmentDir), _, _))
+                .Times(AnyNumber())
+                .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) {
+                    *out = {"fragment.xml"};
+                    return ::android::OK;
+                }));
+            expectFetchRepeatedly(kSystemManifestFragmentDir + "fragment.xml",
+                                  systemEtcManifestFrag);
+        } else {
+            EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemManifestFragmentDir), _, _))
+                .Times(AnyNumber())
+                .WillRepeatedly(Return(::android::OK));
+            expectFileNotExist(kSystemManifestFragmentDir + "fragment.xml");
+        }
+    }
+    // Set the existence of /product/etc/vintf/manifest.xml
+    void expectProductManifest(bool exists) {
+        if (exists) {
+            expectFetchRepeatedly(kProductManifest, productEtcManifest);
+        } else {
+            expectFileNotExist(kProductManifest);
+        }
+    }
+    // Set the existence of /product/etc/vintf/manifest/fragment.xml
+    void expectProductManifestFragment(bool exists) {
+        if (exists) {
+            EXPECT_CALL(fetcher(), listFiles(StrEq(kProductManifestFragmentDir), _, _))
+                .Times(AnyNumber())
+                .WillRepeatedly(Invoke([](const auto&, auto* out, auto*) {
+                    *out = {"fragment.xml"};
+                    return ::android::OK;
+                }));
+            expectFetchRepeatedly(kProductManifestFragmentDir + "fragment.xml",
+                                  productEtcManifestFrag);
+        } else {
+            EXPECT_CALL(fetcher(), listFiles(StrEq(kProductManifestFragmentDir), _, _))
+                .Times(AnyNumber())
+                .WillRepeatedly(Return(::android::OK));
+            expectFileNotExist(kProductManifestFragmentDir + "fragment.xml");
+        }
+    }
+
+    void expectContainsInterface(const std::string& interface, bool contains = true) {
+        auto manifest = vintfObject->getFrameworkHalManifest();
+        ASSERT_NE(nullptr, manifest);
+        EXPECT_NE(manifest->getInstances("android.hardware.foo", {1, 0}, interface).empty(),
+                  contains)
+            << interface << " is missing.";
+    }
+};
+
+TEST_P(FrameworkManifestTest, Existence) {
+    expectSystemManifest(std::get<0>(GetParam()));
+    expectSystemManifestFragment(std::get<1>(GetParam()));
+    expectProductManifest(std::get<2>(GetParam()));
+    expectProductManifestFragment(std::get<3>(GetParam()));
+
+    if (!std::get<0>(GetParam())) {
+        EXPECT_EQ(nullptr, vintfObject->getFrameworkHalManifest())
+            << "getFrameworkHalManifest must return nullptr if " << kSystemManifest
+            << " does not exist";
+    } else {
+        expectContainsInterface("ISystemEtc", std::get<0>(GetParam()));
+        expectContainsInterface("ISystemEtcFragment", std::get<1>(GetParam()));
+        expectContainsInterface("IProductEtc", std::get<2>(GetParam()));
+        expectContainsInterface("IProductEtcFragment", std::get<3>(GetParam()));
+    }
+}
+INSTANTIATE_TEST_SUITE_P(, FrameworkManifestTest,
+                         ::testing::Combine(Bool(), Bool(), Bool(), Bool()));
+
 }  // namespace testing
 }  // namespace vintf
 }  // namespace android