Add device/fwk compatibility matrix to VintfObject.

For framework compatibility matrix, <sepolicy> sections
is injected in build time.

Test: libvintf_test
Test: adb shell vintf; matrices exist, compatible = true
Bug: 37321309
Bug: 36814503
Change-Id: I997b93456a261f0cdb85997ae88f4ac5a5f36ff3
Merged-In: I997b93456a261f0cdb85997ae88f4ac5a5f36ff3
diff --git a/CompatibilityMatrix.cpp b/CompatibilityMatrix.cpp
index 1f95ada..379fd78 100644
--- a/CompatibilityMatrix.cpp
+++ b/CompatibilityMatrix.cpp
@@ -16,6 +16,8 @@
 
 #include "CompatibilityMatrix.h"
 
+#include "utils.h"
+
 namespace android {
 namespace vintf {
 
@@ -63,6 +65,11 @@
     return mType;
 }
 
+
+status_t CompatibilityMatrix::fetchAllInformation(const std::string &path) {
+    return details::fetchAllInformation(path, gCompatibilityMatrixConverter, this);
+}
+
 bool operator==(const CompatibilityMatrix &lft, const CompatibilityMatrix &rgt) {
     return lft.mType == rgt.mType &&
            lft.mHals == rgt.mHals &&
diff --git a/HalManifest.cpp b/HalManifest.cpp
index 6197ceb..daf35a5 100644
--- a/HalManifest.cpp
+++ b/HalManifest.cpp
@@ -19,16 +19,13 @@
 #include "HalManifest.h"
 
 #include <dirent.h>
-
-#include <fstream>
-#include <iostream>
-#include <sstream>
 #include <mutex>
 
 #include <android-base/logging.h>
 
 #include "parse_string.h"
 #include "parse_xml.h"
+#include "utils.h"
 #include "CompatibilityMatrix.h"
 
 namespace android {
@@ -286,21 +283,7 @@
 }
 
 status_t HalManifest::fetchAllInformation(const std::string &path) {
-    std::ifstream in;
-    in.open(path);
-    if (!in.is_open()) {
-        LOG(WARNING) << "Cannot open " << path;
-        return INVALID_OPERATION;
-    }
-    std::stringstream ss;
-    ss << in.rdbuf();
-    bool success = gHalManifestConverter(this, ss.str());
-    if (!success) {
-        LOG(ERROR) << "Illformed vendor manifest: " << path << ": "
-                   << gHalManifestConverter.lastError();
-        return BAD_VALUE;
-    }
-    return OK;
+    return details::fetchAllInformation(path, gHalManifestConverter, this);
 }
 
 SchemaType HalManifest::type() const {
diff --git a/VintfObject.cpp b/VintfObject.cpp
index 674031a..1ef6edc 100644
--- a/VintfObject.cpp
+++ b/VintfObject.cpp
@@ -34,6 +34,8 @@
 
 static LockedUniquePtr<HalManifest> gDeviceManifest;
 static LockedUniquePtr<HalManifest> gFrameworkManifest;
+static LockedUniquePtr<CompatibilityMatrix> gDeviceMatrix;
+static LockedUniquePtr<CompatibilityMatrix> gFrameworkMatrix;
 static LockedUniquePtr<RuntimeInfo> gDeviceRuntimeInfo;
 
 template <typename T, typename F>
@@ -65,6 +67,21 @@
                 "/system/manifest.xml"));
 }
 
