Fetch framework matrix from /product/etc/vintf/compatibility_matrix.xml.
am: 73bde5914a

Change-Id: I2e9068c1fa5d28eec47f708205fc1cd71332e8f4
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 64f4a61..1100977 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -144,8 +144,15 @@
 status_t VintfObject::getCombinedFrameworkMatrix(
     const std::shared_ptr<const HalManifest>& deviceManifest, CompatibilityMatrix* out,
     std::string* error) {
-    auto matrixFragments = getAllFrameworkMatrixLevels(error);
+    std::vector<Named<CompatibilityMatrix>> matrixFragments;
+    auto matrixFragmentsStatus = getAllFrameworkMatrixLevels(&matrixFragments, error);
+    if (matrixFragmentsStatus != OK) {
+        return matrixFragmentsStatus;
+    }
     if (matrixFragments.empty()) {
+        if (error && error->empty()) {
+            *error = "Cannot get framework matrix for each FCM version for unknown error.";
+        }
         return NAME_NOT_FOUND;
     }
 
@@ -338,47 +345,66 @@
     }
 }
 
-std::vector<Named<CompatibilityMatrix>> VintfObject::getAllFrameworkMatrixLevels(
-    std::string* error) {
-    std::vector<std::string> fileNames;
-    std::vector<Named<CompatibilityMatrix>> results;
+status_t VintfObject::getOneMatrix(const std::string& path, Named<CompatibilityMatrix>* out,
+                                   std::string* error) {
+    std::string content;
+    status_t status = getFileSystem()->fetch(path, &content, error);
+    if (status != OK) {
+        return status;
+    }
+    if (!gCompatibilityMatrixConverter(&out->object, content, error)) {
+        if (error) {
+            error->insert(0, "Cannot parse " + path + ": ");
+        }
+        return BAD_VALUE;
+    }
+    out->name = path;
+    return OK;
+}
 
-    if (getFileSystem()->listFiles(kSystemVintfDir, &fileNames, error) != OK) {
-        return {};
+status_t VintfObject::getAllFrameworkMatrixLevels(std::vector<Named<CompatibilityMatrix>>* results,
+                                                  std::string* error) {
+    std::vector<std::string> fileNames;
+
+    status_t listStatus = getFileSystem()->listFiles(kSystemVintfDir, &fileNames, error);
+    if (listStatus != OK) {
+        return listStatus;
     }
     for (const std::string& fileName : fileNames) {
         std::string path = kSystemVintfDir + fileName;
-
-        std::string content;
-        std::string fetchError;
-        status_t status = getFileSystem()->fetch(path, &content, &fetchError);
-        if (status != OK) {
-            appendLine(error, "Framework Matrix: Ignore file " + path + ": " + fetchError);
+        Named<CompatibilityMatrix> namedMatrix;
+        std::string matrixError;
+        status_t matrixStatus = getOneMatrix(path, &namedMatrix, &matrixError);
+        if (matrixStatus != OK) {
+            // System manifests and matrices share the same dir. Client may not have enough
+            // permissions to read system manifests, or may not be able to parse it.
+            auto logLevel = matrixStatus == BAD_VALUE ? base::DEBUG : base::ERROR;
+            LOG(logLevel) << "Framework Matrix: Ignore file " << path << ": " << matrixError;
             continue;
         }
-
-        auto it = results.emplace(results.end());
-        std::string parseError;
-        if (!gCompatibilityMatrixConverter(&it->object, content, &parseError)) {
-            appendLine(error, "Framework Matrix: Ignore file " + path + ": " + parseError);
-            results.erase(it);
-            continue;
-        }
+        results->emplace_back(std::move(namedMatrix));
     }
 
-    if (results.empty()) {
-        if (error) {
-            error->insert(0, "No framework matrices under " + kSystemVintfDir +
-                                 " can be fetched or parsed.\n");
-        }
+    Named<CompatibilityMatrix> productMatrix;
+    std::string productError;
+    status_t productStatus = getOneMatrix(kProductMatrix, &productMatrix, &productError);
+    if (productStatus == OK) {
+        results->emplace_back(std::move(productMatrix));
+    } else if (productStatus == NAME_NOT_FOUND) {
+        LOG(DEBUG) << "Framework Matrix: missing " << kProductMatrix;
     } else {
-        if (error && !error->empty()) {
-            LOG(WARNING) << *error;
-            *error = "";
-        }
+        if (error) *error = std::move(productError);
+        return productStatus;
     }
 
-    return results;
+    if (results->empty()) {
+        if (error) {
+            *error =
+                "No framework matrices under " + kSystemVintfDir + " can be fetched or parsed.\n";
+        }
+        return NAME_NOT_FOUND;
+    }
+    return OK;
 }
 
 std::shared_ptr<const RuntimeInfo> VintfObject::GetRuntimeInfo(bool skipCache,
@@ -541,11 +567,13 @@
 const std::string kSystemVintfDir = "/system/etc/vintf/";
 const std::string kVendorVintfDir = "/vendor/etc/vintf/";
 const std::string kOdmVintfDir = "/odm/etc/vintf/";
+const std::string kProductVintfDir = "/product/etc/vintf/";
 
 const std::string kVendorManifest = kVendorVintfDir + "manifest.xml";
 const std::string kSystemManifest = kSystemVintfDir + "manifest.xml";
 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 kVendorManifestFragmentDir = kVendorVintfDir + "manifest/";
 const std::string kSystemManifestFragmentDir = kSystemVintfDir + "manifest/";
@@ -560,9 +588,17 @@
 
 std::vector<std::string> dumpFileList() {
     return {
-        kSystemVintfDir,       kVendorVintfDir,     kOdmVintfDir,          kOdmLegacyVintfDir,
-
-        kVendorLegacyManifest, kVendorLegacyMatrix, kSystemLegacyManifest, kSystemLegacyMatrix,
+        // clang-format off
+        kSystemVintfDir,
+        kVendorVintfDir,
+        kOdmVintfDir,
+        kProductVintfDir,
+        kOdmLegacyVintfDir,
+        kVendorLegacyManifest,
+        kVendorLegacyMatrix,
+        kSystemLegacyManifest,
+        kSystemLegacyMatrix,
+        // clang-format on
     };
 }
 
@@ -658,10 +694,15 @@
     return GetInstance()->checkDeprecation(listInstances, error);
 }
 int32_t VintfObject::checkDeprecation(const ListInstances& listInstances, std::string* error) {
-    auto matrixFragments = getAllFrameworkMatrixLevels(error);
+    std::vector<Named<CompatibilityMatrix>> matrixFragments;
+    auto matrixFragmentsStatus = getAllFrameworkMatrixLevels(&matrixFragments, error);
+    if (matrixFragmentsStatus != OK) {
+        return matrixFragmentsStatus;
+    }
     if (matrixFragments.empty()) {
-        if (error && error->empty())
+        if (error && error->empty()) {
             *error = "Cannot get framework matrix for each FCM version for unknown error.";
+        }
         return NAME_NOT_FOUND;
     }
     auto deviceManifest = getDeviceHalManifest();
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index 4162843..e1a4501 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -305,8 +305,10 @@
 
     status_t getCombinedFrameworkMatrix(const std::shared_ptr<const HalManifest>& deviceManifest,
                                         CompatibilityMatrix* out, std::string* error = nullptr);
-    std::vector<Named<CompatibilityMatrix>> getAllFrameworkMatrixLevels(
-        std::string* error = nullptr);
+    status_t getAllFrameworkMatrixLevels(std::vector<Named<CompatibilityMatrix>>* out,
+                                         std::string* error = nullptr);
+    status_t getOneMatrix(const std::string& path, Named<CompatibilityMatrix>* out,
+                          std::string* error = nullptr);
     status_t addDirectoryManifests(const std::string& directory, HalManifest* manifests,
                                    std::string* error = nullptr);
     status_t fetchDeviceHalManifest(HalManifest* out, std::string* error = nullptr);
@@ -365,12 +367,14 @@
 extern const std::string kSystemVintfDir;
 extern const std::string kVendorVintfDir;
 extern const std::string kOdmVintfDir;
+extern const std::string kProductVintfDir;
 extern const std::string kOdmLegacyVintfDir;
 extern const std::string kOdmLegacyManifest;
 extern const std::string kVendorManifest;
 extern const std::string kSystemManifest;
 extern const std::string kVendorMatrix;
 extern const std::string kOdmManifest;
+extern const std::string kProductMatrix;
 extern const std::string kVendorManifestFragmentDir;
 extern const std::string kSystemManifestFragmentDir;
 extern const std::string kOdmManifestFragmentDir;
diff --git a/test/vintf_object_tests.cpp b/test/vintf_object_tests.cpp
index 6d1c1dd..92e2ce9 100644
--- a/test/vintf_object_tests.cpp
+++ b/test/vintf_object_tests.cpp
@@ -392,6 +392,8 @@
         // Don't list /system/etc/vintf unless otherwise specified.
         ON_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _))
             .WillByDefault(Return(::android::OK));
+        // Don't fetch product matrix unless otherwise specified.
+        ON_CALL(fetcher(), fetch(StrEq(kProductMatrix), _)).WillByDefault(Return(NAME_NOT_FOUND));
     }
 
     void setFakeProperties() {
@@ -437,6 +439,7 @@
     }
 
     void expectSystemMatrix(size_t times = 1) {
+        EXPECT_CALL(fetcher(), fetch(StrEq(kProductMatrix), _)).Times(times);
         EXPECT_CALL(fetcher(), fetch(StrEq(kSystemLegacyMatrix), _)).Times(times);
     }
 
@@ -694,12 +697,55 @@
                 "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\"/>");
     expectFetch(kSystemVintfDir + "compatibility_matrix.empty.xml",
                 "<compatibility-matrix version=\"1.0\" type=\"framework\"/>");
+    expectFileNotExist(StrEq(kProductMatrix));
     expectFetch(kVendorManifest, "<manifest version=\"1.0\" type=\"device\" />\n");
-    expectSystemMatrix(0);
+    expectNeverFetch(kSystemLegacyMatrix);
 
     EXPECT_NE(nullptr, vintfObject->getFrameworkCompatibilityMatrix(true /* skipCache */));
 }
 