+
+// static
+const CompatibilityMatrix *VintfObject::GetDeviceCompatibilityMatrix(bool skipCache) {
+    return Get(&gDeviceMatrix, skipCache,
+            std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
+                "/vendor/compatibility_matrix.xml"));
+}
+
+// static
+const CompatibilityMatrix *VintfObject::GetFrameworkCompatibilityMatrix(bool skipCache) {
+    return Get(&gFrameworkMatrix, skipCache,
+            std::bind(&CompatibilityMatrix::fetchAllInformation, std::placeholders::_1,
+                "/system/compatibility_matrix.xml"));
+}
+
 // static
 const RuntimeInfo *VintfObject::GetRuntimeInfo(bool skipCache) {
     return Get(&gDeviceRuntimeInfo, skipCache,
diff --git a/assemble_vintf.cpp b/assemble_vintf.cpp
index b2b0ed1..663b864 100644
--- a/assemble_vintf.cpp
+++ b/assemble_vintf.cpp
@@ -88,7 +88,18 @@
 
         CompatibilityMatrix matrix;
         if (gCompatibilityMatrixConverter(&matrix, fileContent)) {
-            // TODO (b/37342627): get BOARD_VNDK_VERSION and put it here.
+            KernelSepolicyVersion kernelSepolicyVers;
+            Version sepolicyVers;
+            if (matrix.mType == SchemaType::FRAMEWORK) {
+                if (!getFlag("BOARD_SEPOLICY_VERS", &sepolicyVers)) {
+                    return false;
+                }
+                if (!getFlag("POLICYVERS", &kernelSepolicyVers)) {
+                    return false;
+                }
+                matrix.framework.mSepolicy = Sepolicy(kernelSepolicyVers,
+                        {{sepolicyVers.majorVer,sepolicyVers.minorVer}});
+            }
             outFile << gCompatibilityMatrixConverter(matrix);
             outFile.flush();
             return true;
diff --git a/include/vintf/CompatibilityMatrix.h b/include/vintf/CompatibilityMatrix.h
index 4e86f51..30344dd 100644
--- a/include/vintf/CompatibilityMatrix.h
+++ b/include/vintf/CompatibilityMatrix.h
@@ -20,6 +20,8 @@
 #include <map>
 #include <string>
 
+#include <utils/Errors.h>
+
 #include "MatrixHal.h"
 #include "MatrixKernel.h"
 #include "MapValueIterator.h"
@@ -54,10 +56,14 @@
     // for constructing matrix programitically only.
     MatrixHal *getAnyHal(const std::string &name);
 
+    status_t fetchAllInformation(const std::string &path);
+
     friend struct HalManifest;
     friend struct RuntimeInfo;
     friend struct CompatibilityMatrixConverter;
     friend struct LibVintfTest;
+    friend class VintfObject;
+    friend class AssembleVintf;
     friend bool operator==(const CompatibilityMatrix &, const CompatibilityMatrix &);
 
     SchemaType mType;
diff --git a/include/vintf/VintfObject.h b/include/vintf/VintfObject.h
index 157d00b..4f84a51 100644
--- a/include/vintf/VintfObject.h
+++ b/include/vintf/VintfObject.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_VINTF_VINTF_OBJECT_H_
 #define ANDROID_VINTF_VINTF_OBJECT_H_
 
+#include "CompatibilityMatrix.h"
 #include "HalManifest.h"
 #include "RuntimeInfo.h"
 
@@ -61,6 +62,18 @@
     static const HalManifest *GetFrameworkHalManifest(bool skipCache = false);
 
     /*
+     * Return the API that access the device-side compatibility matrix stored
+     * in /vendor/compatibility_matrix.xml.
+     */
+    static const CompatibilityMatrix *GetDeviceCompatibilityMatrix(bool skipCache = false);
+
+    /*
+     * Return the API that access the device-side compatibility matrix stored
+     * in /system/compatibility_matrix.xml.
+     */
+    static const CompatibilityMatrix *GetFrameworkCompatibilityMatrix(bool skipCache = false);
+
+    /*
      * Return the API that access device runtime info.
      */
     static const RuntimeInfo *GetRuntimeInfo(bool skipCache = false);
diff --git a/main.cpp b/main.cpp
index 25a8cc6..0437a64 100644
--- a/main.cpp
+++ b/main.cpp
@@ -19,18 +19,59 @@
 #include <vintf/parse_string.h>
 #include <vintf/VintfObject.h>
 
+// A convenience binary to dump information available through libvintf.
 int main(int, char **) {
     using namespace ::android::vintf;
 
+    std::cout << "======== Device HAL Manifest =========" << std::endl;
+
     const HalManifest *vm = VintfObject::GetDeviceHalManifest();
     if (vm != nullptr)
         std::cout << gHalManifestConverter(*vm);
 
+    std::cout << "======== Framework HAL Manifest =========" << std::endl;
+
     const HalManifest *fm = VintfObject::GetFrameworkHalManifest();
     if (fm != nullptr)
         std::cout << gHalManifestConverter(*fm);
 
-    std::cout << std::endl;
+    std::cout << "======== Device Compatibility Matrix =========" << std::endl;
+
+    const CompatibilityMatrix *vcm = VintfObject::GetDeviceCompatibilityMatrix();
+    if (vcm != nullptr)
+        std::cout << gCompatibilityMatrixConverter(*vcm);
+
+    std::cout << "======== Framework Compatibility Matrix =========" << std::endl;
+
+    const CompatibilityMatrix *fcm = VintfObject::GetFrameworkCompatibilityMatrix();
+    if (fcm != nullptr)
+        std::cout << gCompatibilityMatrixConverter(*fcm);
+
+    std::cout << "======== Compatibility check =========" << std::endl;
+    std::cout << "Device HAL Manifest? " << (vm != nullptr) << std::endl
+              << "Device Compatibility Matrix? " << (vcm != nullptr) << std::endl
+              << "Framework HAL Manifest? " << (fm != nullptr) << std::endl
+              << "Framework Compatibility Matrix? " << (fcm != nullptr) << std::endl;
+    std::string error;
+    if (vm && fcm) {
+        bool compatible = vm->checkCompatibility(*fcm, &error);
+        std::cout << "Device HAL Manifest <==> Framework Compatibility Matrix? "
+                  << compatible;
+        if (!compatible)
+            std::cout << ", " << error;
+        std::cout << std::endl;
+    }
+    if (fm && vcm) {
+        bool compatible = fm->checkCompatibility(*vcm, &error);
+        std::cout << "Framework HAL Manifest <==> Device Compatibility Matrix? "
+                  << compatible;
+        if (!compatible)
+            std::cout << ", " << error;
+        std::cout << std::endl;
+    }
+
+    std::cout << "======== Runtime Info =========" << std::endl;
+
     const RuntimeInfo *ki = VintfObject::GetRuntimeInfo();
     if (ki != nullptr)
         std::cout << dump(*ki);
diff --git a/parse_xml.cpp b/parse_xml.cpp
index 1502011..9f144f4 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -684,8 +684,10 @@
         }
 
         if (object->mType == SchemaType::FRAMEWORK) {
+            // <avb> and <sepolicy> can be missing because it can be determined at build time, not
+            // hard-coded in the XML file.
             if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels) ||
-                !parseChild(root, sepolicyConverter, &object->framework.mSepolicy) ||
+                !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy) ||
                 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion)) {
                 return false;
             }
diff --git a/utils.h b/utils.h
new file mode 100644
index 0000000..3c06817
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VINTF_UTILS_H
+#define ANDROID_VINTF_UTILS_H
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <android-base/logging.h>
+#include <utils/Errors.h>
+
+#include "parse_xml.h"
+
+namespace android {
+namespace vintf {
+namespace details {
+
+template<typename T>
+status_t fetchAllInformation(const std::string &path,
+        const XmlConverter<T> &converter, T *outObject) {
+    std::ifstream in;
+    in.open(path);
+    if (!in.is_open()) {
+        LOG(WARNING) << "Cannot open " << path;
+        return INVALID_OPERATION;
+    }
+    std::stringstream ss;
+    ss << in.rdbuf();
+    bool success = converter(outObject, ss.str());
+    if (!success) {
+        LOG(ERROR) << "Illformed file: " << path << ": "
+                   << converter.lastError();
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+}  // namespace details
+}  // namespace vintf
+}  // namespace android
+
+
+
+#endif