+// Test product compatibility matrix is fetched
+TEST_F(VintfObjectTest, ProductCompatibilityMatrix) {
+    EXPECT_CALL(fetcher(), listFiles(StrEq(kSystemVintfDir), _, _))
+        .WillOnce(Invoke([](const auto&, auto* out, auto*) {
+            *out = {
+                "compatibility_matrix.1.xml",
+                "compatibility_matrix.empty.xml",
+            };
+            return ::android::OK;
+        }));
+    expectFetch(kSystemVintfDir + "compatibility_matrix.1.xml",
+                "<compatibility-matrix version=\"1.0\" type=\"framework\" level=\"1\"/>");
+    expectFetch(kSystemVintfDir + "compatibility_matrix.empty.xml",
+                "<compatibility-matrix version=\"1.0\" type=\"framework\"/>");
+    expectFetch(kProductMatrix,
+                "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
+                "    <hal format=\"hidl\" optional=\"true\">\n"
+                "        <name>android.hardware.foo</name>\n"
+                "        <version>1.0</version>\n"
+                "        <interface>\n"
+                "            <name>IFoo</name>\n"
+                "            <instance>default</instance>\n"
+                "        </interface>\n"
+                "    </hal>\n"
+                "</compatibility-matrix>\n");
+    expectFetch(kVendorManifest, "<manifest version=\"1.0\" type=\"device\" />\n");
+    expectNeverFetch(kSystemLegacyMatrix);
+
+    auto fcm = vintfObject->getFrameworkCompatibilityMatrix(true /* skipCache */);
+    ASSERT_NE(nullptr, fcm);
+
+    FqInstance expectInstance;
+    EXPECT_TRUE(expectInstance.setTo("android.hardware.foo@1.0::IFoo/default"));
+    bool found = false;
+    fcm->forEachInstance([&found, &expectInstance](const auto& matrixInstance) {
+        found |= matrixInstance.isSatisfiedBy(expectInstance);
+        return !found;  // continue if not found
+    });
+    EXPECT_TRUE(found) << "android.hardware.foo@1.0::IFoo/default should be found in matrix:\n"
+                       << gCompatibilityMatrixConverter(*fcm);
+}
+
 const std::string vendorEtcManifest =
     "<manifest version=\"1.0\" type=\"device\">\n"
     "    <hal format=\"hidl\">\n"
@@ -938,7 +984,8 @@
             .WillOnce(Return(::android::OK));
         expectFetch(kSystemVintfDir + "compatibility_matrix.1.xml", systemMatrixLevel1);
         expectFetch(kSystemVintfDir + "compatibility_matrix.2.xml", systemMatrixLevel2);
-        expectSystemMatrix(0);
+        expectFileNotExist(StrEq(kProductMatrix));
+        expectNeverFetch(kSystemLegacyMatrix);
 
         expectFetch(kVendorManifest,
                     "<manifest version=\"1.0\" type=\"device\" target-level=\"2\"/>");
@@ -1048,7 +1095,8 @@
             expectFetchRepeatedly(kSystemVintfDir + getFileName(i), content);
             ++i;
         }
-        expectSystemMatrix(0);
+        expectFileNotExist(kProductMatrix);
+        expectNeverFetch(kSystemLegacyMatrix);
         expectFileNotExist(StartsWith("/odm/"));
     }
     void expectTargetFcmVersion(size_t level) {